apple/swift
Sema
Active contributors: xedin, hamishknight, DougGregor, slavapestov
Purpose
lib/Sema/ is the type checker. It assigns a type to every expression, resolves overloads, validates conformances, builds generic signatures, and verifies a hundred-and-one specific rules (concurrency, ownership, availability, accessibility). It is the single largest part of the compiler -- by lines of code, by file count, and by feature surface.
Directory layout
lib/Sema/ (120 files)
├── CSGen.cpp # generate constraints for an expression
├── CSSimplify.cpp # 16,668 lines — solve / simplify constraints
├── CSApply.cpp # 9,895 lines — apply a solution to the AST
├── CSDiagnostics.cpp # 9,800 lines — produce error messages from failed solves
├── CSBindings.cpp # type-variable binding policy
├── CSRanking.cpp # rank ambiguous solutions
├── CSStep.cpp # solver state machine
├── ConstraintGraph.cpp
├── ConstraintSystem.cpp
├── TypeCheckType.cpp # resolve TypeReprs to Types
├── TypeCheckDecl.cpp # validate declarations
├── TypeCheckProtocol.cpp # protocol conformance checking
├── TypeCheckGeneric.cpp
├── TypeCheckConcurrency.cpp # 9,237 lines — actor / Sendable / async
├── TypeCheckAttr.cpp # 9,187 lines — attribute validation
├── TypeCheckAccess.cpp
├── TypeCheckAvailability.cpp
├── TypeCheckMacros.cpp
├── TypeCheckUnsafe.cpp
├── PCMacro.cpp # playground transforms
└── ...Key abstractions
| Type | File | Description |
|---|---|---|
swift::constraints::ConstraintSystem |
include/swift/Sema/ConstraintSystem.h |
The state of one expression's solve. |
swift::constraints::TypeVariableType |
include/swift/AST/Types.h |
A placeholder during solving. |
swift::constraints::Constraint |
include/swift/Sema/Constraint.h |
One constraint (conversion, equal, conforms-to, member-lookup, ...). |
swift::constraints::Solution |
include/swift/Sema/ConstraintSystem.h |
A successful assignment of types to type variables. |
swift::TypeChecker |
include/swift/Sema/TypeChecker.h |
The legacy single-shot API; many free functions live here. |
swift::ProtocolConformanceChecker |
lib/Sema/TypeCheckProtocol.cpp |
Drives witness-table construction. |
How it works
graph TD
AST[Typed-checked input AST] --> CSGen[CSGen<br/>generate constraints]
CSGen --> CSSimplify[CSSimplify<br/>solve]
CSSimplify -->|success| Solution
CSSimplify -->|failure| CSDiagnostics[CSDiagnostics]
Solution --> CSApply[CSApply<br/>rewrite expression]
CSApply --> Typed[Typed AST]
CSDiagnostics --> Errors[diagnostics]For each top-level expression statement (and for closure bodies, function bodies, and other "expression contexts"), the type checker:
- Generates constraints (
CSGen.cpp). Every sub-expression gets a freshTypeVariableType. The structure of the expression yieldsbind,convert,equal,member-lookup,disjunction(overload),conforms-to, etc. constraints between the type variables. - Simplifies constraints (
CSSimplify.cpp). The solver applies rules: equal-to-known type drops type variables; conforms-to may unify; disjunctions branch. Branching usesCSStep.cppto traverse the search space. - Selects a solution (
CSRanking.cpp). When multiple solutions exist, score them and pick the best -- or report ambiguity. - Applies the solution (
CSApply.cpp). Walks the expression tree, attaches concreteTypeto every node, inserts implicit conversions / coercions, resolves overloads. - Diagnoses failures (
CSDiagnostics.cpp). When a solve fails, the diagnostics module replays the solver to find a "fix" that explains where the user's intent diverged from a type-correct program.
Beyond expressions
Many checks are not expression-shaped. They live in TypeCheckDecl.cpp, TypeCheckProtocol.cpp, TypeCheckType.cpp, etc.:
- Protocol conformance checking (
TypeCheckProtocol.cpp) -- givenextension Foo: Bar, verify each protocol requirement has a matching member, derive a witness table. - Generic-signature checking (
TypeCheckGeneric.cpp) -- validatewhere-clauses, ensure same-type / superclass / layout constraints are consistent. Uses the requirement machine. - Concurrency checking (
TypeCheckConcurrency.cpp) -- actor isolation,Sendableconformance,@MainActor,nonisolated, async chains,region-based isolation, dynamic isolation. - Attribute validation (
TypeCheckAttr.cpp) -- one giant switch overDeclAttributekinds. - Availability checking (
TypeCheckAvailability.cpp) --@available,if #available, refining contexts. - Macro expansion (
TypeCheckMacros.cpp) -- spawnsswift-plugin-server, parses the resulting code, splices it back in.
The constraint system in detail
The constraint system is essentially a Hindley-Milner solver extended with subtyping, overloads (encoded as disjunctions), and bidirectional inference. Reading order if you want to learn it:
lib/Sema/CSGen.cpp-- start withConstraintSystem::generateConstraints.include/swift/Sema/Constraint.h-- understand the constraint kinds.lib/Sema/CSSimplify.cpp-- the simplifier.docs/TypeChecker.md-- the high-level overview.
Integration points
- Parser → Sema -- Sema's input is the parser's output. Most parser-emitted nodes have
Typenulluntil Sema sets it. - AST request evaluator -- many Sema queries are requests (
TypeChecker::resolveType,getInterfaceType, etc.). They cache results in the evaluator. - ClangImporter -- to type-check
import Foundation, Sema queries ClangImporter for an importedModuleDecl. The imported types must look identical to native Swift types from Sema's perspective. - Sema → SILGen -- once Sema is done, SILGen reads only types and the typed AST; it does not re-run any type checking.
- IDE --
lib/IDE/and SourceKit drive Sema with a customIDEInspectionCallbacksto record completion candidates mid-solve. See IDE and SourceKit.
Entry points for modification
- Improving a diagnostic: most diagnostics flow from
lib/Sema/CSDiagnostics.cpp(for solve failures) or from a specificTypeCheck*.cppfile (for non-expression checks). Find the existing diagnostic ID viagit grep diag::xxx. - Adding a new attribute: extend
include/swift/AST/Attr.def, parse it inlib/Parse/ParseDecl.cpp, validate it inlib/Sema/TypeCheckAttr.cpp. - Adding a Sema-only language feature: gate it behind an
ExperimentalFeatureininclude/swift/Basic/Features.def. Run with-enable-experimental-feature MyFeature. - Tightening or relaxing concurrency checking: live in
lib/Sema/TypeCheckConcurrency.cpp. Tests intest/Concurrency/.
Related pages
- AST -- what Sema reads and mutates.
- SILGen -- the immediate consumer of typed AST.
- IDE and SourceKit -- Sema reused for live IDE features.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.