This page describes the standard library packages used for static analysis and tooling in Go, primarily the go/types package which provides semantic analysis and type checking capabilities. These packages enable the creation of tools like gopls (language server), staticcheck (linter), and other analysis tools that reason about Go code.
For information about the compiler's internal type checking, see 3.1 Frontend and Type Checking. For runtime profiling and metrics, see 2.5 Runtime Metrics and Profiling.
The Go standard library provides two parallel type checking implementations:
| Package | Purpose | Users |
|---|---|---|
go/types | External type checker | Tools like gopls, staticcheck, IDE integrations |
cmd/compile/internal/types2 | Compiler type checker | Go compiler (cmd/compile) only |
Both implementations share the same algorithms and most code structure, but go/types uses go/ast for parsing while types2 uses cmd/compile/internal/syntax.
Sources: src/go/types/expr.go17-57 src/go/types/call.go1-15 src/go/types/decl.go1-14
The Checker type is the central component of the type checking system. It maintains state during type checking and coordinates all checking operations.
Sources: src/go/types/expr.go17-57 src/go/types/decl.go48-167
Expression checking is the core of semantic analysis. The algorithm processes expressions recursively from top to bottom.
From src/go/types/expr.go17-57:
rawExproperand with:
mode: The kind of value (constant, variable, value, typexpr, etc.)typ: The type of the expressionval: The constant value (if mode is constant_)check.untyped mapupdateExprType propagates final types down the expression treeSources: src/go/types/expr.go966-1200 src/go/types/call.go172-351
The operand type represents expression evaluation results with different modes:
| Mode | Description | Example |
|---|---|---|
invalid | Type checking error occurred | Any invalid expression |
novalue | Statement with no value | close(ch) |
constant_ | Compile-time constant | 42, "hello" |
typexpr | Type expression | int, []string |
variable | Addressable value | Variable, field selection |
value | Non-addressable value | Function call result |
commaok | Expression with optional 2nd value | v, ok := m[key] |
builtin | Built-in function reference | len, append |
Sources: src/go/types/expr.go17-57 src/go/types/operand.go
Call expression checking handles both ordinary function calls and generic function instantiation.
Sources: src/go/types/call.go172-351 src/go/types/call.go34-130 src/go/types/call.go463-673
When calling generic functions, the type checker performs type inference to determine type arguments:
f<FileRef file-url="https://github.com/golang/go/blob/0bf3f64c/int, string" undefined file-path="int, string">Hii</FileRef>From src/go/types/call.go70-122 the inference algorithm:
g<FileRef file-url="https://github.com/golang/go/blob/0bf3f64c/type_parameters_of_x" undefined file-path="type_parameters_of_x">Hii</FileRef> for assignment contextscheck.infer() to solve type parameter constraintsSources: src/go/types/call.go34-130 src/go/types/call.go463-673
Declaration checking resolves object types and detects invalid cycles.
From src/go/types/decl.go72-89 objects progress through three states during type checking:
| State | Condition | Color Metaphor |
|---|---|---|
| Unknown | Not in objPathIdx, type == nil | White |
| Pending | In objPathIdx | Grey |
| Known | Not in objPathIdx, type != nil | Black |
Sources: src/go/types/decl.go48-167 src/go/types/decl.go169-251
From src/go/types/decl.go169-251 valid cycles include:
Sources: src/go/types/decl.go169-251 src/go/types/decl.go253-295
Built-in functions like len, append, make have special type checking rules implemented in src/go/types/builtins.go
Sources: src/go/types/builtins.go23-85 src/go/types/builtins.go86-148
Built-in functions have unique handling:
append: Special case for append([]byte, string...) - src/go/types/builtins.go96-148len/cap: May be constants if applied to arrays without function calls - src/go/types/builtins.go149-231make: Validates second/third arguments are integers - src/go/types/builtins.go521-616copy: Validates both arguments have identical element types - src/go/types/builtins.go363-419Sources: src/go/types/builtins.go23-85
The Info type collects type information during checking, making it available to tools.
| Field | Type | Description |
|---|---|---|
Types | map[ast.Expr]TypeAndValue | Type and value for each expression |
Instances | map[*ast.Ident]Instance | Generic type/function instances |
Defs | map[*ast.Ident]Object | Identifier definitions |
Uses | map[*ast.Ident]Object | Identifier uses |
Implicits | map[ast.Node]Object | Implicit objects (e.g., case clauses) |
Selections | map[*ast.SelectorExpr]*Selection | Field/method selections |
Scopes | map[ast.Node]*Scope | Scope for each node |
InitOrder | []*Initializer | Package-level initialization order |
Sources: src/go/types/api.go
While both implementations share the same algorithms, they differ in usage:
| Aspect | go/types | types2 |
|---|---|---|
| AST Package | go/ast | cmd/compile/internal/syntax |
| Position Type | token.Pos | syntax.Pos |
| Public API | Yes | No (internal) |
| Used By | External tools | Compiler only |
| Code Location | src/go/types/ | src/cmd/compile/internal/types2/ |
| Generated From | types2 (with modifications) | Hand-written |
The compiler uses types2 for tighter integration with its internal data structures, while external tools use the stable go/types API.
Sources: src/go/types/expr.go1-15 src/cmd/compile/internal/types2/expr.go1-15
Steps:
1. Parse files with parser.ParseFile()
2. Create types.Config with Importer
3. Create types.Info with desired output maps
4. Call config.Check()
5. Access type information from Info
Steps:
1. Populate Info.Defs and Info.Uses during checking
2. Iterate over Info.Defs to find all definitions
3. Iterate over Info.Uses to find all references
4. Use Object.Pos() for source locations
Steps:
1. Populate Info.Types during checking
2. For each expression, lookup in Info.Types
3. Check TypeAndValue.Type for the expression's type
4. Check TypeAndValue.Value for constant values
5. Check TypeAndValue.IsValue()/IsType() for kind
Sources: src/go/types/api.go
The type checker represents program entities as Object implementations:
Each Object has:
Name(): The object's nameType(): The object's typePos(): Source positionParent(): Containing scopePkg(): Declaring packageSources: src/go/types/object.go src/go/types/decl.go48-167
Scopes form a tree structure representing lexical nesting:
The Checker maintains the current scope and creates new scopes as it enters blocks, functions, and other lexical constructs via openScope() and closeScope().
Sources: src/go/types/scope.go src/cmd/compile/internal/types2/stmt.go156-164
The type checker reports errors through the Config.Error callback. It distinguishes between:
check.softErrorf)Error codes are defined in internal/types/errors and used consistently across both go/types and types2.
Sources: src/go/types/errors.go src/internal/types/errors/codes.go
Refresh this wiki