Open-Source Wikis

/

Swift

/

Systems

/

Sema

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:

  1. Generates constraints (CSGen.cpp). Every sub-expression gets a fresh TypeVariableType. The structure of the expression yields bind, convert, equal, member-lookup, disjunction (overload), conforms-to, etc. constraints between the type variables.
  2. Simplifies constraints (CSSimplify.cpp). The solver applies rules: equal-to-known type drops type variables; conforms-to may unify; disjunctions branch. Branching uses CSStep.cpp to traverse the search space.
  3. Selects a solution (CSRanking.cpp). When multiple solutions exist, score them and pick the best -- or report ambiguity.
  4. Applies the solution (CSApply.cpp). Walks the expression tree, attaches concrete Type to every node, inserts implicit conversions / coercions, resolves overloads.
  5. 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) -- given extension Foo: Bar, verify each protocol requirement has a matching member, derive a witness table.
  • Generic-signature checking (TypeCheckGeneric.cpp) -- validate where-clauses, ensure same-type / superclass / layout constraints are consistent. Uses the requirement machine.
  • Concurrency checking (TypeCheckConcurrency.cpp) -- actor isolation, Sendable conformance, @MainActor, nonisolated, async chains, region-based isolation, dynamic isolation.
  • Attribute validation (TypeCheckAttr.cpp) -- one giant switch over DeclAttribute kinds.
  • Availability checking (TypeCheckAvailability.cpp) -- @available, if #available, refining contexts.
  • Macro expansion (TypeCheckMacros.cpp) -- spawns swift-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:

  1. lib/Sema/CSGen.cpp -- start with ConstraintSystem::generateConstraints.
  2. include/swift/Sema/Constraint.h -- understand the constraint kinds.
  3. lib/Sema/CSSimplify.cpp -- the simplifier.
  4. docs/TypeChecker.md -- the high-level overview.

Integration points

  • Parser → Sema -- Sema's input is the parser's output. Most parser-emitted nodes have Type null until 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 imported ModuleDecl. 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 custom IDEInspectionCallbacks to 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 specific TypeCheck*.cpp file (for non-expression checks). Find the existing diagnostic ID via git grep diag::xxx.
  • Adding a new attribute: extend include/swift/AST/Attr.def, parse it in lib/Parse/ParseDecl.cpp, validate it in lib/Sema/TypeCheckAttr.cpp.
  • Adding a Sema-only language feature: gate it behind an ExperimentalFeature in include/swift/Basic/Features.def. Run with -enable-experimental-feature MyFeature.
  • Tightening or relaxing concurrency checking: live in lib/Sema/TypeCheckConcurrency.cpp. Tests in test/Concurrency/.
  • 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.

Sema – Swift wiki | Factory