This document describes the frontend phases of the Go compiler toolchain, covering parsing, AST construction, and type checking. The frontend transforms Go source code into a typed intermediate representation (IR), performing semantic analysis to ensure program correctness according to the Go language specification.
For information about the IR itself and how it's used in later compilation stages, see Unified IR and Export Data. For SSA generation that follows type checking, see SSA Generation.
The Go repository maintains two parallel type checker implementations:
go/types - Used by external tools (gopls, staticcheck, etc.) and accessible via the standard librarycmd/compile/internal/types2 - Used internally by the Go compilerThese implementations share the same type checking algorithms and logic. The go/types package is generated from types2 with minimal differences to accommodate different AST representations (go/ast vs cmd/compile/internal/syntax).
Sources: src/go/types/expr.go1-57 src/cmd/compile/internal/types2/expr.go1-57 src/go/types/assignments.go1-3
| Aspect | go/types | types2 |
|---|---|---|
| Purpose | External tools, analysis | Compiler frontend |
| AST Package | go/ast | cmd/compile/internal/syntax |
| Position Info | token.Pos | syntax.Pos |
| Output | types.Info map | Typed ir.Node tree |
| Import Path | go/types | cmd/compile/internal/types2 |
The parsing phase transforms source text into an Abstract Syntax Tree (AST). Two parsers exist corresponding to the two type checker implementations:
go/parser (for external tools):
ast.Node trees representing Go source structuregopls, gofmt, go vet, and other toolscmd/compile/internal/syntax (for compiler):
syntax.Node trees with similar structure but different typesSources: src/go/types/expr.go17-57 src/cmd/compile/internal/syntax
Both AST representations organize code into hierarchical nodes:
FuncDecl, GenDecl (const, var, type)IfStmt, ForStmt, SwitchStmt, AssignStmt, etc.BinaryExpr, CallExpr, IndexExpr, SelectorExpr, etc.ArrayType, StructType, FuncType, InterfaceType, etc.The core type checking state is maintained in the Checker struct, which orchestrates the entire semantic analysis process.
Sources: src/go/types/decl.go48-167 src/cmd/compile/internal/types2/decl.go48-166
Type checking proceeds in several phases:
Sources: src/go/types/decl.go48-167 src/go/types/check.go
Expression checking is the heart of semantic analysis. The algorithm recursively checks expressions top-down and propagates type information.
Type checking uses the operand type to represent the result of checking an expression:
Sources: src/go/types/operand.go src/go/types/expr.go17-57
The main entry points for expression checking are:
rawExpr: Core recursive expression checkerexpr: Wrapper that calls rawExpr with default settingsexprInternal: Dispatches to specific checkers based on expression kindSources: src/go/types/expr.go966-1200 src/go/types/expr.go1023-1200
Binary expressions are checked by binary() which:
matchTypes()Sources: src/go/types/expr.go780-872
Call checking (callExpr()) handles:
T(x))funcInst()Sources: src/go/types/call.go172-351 src/cmd/compile/internal/types2/call.go171-349
Generic function instantiation is handled by funcInst(), which:
Sources: src/go/types/call.go34-130 src/cmd/compile/internal/types2/call.go33-129
Selector checking (selector()) handles:
pkg.Name)struct.field)value.method)Sources: src/go/types/call.go686-890 src/cmd/compile/internal/types2/call.go681-880
Go has untyped constants and values that receive their final type through context:
The updateExprType() function propagates final types through expression trees, ensuring untyped values become properly typed based on assignment context.
Sources: src/go/types/expr.go252-372 src/cmd/compile/internal/types2/expr.go253-397
Statement checking validates control flow and operations that don't produce values.
Sources: src/go/types/stmt.go src/cmd/compile/internal/types2/stmt.go100-126
Assignment validation (assignment()) ensures:
singleValue())Sources: src/go/types/assignments.go19-89 src/cmd/compile/internal/types2/assignments.go16-85
Statement checking tracks context via stmtContext flags:
breakOk: break statement allowedcontinueOk: continue statement allowedfallthroughOk: fallthrough statement allowedfinalSwitchCase: last case in switchinTypeSwitch: within type switchSources: src/go/types/stmt.go84-99 src/cmd/compile/internal/types2/stmt.go83-98
The objDecl() function type-checks declarations in dependency order:
Sources: src/go/types/decl.go48-167 src/cmd/compile/internal/types2/decl.go48-166
The checker maintains:
objPath: Stack of objects currently being checkedobjPathIdx: Map from object to its index in objPathobjMap: Map from object to its declInfoThis enables cycle detection and proper ordering of declarations.
Sources: src/go/types/decl.go169-295 src/cmd/compile/internal/types2/decl.go168-293
Type declarations (typeDecl()) handle:
type A = B)type T struct{...})Sources: src/go/types/typexpr.go src/cmd/compile/internal/types2/typexpr.go
Built-in functions have special type checking rules implemented in builtin():
Sources: src/go/types/builtins.go23-84 src/cmd/compile/internal/types2/builtins.go20-81
The len() and cap() built-ins:
intSources: src/go/types/builtins.go149-231 src/cmd/compile/internal/types2/builtins.go146-227
Scopes form a tree structure representing lexical nesting:
The checker maintains the current scope in Checker.scope and provides:
openScope(): Create nested scopecloseScope(): Return to parent scopedeclare(): Add object to current scopelookupScope(): Find object in scope chainSources: src/go/types/scope.go src/go/types/decl.go16-34
Scopes contain Object instances representing declared entities:
| Object Type | Represents |
|---|---|
*Const | Named constant |
*Var | Variable (local, field, parameter) |
*TypeName | Named type or alias |
*Func | Function or method |
*PkgName | Imported package |
*Builtin | Built-in function |
*Nil | Predeclared nil |
Sources: src/go/types/object.go
Type information is recorded in types.Info for use by tools:
Sources: src/go/types/api.go
Type information is recorded at key points:
record()recordDef()recordUse()recordSelection()recordInstance()Sources: src/go/types/expr.go989 src/go/types/call.go753
The checker maintains error state and provides several error reporting functions:
Sources: src/internal/types/errors/codes.go
Errors are reported at specific source positions:
The checker uses positioner interface to abstract position sources across go/ast and syntax packages.
Sources: src/go/types/errors.go src/cmd/compile/internal/types2/errors.go
The frontend and type checking phases transform Go source code into semantically valid, typed representations:
go/parser or syntax.Parse)Checker:
types.Info maps for external tools (go/types)ir.Node tree for compiler (types2)The type checker implements the Go language specification's semantic rules, detecting errors like undefined names, type mismatches, invalid operations, and declaration cycles.
Sources: src/go/types/expr.go17-57 src/go/types/call.go1-14 src/go/types/decl.go48-167 src/cmd/compile/internal/types2/expr.go17-57 src/cmd/compile/internal/types2/call.go1-14 src/cmd/compile/internal/types2/decl.go48-166
Refresh this wiki