Compiler frontend
Thread map, Go 1.0 – 1.17
| Thread | 1.0 | 1.1 | 1.2 | 1.3 | 1.4 | 1.5 | 1.6 | 1.7 | 1.8 | 1.9 | 1.10 | 1.11 | 1.12 | 1.13 | 1.14 | 1.15 | 1.16 | 1.17 | Status at go1.17 (or at the end of its era slice) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Compiler frontend (Go 1.0: 2008–2012) | |||||||||||||||||||
| Lexer, grammar and statement syntax (semicolons, chan operators, conversions) | ● | the surface syntax is the Go 1 one; the yacc grammar go.y and hand-written lexer lex.c stayed the parser until the compiler was rewritten in Go (not in this range). → continues as The syntax package (parser, scanner, tree) (1.18+) | |||||||||||||||||
| Package system, visibility and import resolution | ● | capitalisation-based export and -p/-D/-I import resolution as of go1; compiler flags later reworked by the build system. → continues as Package paths, -p, and build-system contract (1.18+) | |||||||||||||||||
| Export/import data format | ● | textual export data in the object file's __.PKGDEF section was still the format at go1 and in 1.17 had moved through the binary format and then indexed export data → continues as Unified IR: one serialization for noding, stenciling, inlining and export (1.18+) | |||||||||||||||||
| Constants and multi-precision arithmetic | ● | arbitrary-precision constants as at go1 (mparith); later moved to go/constant and math/big → continues as Language features as seen by the type checker (by release) (1.18+) | |||||||||||||||||
| Typecheck/walk separation and package-level declaration order | ● | typecheck pass (typecheck.c) as one separate pass over a whole function tree, still the design at go1.17 in Go form → continues as Old typechecker and IR node-model cleanup (1.18+) | |||||||||||||||||
| Interfaces, type switches, assertions and comparability | ● | interface layout Eface/Iface and comparison rules as at go1 persisted; the runtime later moved to itab caches in Go-era reflect → continues as Type sets, union terms, interfaces and constraint satisfaction (1.18+) | |||||||||||||||||
| Embedded fields, method sets and receivers | ● | embedding via genembedtramp-style wrapper generation as at go1 → continues as Method receiver checking (1.18+) | |||||||||||||||||
| Closures | ● | closure conversion by value-or-reference capture classification as at go1; the compiler later rewrote it → continues as Frontend support for new language features and spec changes (1.18+) | |||||||||||||||||
| Escape analysis and heap allocation | ● | first escape analysis enabled by default in esc.c → continues as the escape analysis in later threads; no 1.18 link. | |||||||||||||||||
| Inlining | ● | first inliner, evolved massively afterwards. | |||||||||||||||||
| Builtins and unsafe | ● | builtin set as at go1 → continues as Language features as seen by the type checker (by release) (1.18+) | |||||||||||||||||
| Channels, select, maps and strings as built-in types | ● | compiler lowering to runtime calls as at go1. | |||||||||||||||||
| Initialization and static data | ● | sinit.c static init as at go1 → continues as Static initialization and package init (1.18+) | |||||||||||||||||
| Composite literals | ● | Go 1 rules; type elision for struct/array elements came later. | |||||||||||||||||
| Variadic functions (...) | ● | ...T as a property of func types. | |||||||||||||||||
| Statement and flow rules | ● | Go 1 rules. | |||||||||||||||||
| Diagnostics, error recovery and compiler plumbing | ● | C compiler diagnostics; messages later shared with types2. | |||||||||||||||||
| Compiler frontend (Go 1.1–1.9) | |||||||||||||||||||
| The C-to-Go translation of the compiler (cmd/gc → cmd/internal/gc → cmd/compile/internal/gc) | ● | ● | ● | done in 1.5; the Go gc package then became the single frontend, later split into syntax, types, ssa and so on → continues as Old typechecker and IR node-model cleanup (1.18+) | |||||||||||||||
| Parser: from yacc to a hand-written recursive-descent parser | ● | ● | ● | ● | ● | ● | ● | the gc-internal parser was removed in 1.8; the syntax package parser is the only parser → continues as The syntax package (parser, scanner, tree) (1.18+) | |||||||||||
| The syntax package, position representation and parse-time checks | ● | ● | still the design (syntax tree with Pos and PosBase; branch checking in the parser) → continues as The syntax package (parser, scanner, tree) (1.18+) | ||||||||||||||||
| Binary export data and the object-file split | ● | ● | ● | ● | ● | ● | ● | ● | binary export format (v1..v5 "bexport"/"bimport") plus inlined bodies; later replaced by the indexed format and then unified IR → continues as Unified IR: one serialization for noding, stenciling, inlining and export (1.18+) | ||||||||||
| Inlining | ● | ● | ● | ● | ● | ● | the Node-based inliner with budget 80 survives, extended later (mid-stack, then PGO) → continues as Compile-time performance, concurrency and the self-PGO'd compiler (1.18+) | ||||||||||||
| Escape analysis and stack allocation | ● | ● | ● | ● | ● | ● | the 2012–2015 flow-graph analysis (esc.go) with param tags remains; rewritten in later releases → continues as Old typechecker and IR node-model cleanup (1.18+) | ||||||||||||
| Closures, method values and variable capture | ● | ● | ● | ● | ● | ● | ● | still the design (capture by value when never reassigned and not address-taken; closure call → function call) → continues as Old typechecker and IR node-model cleanup (1.18+) | |||||||||||
| Language changes and rules as implemented in the compiler | ● | ● | ● | ● | ● | ● | ● | ● | ● | each rule is part of the language; implementation later moved to types2 → continues as Frontend support for new language features and spec changes (1.18+) | |||||||||
| Type aliases (the => experiment and type A = B) | ● | ● | type A = B is the language feature; the first implementation was reverted in 1.8 and redone on [dev.typealias] in 1.9 → continues as Generic type aliases and Alias type nodes (1.18+) | ||||||||||||||||
| Constant arithmetic, Mpint/Mpflt and floating-point constants | ● | ● | ● | ● | ● | big.Int/big.Float-based constants (Mpint, Mpflt) → continues as Old typechecker and IR node-model cleanup (1.18+) | |||||||||||||
| Static initialization, composite literals and init | ● | ● | ● | ● | ● | ● | ● | ● | sinit.go model with static data, dynamic init and oaslit; extended later with staticinit → continues as Static initialization and package init (1.18+) | ||||||||||
| Walk-level lowering and runtime-call optimisations | ● | ● | ● | ● | ● | ● | ● | ● | still the walk/order model; the runtime entry points mostly persist → continues as Static initialization and package init (1.18+) | ||||||||||
| Write barriers, precise stacks and liveness (compiler side) | ● | ● | ● | ● | ● | ● | ● | ● | write-barrier insertion moved into SSA later; frontend marks (pragmas, OASWB) removed in 1.9 → continues as Old typechecker and IR node-model cleanup (1.18+) | ||||||||||
| Compiler data structures: Node, Nodes, Type, and the types package | ● | ● | ● | ● | ● | ir.Node and types.Type as separate packages came in later releases; the 1.9 types package is the start → continues as Types package internals: size, algorithm kind, TFlag, SIMD flags (1.18+) | |||||||||||||
| Compiler performance, formatting and concurrency | ● | ● | ● | backend concurrency via -c, with cmd/go setting it; later default → continues as Compile-time performance, concurrency and the self-PGO'd compiler (1.18+) | |||||||||||||||
| Pragmas, directives and compiler flags | ● | ● | ● | ● | ● | ● | ● | ● | //go: pragma set persisted and grew → continues as Compiler debugging infrastructure: bisect/hash debugging, flags, dumps (1.18+) | ||||||||||
| Race detector and sanitizer instrumentation in the frontend | ● | ● | ● | ● | racewalk pass (later instrument) → continues as Compiler debugging infrastructure: bisect/hash debugging, flags, dumps (1.18+) | ||||||||||||||
| Diagnostics and error messages | ● | ● | ● | ongoing; types2 later supplies messages → continues as Error reporting: codes, messages, and sub-errors (1.18+) | |||||||||||||||
| Compiler frontend (Go 1.10–1.17) | |||||||||||||||||||
| dev.regabi: from *Node struct to the ir.Node interface and concrete node types | ● | ● | ● | ● | ● | ● | ● | ● | done: ir.Node is an interface with ~60 concrete node types (ir.Name, ir.Func, ir.CallExpr, …) and generated DoChildren/EditChildren/Copy; Left/Right/List accessors are gone; Nodes is a plain slice → continues as Old typechecker and IR node-model cleanup (1.18+) | ||||||||||
| dev.regabi: breaking up package gc into base, ir, types, typecheck, noder, inline, staticdata, reflectdata, pkginit | ● | done; layout of cmd/compile/internal/ as it remained → continues as Old typechecker and IR node-model cleanup (1.18+) | |||||||||||||||||
| Indexed export format and the export-data lifecycle | ● | ● | ● | ● | ● | ● | ● | ● | the indexed (iexport) format is the only compiler export format, now carrying positions with columns, type information on inlined bodies, closures and ABIs → continues as Unified IR: one serialization for noding, stenciling, inlining and export (1.18+) | ||||||||||
| Generics bring-up in the compiler (dev.typeparams): parser, -G, types2, irgen, first stenciling | ● | generic code is parsed and type-checked only when the undocumented -G flag is given; stenciling of simple generic functions and types exists but is experimental and not enabled by default → continues as Generics via GC-shape stenciling and runtime dictionaries (1.18+) and Bringing up generics in types2 (1.18+) | |||||||||||||||||
| types2 port of go/types: reviews, error-message parity and language-version support | ● | types2 is used for -G builds only; the legacy typechecker is still the authority for ordinary compilation → continues as Sharing code between go/types and types2 (1.18+), Error reporting: codes, messages, and sub-errors (1.18+) and Bringing up generics in types2 (1.18+) | |||||||||||||||||
| The syntax package: parser, scanner, source reader, positions and error recovery | ● | ● | ● | ● | ● | ● | ● | stable parser with optional generics (AllowGenerics), a fast reader, and pragma handling delegated to the noder → continues as The syntax package (parser, scanner, tree) (1.18+) | |||||||||||
| Constants: Go 2 number literals, evconst, untyped conversion and go/constant | ● | ● | ● | ● | ● | ● | ● | the compiler's constants are go/constant.Value; Ctype/Val/Mpint representation gone; untyped types are types.Ideal{int,rune,float,complex}; rational arithmetic enabled → continues as Frontend support for new language features and spec changes (1.18+) | |||||||||||
| Language version gating (-lang) and language changes implemented in the frontend | ● | ● | ● | ● | ● | ● | ● | -lang enforced by both checkers (old typechecker and types2) with errors naming the required version → continues as Per-file language versions and version gating (1.18+) and Frontend support for new language features and spec changes (1.18+) | |||||||||||
| Package initialization order, static initialisation and init functions | ● | ● | ● | ● | ● | ● | ● | spec-compliant init order (initorder.go), static maps/slices/structs emitted as data where possible, fninit earlier → continues as Static initialization and package init (1.18+) | |||||||||||
| Concurrent compilation and frontend performance | ● | ● | ● | ● | ● | ● | backend compiles functions concurrently via the compile queue; frontend is serial → continues as Compile-time performance, concurrency and the self-PGO'd compiler (1.18+) | ||||||||||||
| Directives and pragmas in the frontend (//go: handling) | ● | ● | ● | ● | ● | ● | pragma handling is an interface between syntax and the noder with misplacement diagnostics → continues as The syntax package (parser, scanner, tree) (1.18+) | ||||||||||||
| Inlining-related frontend work: export of bodies, type switches, closures, devirtualization | ● | ● | ● | ● | ● | ● | inliner handles type switches, method values and (re-enabled for the new export format) closures with limits → continues as Old typechecker and IR node-model cleanup (1.18+) | ||||||||||||
| The legacy typechecker: error quality, alias/recursive-type handling and type checking order | ● | ● | ● | ● | ● | ● | ● | ● | still the authoritative checker outside -G; heavily incrementally improved → continues as Old typechecker and IR node-model cleanup (1.18+) | ||||||||||
| Lowering in order/walk and the shape of runtime calls emitted by the frontend | ● | ● | ● | ● | ● | ● | ● | ● | the frontend lowers many constructs to specialised runtime calls; some previously frontend work moved to SSA construction → continues as Method wrappers and promoted-method sharing (1.18+) for wrappers only; otherwise no direct continuation | ||||||||||
| checkptr instrumentation and compiler debugging flags | ● | ● | ● | ● | ● | ● | -d=checkptr implied by -race/-msan; Debug is a struct → continues as Compiler debugging infrastructure: bisect/hash debugging, flags, dumps (1.18+) | ||||||||||||
| Types package internals and type printing | ● | ● | ● | ● | ● | ● | types hosts type constructors, size computation and printing → continues as Types package internals: size, algorithm kind, TFlag, SIMD flags (1.18+) | ||||||||||||
| Register-ABI plumbing in the frontend | ● | ● | ABI wrappers generated per ir.Func, ABIs exported across packages → continues as Method wrappers and promoted-method sharing (1.18+) | ||||||||||||||||
Thread map, Go 1.18 – 1.28
| Thread | 1.18 | 1.19 | 1.20 | 1.21 | 1.22 | 1.23 | 1.24 | 1.25 | 1.26 | 1.27 | 1.28 | Status at HEAD |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Compiler frontend: the types2 type checker (Go 1.18–1.28) | ||||||||||||
| Bringing up generics in types2 (type-parameter operands, core/structural types, tparam-as-interface) | ● | ● | ● | ● | ● | ● | complete; core types no longer used by the checker (removed in 1.25), residual fixes only | |||||
| Type sets, union terms, interfaces and constraint satisfaction | ● | ● | ● | ● | ● | ● | ● | ● | stable; comparable satisfaction by non-type-parameter interfaces since 1.20 | |||
| Instantiation, Named types, Context deduplication and lazy expansion | ● | ● | ● | ● | ● | ● | ● | ● | ● | Named has an explicit state machine, fromRHS/underlying lifecycle enforced since 1.26 | ||
| Type inference and unification | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | new unifier-centred inference since 1.21; reverse inference, interface inference and untyped-constant defaulting shipped; assignment-context refinements in 1.27 | |
| Generic type aliases and Alias type nodes | ● | ● | ● | ● | ● | Alias nodes always on (GODEBUG gotypesalias removed in 1.27); generic aliases enabled | ||||||
| Type declaration cycles, valid-type detection and the object path | ● | ● | ● | ● | ● | ● | ● | validType uses a type nest; setDefType removed and replaced by "pending" checks in 1.26; finite-size check at value observation | ||||
| Per-file language versions and version gating | ● | ● | ● | ● | ● | ● | Info.FileVersions; version computed per file from //go:build lines | |||||
| Language features as seen by the type checker (by release) | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | generic methods (1.27) and string(int) restriction (1.28) are the latest; untyped composite literal inference in progress | |
| Composite-literal type elision via target types (#12854) | ● | ● | in progress; targets threaded through assignments, calls, struct literals, sends, switch, delete/append/copy and comparisons | |||||||||
| Method receiver checking | ● | ● | ● | ● | receiver handled in collectRecv (1.24 rewrite) | |||||||
| Error reporting: codes, messages, and sub-errors | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | compiler and go/types share messages and error codes (internal/types/errors) |
| Sharing code between go/types and types2 | ● | ● | ● | ● | ● | ● | most go/types files are generated from types2 | |||||
| Checker performance, memory and API ergonomics | ● | ● | ● | ● | ● | ongoing micro-optimizations driven by gopls and compilebench | ||||||
| Robustness: invariants, incomplete types and importers | ● | ● | ● | ● | invariant checker in tests; new types2 importer in progress | |||||||
| Compiler frontend: syntax, IR, unified IR and the generics implementation (Go 1.18–1.28) | ||||||||||||
| Generics via GC-shape stenciling and runtime dictionaries | ● | ● | ● | ● | ● | ● | ● | ● | shipped design since 1.18 (first built on the old typechecker/-G=3, reimplemented on unified IR in 1.20); shape sharing is still "underlying type, pointers collapsed", with occasional shape/reshape bug fixes through 1.27 | |||
| Unified IR: one serialization for noding, stenciling, inlining and export | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | the only frontend since 1.21; internal/pkgbits + noder/{writer,reader,unified,linker}.go; UIR at version V4 (V5 method indices added in 1.28 dev), documented with a formal grammar in 1.25 |
| Old typechecker and IR node-model cleanup | ● | ● | ● | ● | ● | ● | ● | ● | ● | typecheck is a thin library (constant folding gone, Ntype gone, ir.CurFunc gone); types2 is the only checker; IR remains ir.Node with generated node_gen.go | ||
| RType/ITab fields and implicit conversions in IR (RTTI plumbing) | ● | complete; every runtime-type-needing IR node carries its RType/ITab explicitly | ||||||||||
| Generic methods (type parameters on methods) | ● | ● | language feature enabled (go1.27 language version); GOEXPERIMENT=genericmethods was added 2026-04-30, default flipped on, flag deleted 2026-06-12; UIR V4 plus V5 method-index fix | |||||||||
| Static initialization and package init | ● | ● | ● | ● | ● | ● | ● | ● | ● | staticinit with inline-aware static init (enabled in 1.21), outlined map init for deadcode, init splitting redone in 1.28 cycle | ||
| Compile-time performance, concurrency and the self-PGO'd compiler | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | backend concurrency = GOMAXPROCS (normally capped at 4 by go build); compiler built with PGO from cmd/compile/default.pgo, refreshed about annually; startup heap boost 128 MiB | |
| Compiler debugging infrastructure: bisect/hash debugging, flags, dumps | ● | ● | ● | ● | ● | ● | ● | ● | -d flags with concurrency tagging, internal/bisect-based HashDebug, astdump HTML | |||
| Frontend support for new language features and spec changes | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | ● | tracks the language; most features need a noder/typecheck/walk piece plus a types2 piece owned by the fe-types area |
| The syntax package (parser, scanner, tree) | ● | ● | ● | ● | ● | ● | ● | ● | ● | stable; mostly error-message and parser-tolerance work | ||
| Package paths, -p, and build-system contract | ● | ● | ● | -p required; symbols carry real package paths; export-data readiness signal to cmd/go since 1.28 dev | ||||||||
| Types package internals: size, algorithm kind, TFlag, SIMD flags | ● | ● | ● | ● | ● | types.Type computes layout, alg kind, pointer bytes and abi.TFlag once, lazily and side-effect-free | ||||||
| Method wrappers and promoted-method sharing | ● | ● | ● | ● | ● | ● | wrappers for promoted methods shared across receiver types (1.28 cycle) | |||||
| SIMD frontend: the "midway" source-to-source translator | ● | ● | ● | prototype in the frontend, -d flag controlled | ||||||||
| ir.StaticValue, ReassignOracle and function-variable tracking | ● | ● | ● | batch oracle used by inliner/escape; ongoing migration of callers | ||||||||
Compiler frontend (Go 1.0: 2008–2012)
Reader: Claude Sonnet. Cites 863 of 935 commits in this slice; every non-noise commit is cited, plus 29 larger commits the noise filter had set aside, which a separate gap reader described. Most pre-2010 messages are one line long, so many claims rest on subject lines and diffstats. About 400 small fixes are cited as per-year hash lists.
Release digest for this slice
- Go 1.0 — The compiler frontend went from a prototype tracking a weekly-changing spec (semicolons, chan operators, export keywords) to the Go 1 language with a separate typecheck pass, exact constants, Eface interfaces, closures, escape analysis, inlining and a stable textual export format.
Lexer, grammar and statement syntax (semicolons, chan operators, conversions)
Span: Go 1.0 → Go 1.0 · Status at go1.17: the surface syntax is the Go 1 one; the yacc grammar go.y and hand-written lexer lex.c stayed the parser until the compiler was rewritten in Go (not in this range). → continues as The syntax package (parser, scanner, tree) (1.18+)
Continues in: Parser: from yacc to a hand-written recursive-descent parser (Go 1.1 → Go 1.8)
Design. The frontend is src/cmd/gc in C: a bison/yacc grammar go.y that builds Node trees directly, a lexer lex.c, and per-architecture code generators (6g/8g/5g) that initially owned most of the semantic code. In 2008 almost every syntactic rule of the language was still moving, and the compiler followed the spec as it was rewritten week by week. Statement termination is the clearest example. The first optional-semicolon support (8200a0b088, 0006c83231, c242b53d22) was replaced by “all statements and declarations are terminated by semicolons; they may be omitted at top level and before/after a closing ) or }” (d364d28142), which doubled parts of the grammar; in June 2009 the rule was moved into the lexer, which now inserts the semicolon itself so the type and statement grammars no longer needed duplicated variants (8abcdee175, 179 insertions, 284 deletions). Follow-ups made 6g match the spec exactly: no semicolon after the package clause, one allowed after imports (aaaa1fc69b), a semicolon inserted at EOF (ec13ed1fce), and mandatory { } around else blocks (58e19aa4cb, 2011). The if condition became mandatory (52943bfe4d, 2011).
Expression and type syntax went through several iterations. Conversions and constructors were first T{} and T(expr) (0194aaf918, Ken Thompson, which also stopped treating func as a type), then composite literals briefly became T(...) with a warning for the brace form (07244f7c80, Feb 2009), and returned to T{x} with a stricter split between T(x) conversion and x.(T) assertion a month later (49cc649e59). Parentheses were allowed to disambiguate types (ebc10db3e1). Channels first had a <-/-< pair, then a new syntax (ac048ce7f4) and in September 2008 binary <- is send and unary <- is receive, with case a := <-ch: and case a = <-ch: in select (47919799b4, 304440356d). Directional channel types were enforced in May 2009 (f4d3d22a94) and chan <- chan precedence and func() func() were fixed in 2010 (7abb4b3a96), plus send precedence (0e47460915). In December 2008 *chan became chan and *map became map, with new(T) taking the pointee type: “mainly a syntactic change: the compiler representations don’t change (chan and map are now hidden pointers like string)” (dc7b2e98d2, 88b5c5f0f8, 316d377ac2). The range statement arrived in December 2008 (26b357ca5b, b79272d9a2, ae5a475e20), &^ and &^= in March 2009 (bb02e481d2), [...] closed arrays in January 2009 (b0f627a6e1), and empty var ( ) factoring in October 2008 (5f1202428b). Redundant iota rules were redone twice (d915b96100, c597845e13).
The lexer also gained several user-visible rules: control characters other than white space are rejected (2538cf747b), · is disallowed in source (9e497c3656), backslash-newline in strings is illegal (0c222d6e49), //line file:number directives were added in July 2010 (444066e56d, 19d7fc4026, with the earlier //line number file form changed), and colons were permitted in the directive file name (ecda0fa5d4).
Timeline.
- Go 1.0 — Done: user-visible everything above, in chronological order.
- 2008: optional semicolons (
8200a0b088),a,b := fun()(81b325db1b),new chan syntax(ac048ce7f4), send/receive operators (47919799b4), semicolon rules (d364d28142),*Tas implicit declaration ofTremoved (02d184b303), trailing comma in braced lists (82e41cc533),DOTDOTDOT(74427c6346),range(26b357ca5b), chan/map no longer pointers (dc7b2e98d2),T{}/T(x)(0194aaf918). - 2009: composite-literal paren syntax and back (
07244f7c80,49cc649e59), type switches withcase nil(a4a10ed856,0f469a99a3), lexer-driven semicolons (8abcdee175), conversion rules per the new spec (7f3eb2738f), no parens around type in struct literal (9c3c140984), semicolon/package-clause rules (aaaa1fc69b),x[y:]for strings (aa4c638b7b). - 2010:
//linedirectives (444066e56d), EOF semicolon (ec13ed1fce),selectcaseexpr = <-c(9b62461a8f), new slice spec (fce222a95b), improved syntax errors (2a01d72878,78c27ed650). - 2011:
ifneeds a condition (52943bfe4d), else needs braces (58e19aa4cb), non-blocking send/receive statement syntax removed (cb584707af),x, ok := <-creplacesclosed(c)(8bf34e3356). - 2012:
switch _ := v.(type)rejected (74ee51ee92), diagnose(x) := 0and similar (112267d55e, 2011), top-level var/const rules (4bcc9c6b5e). Left open: nothing noted in the commits; the C yacc grammar is still the parser at the go1 tag.
- 2008: optional semicolons (
Package system, visibility and import resolution
Span: Go 1.0 → Go 1.0 · Status at go1.17: capitalisation-based export and -p/-D/-I import resolution as of go1; compiler flags later reworked by the build system. → continues as Package paths, -p, and build-system contract (1.18+)
Design. Visibility changed repeatedly in 2008–2009. First came export adjectives on external var, const, type and func declarations (989676d2ba, 695f83a9e0, b59b551be7), and in November 2008 a package keyword for package-local declarations (d3f6093931, 9c7b064043). In January 2009 the export name-list statement was removed and “package local” became the default; the compiler warned when the name’s case did not match the keyword (07d344e442, 3decb42e6f, 605d0746c5). Case then became the real rule: other packages’ lower-case names are rejected in struct field selectors, method calls and P.t (06869eedf9, aec4d3194a, 61590c4c44), assignments to private fields during initialization (9da6666a8a), implicit assignment to non-exported fields in copy and append (151b2f1509) and then the opposite relaxation for method receivers and copy of structs with unexported fields (0b209b36b6, d03611f628).
Package lookup went from a flat global namespace to explicit paths. 6g autoloaded imports via #pragma lib (e90ae879d6, 12c81a0ce8, f95da9a639), later by searching a pkg directory, .6 before .a, archives with __.PKGDEF and 0-length __.SYMDEF (63a84348cc). -I DIR added include directories (062d6998ab), local-path lookup was separated from standard directories (70e232e668), the package global name space was eliminated (531e6b77c8, Jan 2010) and the runtime type data records full package paths (1cecac8134). The name main stopped being reserved (c1a695c160, daffc2d2ef). Unused imports are an error (73e52ae971) and print the path (f1550482fa). Import cycles: -p tells the compiler “if you see an import of this package, give up early”, because a cycle otherwise shows up as two different copies of the same package and type-signature mismatches (1e480cd1ad). Import-path hygiene landed in early 2012: \ diagnosed (33f3afa7af), special characters rejected (dc38756ce1), absolute paths disallowed (d0d251f858), ~ allowed on Windows and slash handling (d0a4c9bb62, 29199aa4e4). Relative imports were reworked for cmd/go with a -D prefix option: import "./foo" with -D a/b/c becomes a/b/c/foo, so a _/home/gopher/foo pseudo-hierarchy makes relative imports ordinary paths (604f375110).
Timeline.
- Go 1.0 — Done: user-visible
- 2008:
exportadjectives (989676d2ba,695f83a9e0),packagelocals (d3f6093931), autolib (e90ae879d6). - 2009: case-based visibility and the removal of export lists (
07d344e442,06869eedf9,61590c4c44),-I(062d6998ab), whole-package compilation (66bb399fdd, see the typecheck thread), unused imports (73e52ae971),import .fixes (63aeaa2a03,5a5799f613,7b240e8135). - 2010: global name space dropped (
531e6b77c8), full paths in type data (1cecac8134),-urequires imports marked safe (d20ad1c75a), canonical path checks (555f5b6b24,7e92e1cbfa). - 2011:
mainnot reserved (c1a695c160),-pimport-cycle flag (1e480cd1ad), package paths in symbol names with period/0x7f escaping (33f1d47b38). - 2012: import path validation (
dc38756ce1,d0d251f858,daacba5184,cc99d8ad0b),-Dfor relative imports (604f375110). Left open: nothing noted.
- 2008:
Export/import data format
Span: Go 1.0 → Go 1.0 · Status at go1.17: textual export data in the object file’s __.PKGDEF section was still the format at go1 and in 1.17 had moved through the binary format and then indexed export data → continues as Unified IR: one serialization for noding, stenciling, inlining and export (1.18+)
Continues in: Binary export data and the object-file split (Go 1.1 → Go 1.9)
Design. The compiler writes a text description of everything a package exports into the object file, delimited by $$ markers, and the importing compiler parses it with a second yacc entry in go.y (the “import grammar”). The first version dated June 2008 (2254a8ee99, 343f5aa7b4, 4528854308 made names unique). On 2008-10-03 Russ Cox rewrote it (b8babed7c2, 1827-line delta, export.c shrank by roughly 700 lines): declarations are printed as Go-like type flag.Value interface {...} with fully qualified identifiers, the delimiter changed from (( )) to $$, and sys.go uses a leading export. Other early decisions: only explicitly exported types are exposed to the importer (fb2c66710c), type names “live at the name” so type T struct{ next *T } and type T *struct{ next T } work without forward declarations (74e2e087e2), \n$$ as the section delimiter (4958d41d3b), tag strings on struct fields and across multiple names (f27aaf4819, 1850b29da6, f2b1536328), ... (2fef4c7198), embedded types (21617250f4), and a separate section for non-exported types referenced by exported ones (aacfbb461b). Constants are exact: negative constants (c3d841f5d4), large constants (2b75556436) and multi-precision floats via a decimal-integer “p” exponent syntax (f8797daa9f); complex constants (713e3e1541).
From 2011 the format was prepared for inlining: all transitive dependencies are listed, with indirect imports marked, “purely informational” (e6f3aa6c36); string literals used as package qualifiers are prefixed with @ which removed the : before tags (b536adbfba, Luuk van Dijk); further changes, with a “minimal change to gcimporter” (40b2fe004f); tags allowed on parameters (56668283f1); nil literals exported without inferred type (feaa9ed10a), implicit type bug fixes (5c52404aca, 419c53af30, 77aaa3555d), field names in struct literals inside exported inline bodies not qualified for embedded builtin types (6ff01f01f4), and a limit on the size of exported recursive interfaces to stop memory blowup (aa63a928ea). The byte/uint8 distinction was preserved in errors and import data (862179b0f5).
Timeline.
- Go 1.0 — Done:
- 2008: first import/export (
2254a8ee99), new format (b8babed7c2), embedded type export (21617250f4), mp float constants (f8797daa9f). - 2009: re-export of bools fixed (
dec12d3654),unsafeimport foundation (1d4daa2d39), import-name resolution fixes (c715b58dad,e733766dda). - 2010: complex constants (
713e3e1541), export of complex types (cd016d7558), full paths (1cecac8134). - 2011: metadata for all dependencies (
e6f3aa6c36), inlining-preparation format changes (b536adbfba,40b2fe004f), byte/rune distinction (862179b0f5). - 2012: limits and fixes (
aa63a928ea,feaa9ed10a,5c52404aca). Left open: the textual format has to carry inline bodies, which the 2011 commits say they were preparing; no binary format yet.
- 2008: first import/export (
Constants and multi-precision arithmetic
Span: Go 1.0 → Go 1.0 · Status at go1.17: arbitrary-precision constants as at go1 (mparith); later moved to go/constant and math/big → continues as Language features as seen by the type checker (by release) (1.18+)
Continues in: Constant arithmetic, Mpint/Mpflt and floating-point constants (Go 1.1 → Go 1.9)
Design. Go’s “ideal” constants were implemented by hand in mparith*.c: Mpint integer arithmetic (mp constants 9c2ade358d, fixed arithmetic 272ae659db) and multiprecision floating point Mpflt (3fa4610601, Ken Thompson, December 2008). Floats are truncated when used in float64/float32 contexts (89996e1fb1). Precision work: 29 more bits of precision (Mpscale) from floating-constant multiply with rounding code for const fix = float (95b93c28e3), and floating literal normalisation moved from word-oriented to bit-oriented for up to a full extra word of precision (f6b93ab432); denormals round correctly (cf63e34b1d); constant divide bug (ce85868a00); float zero 0p+0 (f51ca384eb). The type-rule side: ideal bools (a95ee61aea), comparisons have type bool (ed6de5af4c) and, at the end, “drop ideal bool” (126d475a43) followed by “new, less strict bool rules” (e29d3dfc49) and the return of ideal bool for a corner case (a457fa500d). Complex numbers arrived in February 2010 as a three-step plan (front-end, back-end, library): complex, complex64, complex128 types (33d6a260c1), complex constant multiply and divide (fc010adcd7), simplified typecheck that does not convert to float prematurely (4ac011a011), and constant float parts of complex constants (94df1a067c).
Shift rules changed many times: typing of (1<<x) (944ad62ecd), x << "a" and 1 << int(2) (0aa1b1508a), shifts must be unsigned (message, 67941bf644), then “new shift rules” where 1.0<<2 is okay (5ab096d030) and a shift-type bug (4389192669). Unary ^: ^ type(const) inverts “enough” bits, signed becomes illegal (b8be809c10). Constant-evaluation hygiene: constant evaluation decided by whitelist instead of blacklist (1ee83f851d), string constant comparison made unsigned (3a2d64789b), “do not constant-evaluate (interface{})("bar")” (4b13d1b9b5), original expression kept for error messages (4349effb15, 60e4a61d30, 21f1769519), constant shift overflow errors (79db6ada48), friendlier constant arithmetic errors (337547d1c9) and constant % on floats (83feedf7bf). Character constants received typing rules in December 2011 (be0ffbfd02).
Timeline.
- Go 1.0 — Done:
- 2008: mp ints (
9c2ade358d,272ae659db), exact large-constant export (2b75556436), mp floats (3fa4610601),(1<<x)(944ad62ecd). - 2009: ideal bools (
a95ee61aea),^on consts (b8be809c10), shift checks (0aa1b1508a), float/int64 conversions (1620023d03). - 2010: complex (
33d6a260c1,fc010adcd7), precision (95b93c28e3,f6b93ab432), const simplifications (ed13d39972). - 2011: denormal rounding (
cf63e34b1d), shift rules (5ab096d030), character constants (be0ffbfd02, Dec). - 2012: ideal bool dropped and relaxed (
126d475a43,e29d3dfc49), shift overflow (79db6ada48),len(array)/cap(array)constant rule (d4fb568e04). Left open: nothing noted.
- 2008: mp ints (
Typecheck/walk separation and package-level declaration order
Span: Go 1.0 → Go 1.0 · Status at go1.17: typecheck pass (typecheck.c) as one separate pass over a whole function tree, still the design at go1.17 in Go form → continues as Old typechecker and IR node-model cleanup (1.18+)
Continues in: The legacy typechecker: error quality, alias/recursive-type handling and type checking order (Go 1.10 → Go 1.17)
Design. Until mid-2009 type checking was intermixed with code generation: walk.c and the arch-specific code did conversions, argument checks and constant evaluation. On 2009-07-29 typecheck was introduced “before walkexpr”, not complete but the compiler still worked (9271c6402e, plus walkexpr taking Node** and dropping indir, 056940d84b; dead code deleted b754b4348f). By 2009-08-03 “typecheck.c is now responsible for all type checking except for assignment and function argument ...” (9dc22b6d6f, 1141 insertions, 1363 deletions) and assignments, switch, if, for followed (d8c19c80dc). Select was split into typecheck + walk in its own file (f7a867e1a6); := and range processing were made lazy so declarations do not need order (54b403723b, 2609731736, old2new gone); var blocks evaluate lazily (dbe004efe4); and “forward declarations not necessary” (b648716ee9, 990 insertions, 668 deletions) deleted prototypes in favour of resolving names on demand (“excluding import data, no yacc node has type Type* anymore”, 35e5906f91). Package compilation became whole-package (66bb399fdd) and forward type declarations were deleted (a92610208e). Steps toward this: functions’ forward declarations (be16caf872, e52e9ca82e) and constants referring to later constants in a block (db508ccbff).
Remaining work was explicitly noted: “initializer cycle detection” and “nicer error for type checking cycles” (b648716ee9), later done with initialization-loop diagnostics (41861a8812, 896f0c61c8) and a typechecking loop detail message (2aafad25b4). In June 2010 “new typechecking rules” made assignment and conversion code mirror the spec, and renamed runtime functions to separate interface conversions from assertions (convT2I, assertI2T, 565b5dc076). Other stages: the real type of identifiers is tracked (49a835fc97); sort errors by line number (2372408189); typecheck the whole tree before walking, a prerequisite for escape analysis (e59aa8ea4a, Jun 2011, 177 insertions 345 deletions); builtins resolve to the built-in symbol (e77f057bf3). Type declaration cycles: type T *struct { T } as invalid embedded (6c2738eb43), recursive types (05a1eb1ab0), recursive interfaces (44898c7b76, 1734cb02e7), recursive forward references through pointer fields (b6f0632e93), and “typecheck loop” fixes (5e98505ba7).
Timeline.
- Go 1.0 — Done:
- 2009: typecheck pass (
9271c6402e,9dc22b6d6f,d8c19c80dc), lazy declaration processing (dbe004efe4,54b403723b,2609731736), no forward declarations (b648716ee9,a92610208e), whole-package compilation (66bb399fdd), per-file filename disambiguation dropped (107d404378). - 2010: spec-mirroring conversion/assignment (
565b5dc076), less aggressive name binding for line numbers (76da2780c3), types inside function bodies (17f90c68c6). - 2011: whole-tree typecheck (
e59aa8ea4a), cumulative error count (3208917d54). - 2012: typecheck-loop diagnostics (
2aafad25b4), field+method same name (7dd90621f8),returnexpression-list checks (1d3ca9236e). Left open: nothing noted.
- 2009: typecheck pass (
Interfaces, type switches, assertions and comparability
Span: Go 1.0 → Go 1.0 · Status at go1.17: interface layout Eface/Iface and comparison rules as at go1 persisted; the runtime later moved to itab caches in Go-era reflect → continues as Type sets, union terms, interfaces and constraint satisfaction (1.18+)
Design. Interface support began as signature tables: i2s, s2i, i2i conversions (ead7a6d47a, 52861558f4), “interface on arbitrary types” with global signatures for basic types (1bf38484d1), duplicate interface signatures (0a7e4a7415), and sigt/sigi structures. On 2009-05-06 “new interface rules (code got simpler!)” (a6ba5ec535). On 2009-05-20 the representation changed: before, every interface value was {addr, Itype*} with Itype{Sigt *type; Sigi *inter; void *method[n]} acting as a vtable; now interfaces with static type interface{} use struct Eface {void *addr; Sigt *type}, which “reduces the number of Itypes that have to be computed and cached”, opens up avoiding calls, and lets interface{} values be laid out at compile time for the new reflection (2da5022bcf, plus ifaceop split into ifacecvt and ifaceop, a39bae095a). The runtime moved to reflect data structures in July 2009 (c7513eac88, 541e638f9b). Conversion rules: narrowing needs type assertions (5f4f5647ef), i.(T) requires non-nil i (23e62d169f), a heuristic complains when putting T in an interface when T has pointer methods (4eb7ceba58), conversion to interface type when implicit assignment would be okay (d436a70193), typed nil constants distinct from nil interface (a14b28a24d), unsafe.Pointer not a pointer (5c2666c18c), interface embedded in interface (b4af09ab56) and disallowed interface { x, y() } (7743ffead4), recursive interface embedding (1734cb02e7).
Type switches arrived 2009-03-06 along with removing typeof (a4a10ed856), got binary search and case nil (0f469a99a3), a rewritten switch (bf983477a2, 79fa5b65cb), and the unused-switch-variable error (aac144b120). Interface equality was first a runtime hack sys.BUG_intereq (827dcb86b7) until the compiler supported it (edb1412c50, 5933dbda3a).
Comparison and map keys were slowly formalised: map key types checked at compile time (98b34e5bbd), maps allowed as keys because maps have == (75fe1303c1), then the reverse: “remove func, map compare” (5bb54b8e9c) and “disallow map/func equality via interface comparison” (46deaa297b, Dec 2011), “new comparison rule” basing comparison compatibility on assignment compatibility (23bd214aee), invalid keys disallowed (7ca406396f), and in December 2011 == on structs and arrays: “structs or arrays that are ‘just memory’, like [2]int, continue to use the AMEM algorithm; those containing strings or interfaces use generated functions for equal and hash; the runtime helper runtime.equal(t, x, y) handles the general case; for short values (≤4 fields or elements) the elementwise comparison is inlined” (196b663075). Algorithm tables got specialised entries: word-sized copy/equal (4d903504b3, 0–6% regexp benchmark gains), slices and sizes 8/16/32/64/128 (54e9406ffb, ChanUncontended 226→94 ns) and zero-sized types (1ff1405cc7, ChanSem 127→78.6 ns). Floating-point map keys were handled in 2012 (408f0b1f74). Finally the predeclared error type was added (2a0e15d36c, Nov 2011) with a temporary GOEXPERIMENT=os.Error (47f4bf763d, “this won’t last long”), and GOEXPERIMENT=reorg to ease conversions (ae7a003cf9).
Timeline.
- Go 1.0 — Done:
- 2008: signatures and conversions (
ead7a6d47a,1bf38484d1), interface equality (edb1412c50). - 2009: new interface rules (
a6ba5ec535),Eface(2da5022bcf), type switches (a4a10ed856,0f469a99a3), embedded interfaces (b4af09ab56), map key checks (98b34e5bbd). - 2010: new comparison rule (
23bd214aee), recursive interfaces (44898c7b76), equality algorithm specialisation (4d903504b3). - 2011: algorithms (
54e9406ffb),errorand experiments (2a0e15d36c,47f4bf763d,ae7a003cf9), map/func compare removed (5bb54b8e9c), struct/array==(196b663075). - 2012: zero-size algorithms (
1ff1405cc7), comparison recursion fix (427b5bddcd), struct with_field (c4c92ebeb6), float map keys (408f0b1f74). Left open: the pointer-methods heuristic was labelled a heuristic that “catches the problem” only (4eb7ceba58,935953a9f8).
- 2008: signatures and conversions (
Embedded fields, method sets and receivers
Span: Go 1.0 → Go 1.0 · Status at go1.17: embedding via genembedtramp-style wrapper generation as at go1 → continues as Method receiver checking (1.18+)
Design. “Unnamed substructures” appeared in October 2008 (61361af9e8), then import/export of embedded types, auto-& on methods and embedded methods (21617250f4, 6fecb76eea, 7ed8fc611d, b642cf8c00). Methods on arbitrary types were stepped in: any type but only *struct tested (2119294af9, 89ac5618ac), slices as receivers (b2dfd787d7), funcs (5e2c05877d), chan/map/string once they were real types (316d377ac2), complex types (883d68f885), unnamed struct types (4267974c0b). An anonymous interface field m shows up in the struct’s method set (401a95aa83). Wrapper generation requires care with private methods in signatures (35e37bbf41), methods must immediately follow their struct (ef40d9435b), and in 2011 non-methods are kept out of xmethod (11075ed893) and copytype resets xmethod (ffa6b383f5). Method expressions on concrete types came in Dec 2009 (0d668259dc, 9e2c9bb0ca), receivers relaxed (0b209b36b6), invalid receivers explained (4684df520f, 6a401339c1), names made Go-like (1bd4b6371a), unexported methods of the same name no longer confused (987a580b9f), field-and-method same name diagnosed (7dd90621f8), ambiguous selector deduplicated (7ae1fe420e), pointer-to-pointer method call message (7df9ff5594).
Timeline.
- Go 1.0 — Done:
- 2008:
61361af9e8,6fecb76eea,b642cf8c00, method on*Tnames (258c817a1b). - 2009: methods on slices, funcs, chan, map, string (
b2dfd787d7,5e2c05877d,316d377ac2), method expressions (0d668259dc). - 2010–11:
883d68f885,0b209b36b6,1bd4b6371a. - 2012:
4267974c0b,987a580b9f,7dd90621f8. Left open: nothing noted.
- 2008:
Closures
Span: Go 1.0 → Go 1.0 · Status at go1.17: closure conversion by value-or-reference capture classification as at go1; the compiler later rewrote it → continues as Frontend support for new language features and spec changes (1.18+)
Continues in: Closures, method values and variable capture (Go 1.1 → Go 1.7)
Design. Function literals first needed parameter-declaration parsing fixes (8003849498, 814320c8b4). Closures arrived with 6g support on 2009-02-06 (0970c46863, 251 insertions) building the closure via a runtime.closure call. Function literals are named _f007·filename-style to allow multiple closures per package (416b27548e); the outnamed flag is copied (941ed00b1d). Performance work was done by Luuk van Dijk in 2011: calls to function literals called in place skip runtime.closure (9b82408f6d; BenchmarkCallClosure 499→5 ns, CallClosure1 681→160 ns), merely referencing an outer variable in a closure no longer forces heap allocation (2c4edb0eea; 135→6 ns), and closures without closure variables omit the wrapper (ba25778f3f, Jan 2012). Bugs: closure bug (e8ff9a624f), top-level closure (890bdc5339), escape analysis + inlining + closure (075eef4018), loopdepth for labels (9bf3478658).
Timeline.
- Go 1.0 — Done:
- 2009:
0970c46863,416b27548e,941ed00b1d. - 2011:
9b82408f6d,2c4edb0eea,e8ff9a624f,890bdc5339. - 2012:
ba25778f3f,075eef4018. Left open: closures containing closure expressions were excluded from inlining (a62722bba4).
- 2009:
Escape analysis and heap allocation
Span: Go 1.0 → Go 1.0 · Status at go1.17: first escape analysis enabled by default in esc.c → continues as the escape analysis in later threads; no 1.18 link.
Continues in: Escape analysis (esc.c → esc.go) (Go 1.0 → Go 1.9) · Escape analysis and stack allocation (Go 1.1 → Go 1.9)
- background Go Escape Analysis Flaws listed in Go: A Documentary
Design. Early rule: taking the address of a local moves it to the heap (391425ae55), refined to not move x because of *&x (a75e347a21). On 2011-08-24 Luuk van Dijk added a real escape analysis, switchable with -s, effects inspectable with -m, defaults old paths (847b61b554, 945 insertions). Days later it was enabled: “-s now means disable escape analysis”, leaks for struct/slice/map literals fixed, ... tracking, new(T) and slice literal rewritten into stack allocation when safe, and annotations added to reflect (db5f9da425). Supporting changes: stack-allocated slice backing arrays are zeroed (c45c0c0c1d), a temp = nod+tempname helper (9854fd2a0e), FlagNoPointers passed to runtime.new (bf9c778fe2), loopdepth analysis for labels (9bf3478658), label recursion (60d47101aa), and the typecheck-whole-tree prerequisite (e59aa8ea4a). Goto restriction work removed stack frame zeroing (7f4c5ea7d8).
Timeline.
- Go 1.0 — Done:
391425ae55(2009),a75e347a21(2009),847b61b554anddb5f9da425(2011),c45c0c0c1d,bf9c778fe2,9bf3478658,075eef4018(2012). Left open: nothing noted.
Inlining
Span: Go 1.0 → Go 1.0 · Status at go1.17: first inliner, evolved massively afterwards.
Continues in: Inlining (inl.c → inl.go) (Go 1.0 → Go 1.9) · Inlining (Go 1.1 → Go 1.9)
Design. Inlining is exported in the object file: export format changes in October and December 2011 (b536adbfba, 40b2fe004f) carry function bodies. a62722bba4 (2011-12-14) added “cross- and intra-package inlining of single assignments or return <expression>”, with hairy cases (calls, closures, ...) excluded, disabled without -l (824 insertions). Follow-ups: empty bodies and _ arguments (7e6890a670), inlining fixes (97fd7d5f34, 836a517f69, 524fb81c41), enabled by default 2012-01-10 (4a6b07f235), unsafe.Pointer permitted (2332439b1b, 1b19134c4f, 82a6a4f39e), minor changes (fc128403dc), append inlining of dst = append(src,...) (36cec789cd). The order of evaluation was repaired by a new pass that “moves things with a fixed order out of expressions and into the statement sequence”, because pulling calls out had caused illegal reorderings, worse with inlining (ee9bfb023a, Jan 2012, plus 5efd5624cc for && and ||).
Timeline.
- Go 1.0 — Done: 2011:
b536adbfba,40b2fe004f,a62722bba4,7e6890a670. 2012:4a6b07f235,ee9bfb023a,2332439b1b. Left open: excluded calls, closures and...(a62722bba4).
Builtins and unsafe
Span: Go 1.0 → Go 1.0 · Status at go1.17: builtin set as at go1 → continues as Language features as seen by the type checker (by release) (1.18+)
Design. The early sys package gave way to builtins: len takes an expression (b2d9020242) and fixed arrays (4c5a165873), print/println, printn/panicn (f21e731c71), panicln deprecated (623dfd1b07). Copy: copy without result (01c2de0c15), *[10]int to slice (9be56adf3c, removed by 82ee481dfc), copy([]byte, string) (82c6f5e3d1). append landed 2010-10-27 (d8b5d039cd), optimisation by dst = append(src, ...) inlining (36cec789cd), append([]byte, string...) (77fac21e82). Panic/recover: 01eaf780a8 (2010-03-30) enforced a single argument and 9b1507b050 implemented them; defer print etc. (a186b77b03). delete(m, x) was added while retaining m[x] = 0, false for a transition month (1d687c742d) and the old syntax removed (5fc3771b3a). close on receive-only channels disallowed (f58ed4e641). Unsafe: unsafe.Sizeof, Offsetof (8a70545b57), Alignof (651972b31f), then in 2011 returning uintptr (cf9f380499), non-call use diagnosed (924ea515cf), old unsafe functions deleted (1f2445d27b), unsafe.New (33649bd278), reflect moved into unsafe (c367d1b789). string(int)/string([]int) conversions (64c3fe05bf), []int(string), []byte(string) (3910161307), direct conversion string ↔︎ named []byte/[]rune (6e3e380923), and rune (6ed3fa6553, Oct 2011; “alias for int32”, 012798a325).
Timeline.
- Go 1.0 — Done: 2008:
b2d9020242. 2009:01c2de0c15,8a70545b57,64c3fe05bf. 2010:d8b5d039cd,01eaf780a8,9b1507b050,a186b77b03,3910161307. 2011:1d687c742d,5fc3771b3a,6ed3fa6553,012798a325,cf9f380499. 2012:1f2445d27b. Left open: nothing noted.
Channels, select, maps and strings as built-in types
Span: Go 1.0 → Go 1.0 · Status at go1.17: compiler lowering to runtime calls as at go1.
Design. Chan and map became real types after the pointer-removal (dc7b2e98d2). Select: first implemented 2008-07 (b78676a49d, cb9b1038db, ece3e57c85) with select default (79fbbe37a7), moved into its own file with typecheck + walk (f7a867e1a6), special-case code for single-op blocking and non-blocking selects (5038792837), made faster by passing a pointer to the element so Scase is fixed-size and Select, Scases and SudoGs allocated together (6b2ec06587, uncontended 1080→558 ns), and “select functions are no longer special” (22853098a9). Range over a channel was made safe for multiple goroutines (b0543ddd8a). Maps: literals (182f91ffe0), nil maps (65bde087ae) and nil channels (3770b0e60c), multivalue map index (0282cc5e74), correct typecheck of x, ok (b7c4314ecb). Strings: representation changed April 2009 (3657061550), range over strings (a91a8042b4), x[y:] for strings (aa4c638b7b), string-index code generation inline (e48c0fb562), efficient x + y + z (f47d403cb4). Large channel element sizes are rejected (d116a32727) and data types are limited to 1GB (7e7008fa5e).
Timeline.
- Go 1.0 — Done: 2008:
cb9b1038db,79fbbe37a7. 2009:3657061550,a91a8042b4. 2010:f47d403cb4. 2011:5038792837,b0543ddd8a,65bde087ae,3770b0e60c,6b2ec06587. Left open: nothing noted.
Initialization and static data
Span: Go 1.0 → Go 1.0 · Status at go1.17: sinit.c static init as at go1 → continues as Static initialization and package init (1.18+)
Continues in: Static initialization, composite literals and init (Go 1.1 → Go 1.9)
Design. Package init order was added in July 2008 (fb3af53f4e, 90da636c15, f24f8ffae0); empty init functions are dropped (49f7494894); static initialization of slices (b91a043d02) was re-enabled (802e1a6104); recursive initialization is detected (e2613711aa) and diagnosed better (41861a8812); composite literals under init were moved from walk.c to sinit.c (0631d65dc5, 18f2e360a0); an optimisation of static initialization (33da9afc3e) with a read-only flag (d348971103, 103d756663); adjustable hash code in composite-literal typechecking to get rid of O(n^2) behaviour (b3dd22fecb, 8cb8ba14a5); init loops involving functions (896f0c61c8); stack allocation for the init function (1ea5bc7533).
Timeline.
- Go 1.0 — Done: 2008:
fb3af53f4e,1ea5bc7533. 2009:b91a043d02,e2613711aa,0631d65dc5. 2010:33da9afc3e,d348971103,b3dd22fecb. 2012:896f0c61c8. Left open: nothing noted.
Composite literals
Span: Go 1.0 → Go 1.0 · Status at go1.17: Go 1 rules; type elision for struct/array elements came later.
Continues in: Static initialization, composite literals and init (Go 1.1 → Go 1.9)
Design. Array literals (4539ced714), map literals (182f91ffe0), key:val extensions in array and struct literals (a016081f43), constant array keys (18840f5429), &Point{1, 2} rewrite as allocation (beee6915f8), static init of literals (above). The December 2011 commits implemented “composite literals as per Go 1” (7dc9d8c72b) and removed type elision in struct literals (5cb1c82d96); [...][...]int{{1,2,3}} was disallowed (bf899befdb), slicing array literals not allowed (7d15eda95d), duplicate key shown in error (5ab9d2befd). The October 2010 version (8ffc4ec5d0) implemented the spec of that time for element elision.
Timeline.
- Go 1.0 — Done: 2008-09:
4539ced714,182f91ffe0. 2009:a016081f43,18840f5429. 2010:8ffc4ec5d0. 2011:7dc9d8c72b,5cb1c82d96,bf899befdb. Left open: nothing noted.
Variadic functions (...)
Span: Go 1.0 → Go 1.0 · Status at go1.17: ...T as a property of func types.
Design. ... was a distinct, special type at first (74427c6346, 2fef4c7198); ... was double-checked (d122bb2193), allowed in method lists (101f499fa5), and then “add ... T, rework plain ...: no longer a distinct type; now a property of func types” (68796b0270, bea730d1f9); ... vs ...T crossing was an error “at least for now” (8bef7fdc39). Further ... changes and printing (75dd8fdb34, 1d315a8abd), an interim error rejecting valid code removed (2795b13156), and ... forbidden in type conversions (5b62ba14c4).
Timeline.
- Go 1.0 — Done: 2008:
74427c6346. 2009:d122bb2193. 2010:68796b0270,75dd8fdb34. 2011:2795b13156,5b62ba14c4. Left open: nothing noted.
Statement and flow rules
Span: Go 1.0 → Go 1.0 · Status at go1.17: Go 1 rules.
Design. Labels, break/continue/goto (33ee52727f), goto restriction that jumping over variable declarations or into blocks is an error (7f4c5ea7d8), terminating statement requirement “new return restriction” (c18d1a78a4), no implicit return in empty function body (0b2683d1ee), declared and not used (59914723df disabled initially), unused type-switch variable (aac144b120), write-only _ (5438be4541), error on redeclaration (54abac678a), nested function errors (371b77ad20).
Timeline.
- Go 1.0 — Done:
33ee52727f(2008),59914723df(2009),7f4c5ea7d8andc18d1a78a4(2011),1d3ca9236e(2012). Left open: the unused variable check was disabled when added (59914723df).
Diagnostics, error recovery and compiler plumbing
Span: Go 1.0 → Go 1.0 · Status at go1.17: C compiler diagnostics; messages later shared with types2.
Continues in: Diagnostics and error messages (Go 1.1 → Go 1.9)
Design. Large numbers of “bug NNN” fixes track the test/bugs directory (193eac7917, 1cb7f85d74 “0 expected bugs”). Error-reporting infrastructure: syntax-error recovery (1efa6a0544, 417a971f9a), helpful error rules (46f89d53c6, d7c1048771), line numbers from yacc lookahead (4656686cf5, 38df5ec58d), pretty types with 6g -t to disable (387c1bc31e), expression printer %#N (4152b925f9), errors sorted by line (2372408189), duplicate errors removed (529369e452, 6865cc0e8e), original expressions preserved (8133cb3565), a fatal-bug vs error distinction (9475cafa73), graceful seg-fault exit (b49561d884), cumulative error count (3208917d54), debug-flag docs (4b6cd239c5), and -L full paths (779dfea487). Build plumbing: builtin.c.boot generated from runtime.go (d06a79e31b, 8b3b1edc04), golden copy (ce7f345cd1), generated y.tab.[ch] checked in (d53cdd1775), Plan 9 yacc (920df48fb1), clang support (60a4b5e4db, 6998ea2982), and the move of portable code from 6g into gc (531f242f5d, 8e54729b5a, d30285a6f5, bac922c6e1, 5e792b6c09). Alignment: 20cfa4a568 rolls the receiver into input parameters, outputs in their own struct.
Timeline.
- Go 1.0 — Done: as above in each year; 2009-03-30: portable code moves into gc (
bac922c6e1,5e792b6c09). Left open: nothing noted.
Changes in this slice that are not part of a thread are listed on the release pages: 1.0
Compiler frontend (Go 1.1–1.9)
Reader: Claude Sonnet. Cites 1,297 of 1,507 commits in this slice; every non-noise commit is cited, plus 30 larger commits the noise filter had set aside, which a separate gap reader described. Read the design-heavy messages and subject lines. Some timeline items are plain hash lists.
Release digest for this slice
- Go 1.1 — C
cmd/gcmaintenance: method values, new return rules and shift/const rules; first escape-analysis flow tracking and inlining with locals; first race-detector instrumentation (041fc8bf96); mostly error-message and robustness fixes. - Go 1.2 — Three-index slices (
b4e92cee97), precise stack collection built but disabled (30ecb4cd05), large stack variables moved to heap, many inlining-export and message fixes. - Go 1.3 — Precise stacks enabled (
ecf700b5ee/53061193f1) with temporary-lifetime shortening and compact liveness bitmaps; mparith float-range fixes;-pack,-live. - Go 1.4 — Write barriers emitted (
fcb4cabba4), pointer-only interface data word (950ad4fa2b),for range x {}, escape-analysis soundness fix for stack copying,go:nosplit. - Go 1.5 — Compiler translated from C to Go (
cmd/internal/gc→cmd/compile),math/big-based constants, Node slimming, capture-by-value closures and closure-call transformation, stack allocation of strings/maps/interfaces, transitive inlining, flow of params to results in escape analysis. - Go 1.6 — Hand-written recursive-descent parser replaces yacc, compact binary export data under
-newexport, captureless-closure constants,go:noinline,-msan, massNodeList→slice cleanup. - Go 1.7 — Binary export data on by default (inlined bodies, positions,
-linkobj),NodeListremoved in favour ofNodes,Typeencapsulation and shrinking, itabs emitted by compiler, [dev.ssa] backend lands with frontend support, lexer rewrite. - Go 1.8 — New
syntaxpackage andnoderreplace the gc lexer/parser, textual export format removed,printervsfmt.Formatterformatting rewrite,go:notinheap/yeswritebarrierrec,mapassignreturns a slot pointer, first (reverted) alias implementation. - Go 1.9 — Type aliases implemented,
syntax.Posposition redesign with columns in errors, parse-time label/goto checking, concurrent parsing and initial backend concurrency (-c),cmd/compile/internal/typessplit,-importcfg, export-data version 5 with inlined-body positions.
The C-to-Go translation of the compiler (cmd/gc → cmd/internal/gc → cmd/compile/internal/gc)
Span: Go 1.5 → Go 1.9 · Status at go1.17: done in 1.5; the Go gc package then became the single frontend, later split into syntax, types, ssa and so on → continues as Old typechecker and IR node-model cleanup (1.18+)
- design doc Go 1.3+ Compiler Overhaul listed in Go: A Documentary
- design doc Go 1.5 Bootstrap Plan listed in Go: A Documentary
- design doc dev.cc branch plan cited in this thread's commits
- talk The move from C to Go in the toolchain. GopherFest 2015. Jun 10, 2015. listed in Go: A Documentary
Design. Until Go 1.4 the frontend was C in src/cmd/gc (lexer lex.c, yacc grammar go.y, typecheck.c, walk.c, esc.c, inl.c, sinit.c, …) shared by the per-arch code generators 5g/6g/8g. The Go 1.5 cycle converted it mechanically to Go. The runtime-C-removal branch work started it: fd2bc95d53 ([dev.cc]) changed cmd/gc to emit an -asmhdr header (struct field offsets and consts that cmd/dist used to scrape from the C compiler), to accept //go:cgo_xxx and //go:linkname directives, and to hard-code that interfaces contain only pointers. The translated code was committed as cmd/internal/gc (9c8c0e729d “reconvert to pick up bug fixes”, f6791da7ad for new6g etc.), still driven by a Go-ported yacc (cmd/yacc, go.y → generated y.go). Matthew Dempsky’s cmd/yacc work restored the “unexpected X, expecting Y” syntax-error style that Bison produced (e7d9f81645, 398bf9d5a0, 4f2a73011f, 82e1651a24), and a1bb3030c8 made yacc emit arrays instead of slices.
C idioms were then peeled off: Strlit/Zconv deleted (bed1f90d08), C hash tables replaced by Go maps (d0b59deb71), md5.go replaced by crypto/md5 (392434e1d0), Mpint/Mpflt re-based on a vendored math/big (e5a0d6399e, 4da157a723, 888767fcc4, 5bb89eb009; the vendored copy was refreshed repeatedly: 1e48683708, 65cd1ba682, f39cca94af, 646939c0e3, 5693bee0f1), Val.U became interface{} (13485be939, Node 424→392 bytes) and many int flags became bools (4a174ee4be, 5bf428ef80, 7885de55dc, d328756a69, 75883bae28, e7fe9f56ea). The package was then moved to cmd/compile/internal/gc with the binary renamed from 6g to compile (b3a508c03e usage names).
The second half of the effort was memory: Node dominated compiler memory, so func-only, name-only and param-only fields were split out into Node.Func, Node.Name, Node.Param (57279ba752 504→416 bytes, 76ec0ee53a, f4ab8203ba, 3ed9e4ca3c, bd8bb67357), and a long series moved fields into those substructures and deleted dead ones (ffef180f82, 66be1481df, 496ad0a286, 4fdd53680c, 71080fbb9e, 60e5f5bdff, 140ef3c59a, ac2bda1b00, 3007e953d0, 11322d45a1, 3c3019aa51, fd2154f906, bd4fff6358, da094f19f1, f1f0eda446, 3be7f28e82, 81d5810be9). cd9f417dbb documented which Node fields each Op uses.
Timeline.
- Go 1.5 — Done: [dev.cc]
fd2bc95d53prepares cmd/gc for runtime C removal (-asmhdr,//go:linkname,//go:cgo_*, pointer-only interface data word); the compiler is converted to Go ascmd/internal/gc(9c8c0e729d,6eaa095012expands theDBGmacro,d68f52aa43restores mkbuiltin,2bcfe8b935NULL→nil,8d44ede0dc“simplify code for c2go”); yacc ported with expecting-messages;math/bigvendored; Node slimmed; package becomescmd/compile/internal/gc(d00e7ad640-d panic=1to show compiler panics,7bcc6a1615-importmap,442959ec47fix builtin generation). Left open: the grammar is still yacc-generatedy.go;NodeListlinked lists and C-style global state persist. - Go 1.6 — Done: leftovers cleaned:
cb0e98b833“fix some C to Go translation leftovers”,dd42eff8fe/703bd83623/22452ac592/dab0dac01a/391cc54da8/bab01a0b4b/d5fe165ca0/a2119aca7d/b9dbb030d5convert ad-hocNodeListuses to[]*Node,8712e1867b/8937780c8a/e03c7896a7/9ac0fff70a/a20fbe8e18bool conversions,cd7d7382bband53d43cb556introduce types for decl contexts and untyped constant kinds;b569b87ca1replaces yacc (see parser thread). Left open:NodeListitself. - Go 1.7 — Done:
NodeListeliminated in favour ofNodes(see data-structure thread).
Parser: from yacc to a hand-written recursive-descent parser
Span: Go 1.1 → Go 1.8 · Status at go1.17: the gc-internal parser was removed in 1.8; the syntax package parser is the only parser → continues as The syntax package (parser, scanner, tree) (1.18+)
Continues in: The syntax package: parser, scanner, source reader, positions and error recovery (Go 1.10 → Go 1.17)
Earlier history: Lexer, grammar and statement syntax (semicolons, chan operators, conversions) (Go 1.0 → Go 1.0)
Design. In Go 1.1–1.4 the grammar was go.y with Bison (y.tab.c), custom error-message tables generated by bisonerrors (made compatible with Bison 2.7 e7ef3b6daf and 3.0 4eaf91a7a7), and a hand-written lexer (lex.c). Many error-message commits in these releases tweak the yacc actions (for example d00bd1d1f4 friendlier error for C-style if (i == 0), 9146ac14ee avoids parser stack overflow on a long else if chain, c956dcdc54 rejects parenthesized .(type)).
After the Go port (see previous thread) Robert Griesemer translated the grammar into a recursive-descent parser (parser.go) in b569b87ca1: “a translation of the yacc-based parser with adjustments”, yacc actions copied for correctness, enabled by default, -oldparser to revert; measured about 18% less parse time per file and about 3% less time compiling cmd/compile. Follow-ups made syntax-error handling and recovery match the old messages (c8bc7f1abd, ac658a83c2, 0133d24c94, 64cd86798b, aad18b849b, 656a732a21, 5500d46914 for &(T{}), 1a111ea2c7 for <-x vs <-chan), and b5fe07710f deleted go.y and y.go (6025 lines removed). In 1.7 the lexer was rebuilt around bufio.Reader directly (5aa5db7593, 539aa05a64 always use getr, 8dd2ce2b98 factor out literal lexing, aa5b44aeab set nlsemi where the token is identified, 071e43a958 keywords no longer Syms, 3c0fae5306 pragmas tracked in the lexer, 8fd7c11d59, e0fa809f4c rationalize lineno vs lexlineno, a5b7a8d6dd error sorting, 49d1e30710 binary-expression parsing shared with go/parser, f5f8b38462 removes prectab).
The parallel track was the new cmd/compile/internal/syntax package (see next thread). 2ff463948c introduced noder.go which converts the syntax AST into gc Nodes (hidden behind -newparser); adda7ad295 made it the default on 2016-08-16, and 57df2f802f removed the old lexer/parser in 1.8.
Timeline.
- Go 1.1 — Done: yacc era maintenance:
6ce4930365accepts an initial BOM,8f3b703323complains about invalid whitespace chars,ffc742b658accepts new conversion syntax,27d17255db1.2 inserts\nat end of every input file,6592456feb. Left open: grammar tied to Bison. - Go 1.2 — Done:
b4e92cee97and8cd6341cf8add full slice expressionsx[i:j:k]togo.y(12 files; commit says “experimental … may not be included in the release”, then allowed in), see language thread;d00bd1d1f4C-style-if message. Left open: nothing noted. - Go 1.4 — Done: user-visible
8d504c4e97for range x {;2565b5c060drops the parenthesization restriction for receiver types. - Go 1.5 — Done: yacc ported to Go, expecting-messages restored (
e7d9f81645), lexer allocation reduction9f4c25e223. Left open: hand-written parser not yet. - Go 1.6 — Done:
b569b87ca1recursive-descent parser (default),b5fe07710fyacc removed,247959d9b8rejects identifiers beginning with a non-ASCII digit,e18cd34c76correct line for:=,fe762b6466parenthesized go/defer message. Left open: gc’s parser still buildsNodes directly, not a separate AST. - Go 1.7 — Done: lexer/parser simplifications listed above;
3a11c8d319,e4571d33ac,9f301643bd/bb3b10214d(parameter parsing without OKEY nodes),135109d241. Left open: new AST parser exists only as an unused package. - Go 1.8 — Done:
2ff463948c+adda7ad295noder on by default;57df2f802fold lexer/parser removed;2d4d22af7eparser.go remnants moved into noder.go;ee161e8591pragmas handled immediately;70544c91ff“match old parser errors and line numbers”;117793624bsyntax exposes extra info for gc;2d136ae82e//line filename:linewith ‘:’ in file name;7a26d9fced,322436b78c,60a9bf9f95Read/Parse error handling.
The syntax package, position representation and parse-time checks
Span: Go 1.8 → Go 1.9 · Status at go1.17: still the design (syntax tree with Pos and PosBase; branch checking in the parser) → continues as The syntax package (parser, scanner, tree) (1.18+)
Continues in: The syntax package: parser, scanner, source reader, positions and error recovery (Go 1.10 → Go 1.17)
Design. c8683ff797 (2016-03-04, in go1.8) added cmd/compile/internal/syntax: “fast Go syntax trees”: nodes, scanner, parser and printers, building trees for the whole std lib at about 1.8M lines/s and 282 MB allocated for 1.07M lines. Its error messages were aligned with the old parser (70544c91ff). In the 1.9 cycle the representation of positions was redesigned on the [dev.inline] branch: 8d20b25779 introduced a general syntax.Pos plus PosBase (line-directive aware), 32bf2829a1 processed //line pragmas in the scanner, 24597c080b introduced cmd/internal/src.Pos, 4808fc4443 replaced src.Pos/LineHist with syntax.Pos throughout (the commit notes that compiler data structures grew, with Template compile up by about 9.5% and Compiler by about 4% in compilebench), and 33c036867f removed LineHist. The column unit was set to bytes (f3b56de4d2, 1f9f0ea32b starts columns at 1), and 5267ac2732 removed the gcCompat flag and set node positions “in a principled way”: the position of an Operation is that of the operator, so a + b + c has different positions for the two additions; this changed export data and pcline tables so it did not pass toolstash. e0329248d5 added positions for { and } (1.9% more node memory), b5f81eae17 replaced inlined statement lists with BlockStmt (+0.4%), f37ee0f33b records the column at function end, d1f5e5f482 “always construct a correct syntax tree”, and 2a5cf48f91 made error messages print line:col (byte offsets; -C flag to disable and planned for removal).
Two compile-time structural changes rode on the syntax tree. Files are parsed concurrently (ec63158d71, with b90aed020d reorganizing file parsing and e48919bcde splitting mkpackage). Label and goto checking, first a separate checkcfg.go pass over Nodes (c03e75e539, 299 lines, so that SSA generation can skip dead code), was moved into the parser as syntax/branches.go (912a638b0c, with a CheckBranches mode flag so tests that only care about syntax can switch it off; also fixed the issue 8042 “jumps over declaration” reporting), with bb70f517e9 reporting the innermost block for gotos jumping into blocks and a50962131a computing BranchStmt.Target. style cleanups aside, 912a638b0c also removes the dependency on the symbol dclstack.
Syntax error quality got a long tail of work in 1.9: 9799622f09 distinguishes ; from newline in messages, 3c22e5ca27/53c6ac5419/f823d30514/efb3cab960 improve errors for malformed if/for/switch headers and var decls in init clauses, 1693e7b6f2 character literals, d390283ff4 compiler directives must start at the beginning of a line, 5e954047bc/ee2f5fafd8/b5e1ae46ad tolerance and crash fixes, 422c7fea70 rejects declarations in a for post statement.
Timeline.
- Go 1.8 — Done:
c8683ff797package added; used bynoderfrom2ff463948c(defaultadda7ad295);32db3f2756support for alias declarations in the syntax package (see alias thread);cfc0d6d884. Left open: positions still based on the gc LineHist/linenomodel. - Go 1.9 — Done: Pos redesign (
8d20b25779,32bf2829a1,e97c8a592f,3d5df64b3f,4b8895e2dd,24597c080b,4808fc4443,f3b56de4d2,2d429f01bd), principled node positions (5267ac2732), columns in errors (2a5cf48f91), concurrent parsing (ec63158d71), parse-time branch checking (912a638b0c), brace positions (e0329248d5);d10b50dc34print positions in tree dump. Left open: the-Cflag is expected to be removed eventually (2a5cf48f91); the gcNodetree still exists as a second representation (“Phase 3 is planned for eventual removal”,756b9ce3a5).
Binary export data and the object-file split
Span: Go 1.1 → Go 1.9 · Status at go1.17: binary export format (v1..v5 “bexport”/“bimport”) plus inlined bodies; later replaced by the indexed format and then unified IR → continues as Unified IR: one serialization for noding, stenciling, inlining and export (1.18+)
Continues in: Indexed export format and the export-data lifecycle (Go 1.10 → Go 1.17)
Earlier history: Export/import data format (Go 1.0 → Go 1.0)
- tracking issue #13241 cmd/compile: switch to new export format referenced by 2 of this thread's commits
Design. Export data in Go 1.1–1.5 was text: a $$ section of Go-like declarations written by export.c, parsed by the ordinary lexer/parser. Inlinable bodies were exported as source-like fragments, which made inlining bugs show up as export-data bugs: 8d95245d0d, 761830f481, fc7b75f216, 78f5b616fc, 62891fb811, 20ebee2c31 and c1fc8d5296 all repair missing or corrupted body exports; constants were exported in hexadecimal (fbaf59bf1e) and later without the original expression (f09887cdce).
Go 1.6 added ae2f54a771, Robert Griesemer’s compact binary export format (bexport.go/bimport.go) under -newexport, importable in “mixed mode” with the textual format; export sizes were about 26–30% of the textual size for std packages in the commit’s table. It initially lacked inlined function bodies. Binary-escaping (e6ccfc1ad1: no $ bytes inside) and -importmap before unsafe handling (a8fc547f78) followed. In 1.7 4598382724 exported and imported all bodies without hooking them up, a9ea36afbb completed body export (three sections: platform-independent objects, objects pulled in by inlined bodies, and the bodies themselves; “completely compiler-specific and easily changeable”), compiler-specific flags moved to a compiler-specific section (b1851a3c11, 7d0d122247), position info was added (5c593a3227 “first cut”, delta-encoded line numbers and canonicalised strings, 14% size increase; e8d4ffb766 fixed the node used; 6c11e2710e delta-encoded filenames, 15–25% savings on some packages; 889c0a66fc disabled position export “for now”), and 7538b1db8e switched to binary by default on 2016-04-15, quoting ~65% smaller export data, at least 62% faster writes and 37% faster reads, with -newexport=0 as the escape hatch. feb6131b1a added -linkobj to write the object in two parts (export data for compiles, everything else for linking) and moved two bits the linker needed into the object header proper.
Go 1.8 removed the textual format (b4e9f70412, f50ced6d73, 074d6a649c), then reintroduced version-0 binary reading (c85b77c22b) and added a version byte with graceful failure on skew (5a6f973565), and exported aliases (03d81b5ed9, later revert of user visibility 8e970536df). 1.9 added linknames to export data (e3efdffacd: lets -l=4 inline functions that contain linknamed calls), position info in inlined bodies (9fd359a29a: +8–20% export size, accurate line numbers for cross-package inlining), type-alias format (49de5f0351: embedded-field name modes), interface embedding information (ee272bbf36), a cheaper position encoding with a -64 new-file marker and /-component paths, bumping the version to 5 (a6b16e0024: about 8% smaller), ad8c17b703 not exporting dead code in inlinable functions, and ff0748670c/2123a6c644 fixes for exported bodies and line-directive-relative positions.
Timeline.
- Go 1.1 — Done: inlining makes export data carry bodies, with a stream of bug fixes (
8d95245d0d,761830f481,fc7b75f216,9e66ee4562,b0bb6f8cee,a9f1569e7bBOM escaping,a45777fe99don’t export embedded builtins,561edbd63cno useless private symbols,8fff2525cb,fbaf59bf1e). Left open: export is source text. - Go 1.2 — Done:
78f5b616fc,62891fb811,20ebee2c31,c1fc8d5296,a85cfbd433(tag builtin error/byte/rune so they are not exported),8d6bc666fb(qualified embedded fields with owner package),a9e119ac70. Left open: nothing noted. - Go 1.3 — Done:
20137eb4b9preserve qualified names of unexported methods;b022334029-packflag. - Go 1.5 — Done:
f09887cdceno original expression in exported constants;7c3eeda66fgo.builtinpackage prefix;bed481d683. - Go 1.6 — Done: user-visible
ae2f54a771binary format behind-newexport,3d3bc88bb5export list as slice,e6ccfc1ad1,92ba69d216,91c8e5f80b,d37d76af43,ab5d2bf92f(don’t export Note field in bodies),feb2a5d610. Left open: no inline bodies in binary form; not default. - Go 1.7 — Done:
4598382724,a9ea36afbb,5c593a3227,7538b1db8e(default),feb6131b1a(-linkobj),a5cd53a9fdinvalid types/constants,d78c84c419sorted imports for canonical obj files,6e4a8615f6deterministic output viaAbsFileLine,eb4d1be285keep variable numbering for inlinable exported funcs;80e9a7f079all-or-no named params,8650c23034verify imported types after full import,87a2ae1fa2,ef62f641c3,21d781070cone format for builtin calls,054a721dcasafemode bit from package header,30282b091dlabels/goto/fallthrough import,bbd1dcdf7d,575a871662//go:nointerface,15f7a66f36blank names,1402e522c6load builtin export data once,d930d69fd9,113c4d2581/7d3a40978arefactor import/export parsing,7d80291c4c,f8e41f6f59,699a2ba137,338a891e79,3e40f13cf3,e7524d51fdremoval of lexer-IO-state globals (the “Io” type). Left open: position export disabled “for now” (889c0a66fc) and parameter numbering kept (0b8c0767d0). - Go 1.8 — Done:
b4e9f70412textual removed;c85b77c22b/5a6f973565version handling;b11c79fd07;03d81b5ed9alias import/export;bcc0247331avoid double export of aliased objects;6394eb378eblank struct fields’ package;14efaa0dc3qualify unexported fields of unnamed types;9aea69d6dc;595cebb055;c7b9bd7456self-recursive interfaces;f50ced6d73. - Go 1.9 — Done:
e3efdffacd,9fd359a29a,49de5f0351,ee272bbf36,a6b16e0024(v5),ad8c17b703,2123a6c644,a680a85ea7simplify export info,ff0748670c. Left open: the format is still a sequential stream;ebcdda4732andeb86abaa36improve importer failure modes only.
Inlining
Span: Go 1.1 → Go 1.9 · Status at go1.17: the Node-based inliner with budget 80 survives, extended later (mid-stack, then PGO) → continues as Compile-time performance, concurrency and the self-PGO’d compiler (1.18+)
Continues in: Inlining: budget, mid-stack inlining, closures, and what became inlinable (Go 1.10 → Go 1.17) · Inlining-related frontend work: export of bodies, type switches, closures, devirtualization (Go 1.10 → Go 1.17)
Earlier history: Inlining (Go 1.0 → Go 1.0)
Design. Inlining (inl.c/inl.go) works on the typechecked AST: ishairy decides eligibility by a node-count budget, the callee body is deep-copied (treecopy/mkinlcall) with parameters turned into assignments to fresh locals, and the body is exported so importing packages can inline too. Go 1.1 widened it to functions with local variables (530147e870, with cb856adea9 annotating locals with unique ids so copies get distinct names, ae5e791ed2 saving the local var list before inlining, dfdfba14b9 letting temporaries from inlining be registerized), fixed a series of inlining-related miscompiles (b6ea905ed9 receive operator, a4682348c2 complex literals, 319131f295 composite literals in if, 9aef20e823 embedded builtins, 49da9a8e44 unnamed structs with embedded fields). Go 1.5 added transitive inlining (77ccb16eb1: calls that are themselves inlined away no longer block inlining of the caller, together with a larger budget so heapBits.next inlines; html/template compile time −12%). Go 1.7 allowed bodies that declare constants (fc6bcdee79) and switch (e41f527f4d, with a follow-up ac8d97b679), and Go 1.8 added -m-style explanation of why a function is not inlined (e4cae432d6) and stopped considering recursive calls (376d9665a8). Go 1.9 stopped counting statically dead if arms toward the budget (566e72d0ce, newly inlinable: bits.OnesCount, (*Float).Sign, etc.), then removed dead if code once after typechecking instead (dffe5ac9f2, with the caveat that labelled/goto code is kept), fixed names of inlined methods from other packages (83843b1610) and positions of inlined bodies via export data (9fd359a29a).
Timeline.
- Go 1.1 — Done:
530147e870,cb856adea9,dfdfba14b9,ae5e791ed21.2 (1.2), fixesb6ea905ed9,a4682348c2,319131f295,9aef20e823;8d95245d0dexport data for inlined local variables. Left open: inlined bodies that contain calls are refused soruntime.Callercannot observe inlining. - Go 1.2 — Done:
49da9a8e44,ae5e791ed2. - Go 1.5 — Done:
77ccb16eb1transitive inlining;2e4b659954embedded field in inlined function;ec0ebc2281non-local vars inlined into wrappers treated as escaping;4224d81faeinlinex := y.(*T). - Go 1.7 — Done:
fc6bcdee79,e41f527f4d,ac8d97b679,a9ea36afbbmakes imported bodies actually available;17db07f9b5don’t discard empty inlinable functions. - Go 1.8 — Done:
e4cae432d6,376d9665a8;c7b9bd7456. - Go 1.9 — Done:
566e72d0ce,dffe5ac9f2,83843b1610,9fd359a29a. Left open: the “unexported funcs are never inlinable across -l=4 with linknames” issue fixed bye3efdffacd; inlining remains leaf-only (calls block inlining).
Escape analysis and stack allocation
Span: Go 1.1 → Go 1.9 · Status at go1.17: the 2012–2015 flow-graph analysis (esc.go) with param tags remains; rewritten in later releases → continues as Old typechecker and IR node-model cleanup (1.18+)
Continues in: Escape analysis: the esc.go fixes, the escape.go rewrite, and the move to package escape (Go 1.10 → Go 1.17)
Earlier history: Escape analysis and heap allocation (Go 1.0 → Go 1.0)
- background Go Escape Analysis Flaws listed in Go: A Documentary
Design. Escape analysis (esc.c, later esc.go) assigns each Node a “loop depth” and tracks whether addresses flow to the heap, to a longer-lived scope, or to results, producing per-function parameter tags used at call sites. Go 1.1 added tracking of the flow from input to output parameters (976ca1a47d step 0 synthesizes names for anonymous results, 75692424d2/507fcf37d2 the analysis, 572d984eaa, 71282131a1 fixes), applied results to closures (9fe60801ae: avoids allocating closures used as “macros”, defer args or Walk idioms; BenchmarkCallClosure1 119→7 ns), handled method values (38e9b0773d) and added a noescape marker for extern funcs (fd178d6a7e). Go 1.2 moved big stack variables to the heap (1f4d58ad5d) and fixed wrapper escape analysis (7cfa8310c7). Go 1.4 made it run always, even in -N mode (00d2f916ad) and fe3c913443 fixed an unsoundness with functions returning an indirection of a parameter, which mattered once stacks were copied (heap objects pointing at stack variables would not be updated). The fix tags such parameters as “content escapes” without recording which result; a more precise mapping was explicitly left out as a trade-off (more precise means fewer heap allocations).
Go 1.5 improved flow precision (7fbb1b36c3, David Chase): the per-function summary records outK = paramJ, outK = *paramJ, heap = paramJ, heap = *paramJ in a tunable number of bits (2 chosen), “level” split into three parts to model address-of cancelling indirection; 420 fewer heap allocation sites compiling std and a 15% reduction in allocations performed by the compiler on html/template. Dmitry Vyukov’s series then used escape results to stack-allocate more: 32-byte buffers for non-escaping []byte→string and concatenation (e6fac08146), []byte(str) conversions (9568126f35), string(rune) (4ce4d8b2c4), non-escaping make(map) with hmap and one bucket on the stack (b3be360f16, 75 std cases, NewEmptyMap 124→55.7 ns), interface backing storage (2270133981), &T{} like new(T) (2af3cbe308, 1.1), and no copy for range []byte(str) (71be013842). Go 1.5 also ran escape analysis after method-wrapper generation (5be61b18d4); Go 1.7 eliminated PPARAMREF (20803b845f), changed liveness handling of heap-escaped params with the new PAUTOHEAP pseudo-class (b6dc3e6f66), and stopped leaking dottype expressions (5c5e8d4105). Go 1.9 stopped updating outer variables after capturevars completes (61336b78c1) to make results deterministic under concurrent compilation.
Timeline.
- Go 1.1 — Done:
976ca1a47d,75692424d2,507fcf37d2,572d984eaa,71282131a1,9fe60801ae,38e9b0773d,fd178d6a7e,2af3cbe308. Left open: only a single bit of flow info per param. - Go 1.2 — Done:
1f4d58ad5d,7cfa8310c7. - Go 1.4 — Done:
fe3c913443,00d2f916ad,a3416cf5cd-adjacent write-barrier work lives in the GC thread. Left open: result mapping is not recorded; imprecise. - Go 1.5 — Done:
7fbb1b36c3,e6fac08146,b3be360f16,2270133981,9568126f35,4ce4d8b2c4,71be013842,5be61b18d4,3bf005cea3. Left open: “ought to yield better results with a more competent escape analysis algorithm” (7fbb1b36c3). - Go 1.7 — Done:
20803b845f,b6dc3e6f66,fb2af2b35b,7e88826a69(escape reads function decls instead of OTFUNC node slices). - Go 1.9 — Done:
61336b78c1,ecc6a81617(walkexpr must not modify ONAME/OLITERAL/OTYPE nodes, for concurrency).
Closures, method values and variable capture
Span: Go 1.1 → Go 1.7 · Status at go1.17: still the design (capture by value when never reassigned and not address-taken; closure call → function call) → continues as Old typechecker and IR node-model cleanup (1.18+)
Earlier history: Closures (Go 1.0 → Go 1.0)
Design. Closures are OCLOSURE nodes whose body becomes a hidden top-level function (25922c0658 introduced hidden closure functions earlier in Go 1.1). Method values x.M (d3c758d7d2, 1.1) are compiled as closures over the receiver (176 lines in closure.c). Go 1.5’s Dmitry Vyukov work changed the capture model in two steps. 0e80b2e082 “capture variables by value”: the spec says capture by reference, but if a captured variable is neither address-taken nor ever assigned after capture it is effectively const, so the closure copies it; about 80% of std captures became value captures, with zero heap promotion of PPARAM to PPARAMREF (BenchmarkCompressedZipGarbage allocs 153→126). Range variables and outputs needed special-casing (eaa872009d, 3bf005cea3). c4ee44b7b9 transforms direct closure calls (func(){...}(), go func(){}(), defer func(){}()) into plain calls with closed variables passed as arguments, so no heap context is needed (CreateGoroutinesCapture 6→2 allocs); it split the work into capturevars (decides capture mode, needed before escape analysis) and a new transformclosure pass run just before order/walk, and the call-site rewrite happens in walk of OCALLFUNC(OCLOSURE). Closure names became simpler (3a0fbfab57), called closures get captured args prepended to their params (731dcdae6d), and Go 1.6 made captureless closures constants (4f97ec0866): they can initialise globals at link time, which removed fmt.ssFree’s reachability from fmt.init and shrank hello-world by about 4%. In Go 1.7, PPARAMREF and Func.Outer were deleted (20803b845f, 93369001c7), Func.Cvars became a Nodes (52d9479e3b, 922ce58de0) and transformclosure was simplified (c7917de0bb); b64f549ba9 added -d closure and detection of leaking closures in the runtime.
Timeline.
- Go 1.1 — Done: user-visible
d3c758d7d2method values (also20e05303fevariadic flag,38e9b0773descape,a9e119ac701.2 unnamed interface receiver in 1.2),25922c0658,9fe60801ae,ba0dd1f139missing-return line in closures. Left open: all captures by reference. - Go 1.2 — Done:
0d0d57ccfe(_initializers in closures),280c8b90e2unique method names for function-scoped types. - Go 1.4 — Done:
6c0bcb18631.3 (method value closures on nacl, 1.3). - Go 1.5 — Done:
0e80b2e082,eaa872009d,c4ee44b7b9,3a0fbfab57,731dcdae6d,27edd7209e(PAUTO capture variables on non-amd64). Left open: nothing noted. - Go 1.6 — Done:
4f97ec0866. - Go 1.7 — Done:
20803b845f,93369001c7,b64f549ba9,e0f986bf26(function literal name collision with “glob”),c7917de0bb. - Go 1.9 — Done:
61336b78c1.
Language changes and rules as implemented in the compiler
Span: Go 1.1 → Go 1.9 · Status at go1.17: each rule is part of the language; implementation later moved to types2 → continues as Frontend support for new language features and spec changes (1.18+)
Paths not taken: Quaternion types (never landed)
Continues in: Language version gating (-lang) and language changes implemented in the frontend (Go 1.12 → Go 1.17)
Design. The gc typechecker (typecheck.c, then typecheck.go) implemented each spec change as a mix of grammar edits, typecheck rules and walk lowering. The log shows these language changes (the user-visible bullets in the timeline):
Go 1.1 spec changes. Method values (d3c758d7d2). “New return requirements”: a function with results must end in a terminating statement, implemented in typecheck by ecab408c42 (145 new lines, removing a walk check). The revised rule for shifts in equality comparisons (465ff4cfc0), shift defaultlit in interface context (1947960a6f), untyped complex inference (861aa4698a), integer-valued idealized floats allowed as indices (88b98ff791), bool losing idealness under logical operators (5188c0b59c), rejection of selectors on blank (b65acaeab2), methods on non-locals (7c3694c4de), division by constant zero (ba05a43608), “latest rules for checking make sizes” (f02067a99a), and bounds checks of constant indices/slices in typecheck (85d60a727c, 72bf3bc176, e3977f0d3a). ced8004a00 rejects (**T).Method expressions.
Go 1.2. Three-index slices x[i:j:k] (b4e92cee97, “Design doc golang.org/s/go12slice … experimental”; 8cd6341cf8 lets it into the release), including escape/racewalk/fmt support and per-arch cgen.
Go 1.3. Zero-length arrays are not comparable (502958ffa6), duplicate-key check for maps with interface{} keys (3072df5c1d, fixed again by ec38c6f5e3), fallthrough misuse rejected (96678f9dc0), float rounding and exponent range fixes (cb50277510, a43673cf8a, 60be4a2450, 1be479df92).
Go 1.4. for range x {} (8d504c4e97), pointer constants disallowed (7f40e5e6e5), short variable declarations with duplicate symbols prohibited (55df81d37f), blank methods in interfaces disallowed (db4dad7fd7), **T method calls disallowed (93fcb92257), initialization cycles through method values detected (fe8f799ef7), bounds error for out-of-range constant string slices (870f4e190c).
Go 1.5. Logical operators on untyped operands produce untyped bool (5cc29ab95e), method selectors no longer auto-dereference a named pointer type (b59dd94f33), map index expressions allowed in for range (b581ca5956), map literals may omit the key type (73d109c509), str[i] has type byte (c735064cde), unsafe.Pointer constants may only be converted to uintptr (a3dfcf51c6), detection of bad append(f()) (3f209abb29), goto validation ignores type declarations (5726af54eb), p-notation floats rejected in source (596bb76248), and an error if only one argument to complex (cb1897a58c).
Go 1.6. Rejections and fixes to constant typing: 336c998291 slice/map/func comparison against converted nil, be20948e27 bool(true) is a constant expression, 27691fa467 !typedbool is typed (so const _ bool = !mybool(true) is no longer accepted), c488548967 labels with package names, d6a203ecab const and label names may match, 67722fea50 invalid unsafe.Sizeof([0]byte{}[0]).
Go 1.7. 49dad0f571 arbitrarily deep embedded fields (the 1.7 compiler removed the limit), 75b886ab79 rejects embedded unsafe.Pointer, 3eaa304629 ignore receiver name when finding duplicate methods, f5423a63df a dot expression cannot be a struct literal key, e48a2958d1 empty and absent struct tags are identical, c97ddf9c10/f229e46783 assignment error fixes (“cannot assign to struct field in map”).
Go 1.8. 8895a99c9f typed non-integer constants as len/cap args to make are disallowed, 7f1bc53379 only integer constant keys in array literals, 39055700b1 ignore struct tags when converting between structs (the Go 1.8 spec change), 936ae27b9c untyped array bounds representable as integers are valid, fc5df089da constant comparison fix.
Go 1.9. 660200528a no implicit dereference of pointer-to-array for real/imag, 829adf5047 real/imag of untyped constants, c9446398e8 composite-literal structs with _ fields, 422c7fea70 no declarations in for post, 5f5d882f5c bad pragma combinations earlier, 10a200e560 division by complex zero.
Type aliases are in their own thread.
Timeline.
- Go 1.1 — Done: user-visible
d3c758d7d2method values;ecab408c42return requirements;465ff4cfc0,1947960a6f,88b98ff791,5188c0b59c,861aa4698a,401e0fea3a(rejectcomplexcalls with mismatched args),f02067a99a,ba05a43608,ced8004a00,c956dcdc54,ffc742b658(new conversion syntax),04098d88fa(forward declaration in pure Go package is an error),3aed92f811(var/type/const named init),87c35d8df1(qualified names as literal keys),6cbf35c172(init order with method calls),85ce3c7241. Left open: nothing noted. - Go 1.2 — Done: user-visible
b4e92cee97,8cd6341cf8;880d869764init order for top-level blank vars;66c8935f73initialization loop detection;933d7129c0;903c2fda18(_ = nil). - Go 1.3 — Done: user-visible
502958ffa6,3072df5c1d,ec38c6f5e3,96678f9dc0,f3ecb298ad(builtin calls inlen(fixed array)constants),e5f01aee04(don’t nop-convert equivalent but different interface types),a069cf048dunnamed vs blank-named results. - Go 1.4 — Done: user-visible
8d504c4e97,7f40e5e6e5,55df81d37f,db4dad7fd7,93fcb92257,fe8f799ef7,870f4e190c,2565b5c060. - Go 1.5 — Done: user-visible
5cc29ab95e,b59dd94f33,b581ca5956,73d109c509,c735064cde,a3dfcf51c6,3f209abb29,596bb76248,cb1897a58c,5726af54eb. - Go 1.6 — Done: user-visible
336c998291,be20948e27,27691fa467,c488548967,d6a203ecab,67722fea50,8a34cf7ee0(no blank methods on builtins),b60c8203ea. - Go 1.7 — Done: user-visible
49dad0f571,75b886ab79,3eaa304629,f5423a63df,e48a2958d1. - Go 1.8 — Done: user-visible
39055700b1,8895a99c9f,7f1bc53379,936ae27b9c. - Go 1.9 — Done: user-visible
660200528a,829adf5047,c9446398e8,422c7fea70,10a200e560,5f5d882f5c, type aliases (see next thread).
Type aliases (the => experiment and type A = B)
Span: Go 1.8 → Go 1.9 · Status at go1.17: type A = B is the language feature; the first implementation was reverted in 1.8 and redone on [dev.typealias] in 1.9 → continues as Generic type aliases and Alias type nodes (1.18+)
- design doc Proposal: Type Aliases Russ Cox, Robert Griesemer, December 16, 2016 · linked from #18130
- proposal #18130 all: support gradual code repair while moving a type between packages referenced by 7 of this thread's commits
- design doc Proposal: Alias declarations for Go Robert Griesemer & Rob Pike, July 18, 2016 · linked from #16339
- proposal #16339 Proposal: Alias declarations for Go referenced by 3 of this thread's commits
- talk Lightning Talk: Alias Declarations for Gom: A proposal. GopherCon 2016. Oct 9, 2016. listed in Go: A Documentary
- tracking issue #17487 cmd/compile: support alias referenced by 2 of this thread's commits
- background Russ Cox. Codebase Refactoring (with help from Go). listed in Go: A Documentary
Design. The first attempt (Go 1.8 cycle) added alias declarations to the new syntax package (32db3f2756) and package-level aliases to the compiler (1b0cf430dd, “requires -newparser=1”, then c0e2318f7c simplified parsing), using the => notation (89632aa183: “type T = p.T” disallowed, must use =>; 50f66fbb66 disallows init as alias) with import/export of alias declarations (03d81b5ed9, bcc0247331 avoiding double export). On 2016-11-04 8e970536df reverted the user-visible parts (“Decision to back out current alias implementation”), leaving import/export code in place. The second attempt came after the decision to use = in the spec: 3e11940437 ([dev.typealias]) recognized the syntax but complained, 49de5f0351 defined a tentative export/import format (embedded fields get three modes: name equals type name and exported, same but unexported, @+field name when different), f011e0c6c3 made related fixes in compiler, go/types and go/importer, b2386dffa1 type-checked alias declarations (known issues listed in the message: duplicate method declarations through alias names not detected, cycle error messages, byte/rune setup), 5c160b28ba improved cycle errors, de2e5459ae declares methods after resolving the receiver type, 9ecc3ee252 avoids false-positive cycles from aliases (fixes #18640) and 5d92916770 changed Func.Shortname to *Sym.
Timeline.
- Go 1.8 — Done:
32db3f2756,1b0cf430dd,c0e2318f7c,89632aa183,50f66fbb66,03d81b5ed9,bcc0247331,8e970536df(revert of user-visible parts). Left open: “Leaving import/export related code in place for now”. - Go 1.9 — Done: user-visible
3e11940437,49de5f0351,f011e0c6c3,b2386dffa1,5c160b28ba,de2e5459ae,9ecc3ee252,5d92916770. Left open:b2386dffa1lists “needs many more tests”, undetected duplicate methods and byte/rune alias setup.
Constant arithmetic, Mpint/Mpflt and floating-point constants
Span: Go 1.1 → Go 1.9 · Status at go1.17: big.Int/big.Float-based constants (Mpint, Mpflt) → continues as Old typechecker and IR node-model cleanup (1.18+)
Continues in: Constants: Go 2 number literals, evconst, untyped conversion and go/constant (Go 1.11 → Go 1.17)
Earlier history: Constants and multi-precision arithmetic (Go 1.0 → Go 1.0)
Design. Constants were represented by Val with arbitrary-precision Mpint (fixed array of limbs, 464 bits then 512) and Mpflt (hand-written multi-precision floats in mparith), plus Mpcplx. In Go 1.1–1.4 work was bug fixing: complex literals (15bc7ab957), fixing inverted comparison order in mpcmpfltc (f85ba7d50a), exponent overflow and underflow checks (cb50277510), rounding of large negative exponents toward zero (a43673cf8a), float32 conversion and printing (60be4a2450, 1be479df92), ovf in mpaddxx message (397f129daf), isgoconst crash (32dffef098). Go 1.5 replaced the limb arithmetic: Mpint on math/big.Int (888767fcc4), Mpflt on big.Float (5bb89eb009, via a vendored cmd/internal/gc/big because the real math/big had no Float yet), after which a51d5f27e8 set multi-precision to 512 bits and 1122836b5f rejected huge exponents without math/big; 85de30e72f (1.6) allowed huge right shifts and 715f63778d avoided converting huge floats to integers; 76285213b8/79a3b561b5 removed -0 special handling (“there are no -0 floating-point constants”). Go 1.7 turned Mpint/Mpflt functions into methods (d3253876f2, 0659cf6911) and added special-casing for comparisons against zero (07749aef98), and 97360096e5 replaced Ctype switches with type switches. 1.8 and 1.9 refined diagnostics: e99dafc4a8 reworked the “truncated to int” messages (“integer too large” instead of overflow wording; SetFloat returns bool), 871300308a, bcf2d74ce8 large exponents, 2e60882fc7 no duplicate error on ideal→float overflow, ff3a4ef7ec less reliance on Mpint internals, 2acd3fa8f1 fewer switch cases in evconst, b83a916f71 iface == iface constant evaluation respects !=.
Timeline.
- Go 1.1 — Done:
8931306389reject non-Go constants,0184081eb9small TPTR64 as integer constants,a85fce282esimplify defaultlit,bf59aafddc,08918ba438. - Go 1.3 — Done:
cb50277510,a43673cf8a,f85ba7d50a,60be4a2450,1be479df92,74ce581b06,15bc7ab957,833dae6d26. - Go 1.5 — Done:
888767fcc4,5bb89eb009,e5a0d6399e,4da157a723,a51d5f27e8,1122836b5f,bb418a59f8(approximate float formatting in errors),13485be939,71080fbb9e,99475dfb59(spurious div-zero errors). - Go 1.6 — Done:
85de30e72f,c396c047c6(remove restriction on float exponent parsing),76285213b8,79a3b561b5,ddbc802b07,2c11164db5,715f63778d,732e2cd746,50fa646776. - Go 1.7 — Done:
d3253876f2,07749aef98,97360096e5,35dd2ed58d(rename mparith files),f32161daf8(one new Node per defaultlit: Unicode compile alloc −5.8%).
Static initialization, composite literals and init
Span: Go 1.1 → Go 1.9 · Status at go1.17: sinit.go model with static data, dynamic init and oaslit; extended later with staticinit → continues as Static initialization and package init (1.18+)
Continues in: Package initialization order, static initialisation and init functions (Go 1.10 → Go 1.17)
Earlier history: Initialization and static data (Go 1.0 → Go 1.0) · Composite literals (Go 1.0 → Go 1.0)
Design. sinit decides, per top-level var x = expr, whether the initializer can be laid out as static data (staticassign) or needs init-time code (anylit/fixedlit/maplit). Go 1.1 skipped codegen for var _ = ... when unneeded (6592456feb) and computed initialization order for blank vars (880d869764, 1.2). e5c105033a (1.3) fixed an unsound optimisation: var y = x; var x int was treated as x = 0, wrong when x is defined in C/assembly (cgo), so propagation is disabled when x has no Go initializer. Go 1.4 stopped using static init for small structs/fields (cfafa9f4cb). Go 1.5 resolved &x.f at link time (2fc29a83ae), statically initialised function pointers (632217aae4, go tool text segment −7.4 kB), and unsafe.Pointer(&x) of a global (9f90f31c3a). Go 1.6 statically initialised captureless closures (4f97ec0866), fixed initialization logic (aaabe3d849). Go 1.7 reordered slicelit to fill the stack array before slicing it (934c359964, so no write barriers; binaries ~1% smaller), treated static composite literals as side-effect free (55ab07c224) and eliminated a copy for static literals (b024ed0d94), CSE learned that newobject is bespoke (db5338f879: issue 15235 size 10k compile 44.9 s → 7.7 s). Go 1.8 added OSLICELIT and unified arraylit/structlit (49cce1a62e, cd2d5ee048), statically initialised some interface values (dfc56a4cd3), two tables for table-driven map inserts (d98de0c3d0), size hints for map literal allocations (1faea596e4), OSTRUCTKEY (add3ff549a: Unicode allocs −13.7%) and bba1ac4fd9 (only explicit OKEY nodes). Go 1.9 fixed a missed write barrier for global = T{} (160914e33c, oaslit not for globals), unrolled small static maps with cutoff 25 (50688fcb6e: 15 min → 45 s on #19751), and for functions with more than 500 user inits builds a static array of functions and loops (d1b544c7eb).
Timeline.
- Go 1.1 — Done:
6592456feb,2af3cbe308,0b2ca9e62f. - Go 1.3 — Done:
e5c105033a,8a2db409c4. - Go 1.4 — Done:
cfafa9f4cb,3c40ee0fe0(simplify explicit zeroing). - Go 1.5 — Done:
2fc29a83ae,632217aae4,9f90f31c3a,0c9f3e4972,fa1ea497d5/1125cd4997(func value symbols at declaration). - Go 1.6 — Done:
4f97ec0866,aaabe3d849,1ca7a64a0d. - Go 1.7 — Done:
934c359964,55ab07c224,b024ed0d94,3c6e60c0e4,f973e79d09/7971864267/4e75932cf7sinit cleanups,f3575a9561. - Go 1.8 — Done:
49cce1a62e,cd2d5ee048,7b5df0c195,db9796dac5,dfc56a4cd3,d98de0c3d0,1faea596e4,add3ff549a,bba1ac4fd9,64214792e2,749720a036,41d2278eef,df2b63f09b. - Go 1.9 — Done:
160914e33c,50688fcb6e,d1b544c7eb,a73a330cdf(count init functions from 0),49a533e212,6ee8c6a7ce,095a62c349,3237af2da8.
Walk-level lowering and runtime-call optimisations
Span: Go 1.1 → Go 1.9 · Status at go1.17: still the walk/order model; the runtime entry points mostly persist → continues as Static initialization and package init (1.18+)
Continues in: Lowering in order/walk and the shape of runtime calls emitted by the frontend (Go 1.10 → Go 1.17)
Design. Many compiler changes in this era moved decisions from the runtime to compile time, as walk.c/order.c rewrites to cheaper runtime calls. Interface conversion: convT2I cache (18e86644a3, BenchmarkConvT2ISmall 43→15 ns), inline pointer-sized convT2I (8fd65b0e1d), iface==concrete without allocation as x, ok := i.(C); ok && x == c (77a2113925, 38 std sites, ~75% faster), calls by reference (deb554934c), non-variadic assertI2T (ccdb50931f), inline x := y.(*T) (4224d81fae), scalar x, ok := y.(T) (615a52b95b, fmt printArg 3952→2624 bytes), itabs emitted by the compiler (f00bbd5f81) so remaining convT2I get the itab directly (859b63cc09), inline convT2E/convT2I when result does not escape (6129f37367), inline convI2E (395d36a67d), specialised convT2E16/32/64/string/slice/noptr and zero-value no-alloc (504bc3ed24, 93% of calls), efaceeq/ifaceeq simplification (e67d881bc3), CONV rather than CONVNOP for interface conversions (807c80fce3), canonical empty interfaces (62947bedd2). Maps and strings: []byte key lookup without copy (f5f5a8b620), mapassign returns a pointer to the slot so m[k] = v is *mapassign(t, m, &k) = v (442de98c14, preparation for m[k] += v in one call), mapassign_fast* and mapdelete_fast* (ec091b6af2, 5d6b7fcaa1, int32/int64/string keys, ~30% faster assigns), string range (0dae9dfb08, ASCII fast path 43.7→10.3 ns), runtime string ops written in Go (61dca94e10 with go:nosplit), makeslice with int arguments (e6f9f39ce5), growslice using int (81d4072eb0) and removing growslice_n (d1341d6cf3), vararg runtime calls removed (24699fb05c, 6f6a9445c9). Loop and arithmetic: memclr idiom recognition for for i := range a { a[i] = zero } (f03c9202c4, 18 std places; 64-byte clear 50.8→4.1 ns), single-comparison integer in-range checks (6286188986) extended to switch cases (8c85e23087, “min range size 2”), samesafeexpr extensions for m[k] op= v (9d2b988e4a, 9d4623fe43), constant switch cases tracked in a map (e26499153e), explicit zero-divide panic (18559e2da7), faulting arguments computed before argument stores (cf28e5cc9d), panicwrap argument-free (2c91bb4c8a), loop rescheduling by stack bound via FORUNTIL (d71f36b5aa), unsafe builtins handled as universal builtins (3f2cb493e5).
Timeline.
- Go 1.1 — Done:
18e86644a3,8fd65b0e1d,d098bffd84(avoid copy on type assertion),77f3e189d2faster string equality,1d6eb2e9fa/2ad57b4583(hash/eq ignore padding and blank fields),c0b3c17184. - Go 1.3 — Done:
deb554934c,f5f5a8b620,d227d680ec([]byte("string")100x less memory),6f6a9445c9,24699fb05c. - Go 1.4 — Done:
61dca94e10,4af796fb6e(runtime.hex printing type). - Go 1.5 — Done:
77a2113925,ccdb50931f,f03c9202c4,4224d81fae,1d4bfb3ebb,81d4072eb0,f5b8813e93;32fddadd98(runtime: slice growth reduced to 2x),6f07ac2f28(pad structs ending in zero-sized fields),dbe9ab69d9. - Go 1.6 — Done:
eddd7ff3cd,bca70a66a7. - Go 1.7 — Done:
f00bbd5f81,859b63cc09,4cef0e980a/bc8458ab02/36694064e5(no algs for[0]Tand[1]T,&&in generated eq),d0c11577b9,0f5d78f678,92bf58c238,b30e1d728calg-generation cleanups,8ffe496ae7fewer algorithm kinds,d1341d6cf3. - Go 1.8 — Done:
6286188986,8c85e23087,615a52b95b,9d2b988e4a,9d4623fe43,e26499153e,e6f9f39ce5,0dae9dfb08,6129f37367,395d36a67d,442de98c14,cf28e5cc9d,3f2cb493e5,ca5cea9dca,27eebbabc2(remove throwreturn). - Go 1.9 — Done:
504bc3ed24,e67d881bc3,ec091b6af2,5d6b7fcaa1,d71f36b5aa,2c91bb4c8a,807c80fce3,62947bedd2,febafe60d4,dbd51ce99c(intrinsify math.Sqrt),a0d6d3855f(typename in walk),d8899acaf8.
Write barriers, precise stacks and liveness (compiler side)
Span: Go 1.2 → Go 1.7 · Status at go1.17: write-barrier insertion moved into SSA later; frontend marks (pragmas, OASWB) removed in 1.9 → continues as Old typechecker and IR node-model cleanup (1.18+)
Design. For the concurrent GC, the compiler had to supply precise pointer maps and, later, write barriers. The compiler-side steps were: precise stack-frame liveness (precisestack, disabled for 1.2 in 30ecb4cd05: “the zeroing required without it is too expensive”, re-enable by GOEXPERIMENT=precisestack; enabled by default in 1.3 by ecf700b5ee, reverted/relanded as 53061193f1 after a 32-bit fix, costing about 5% of all.bash time and tracked as issue 7345); this guarantees interface values are always initialised so the type word is trustworthy. Cost reduction followed in 1.3: shorter temporary lifetimes through orderexpr-allocated temporaries with VARKILL (daca06f2e3, 96d90d0981: ambiguously live temps in godoc 860 → 711 → 121 → 23), and compact liveness bitmaps (4676fae525: one bitmap length per set, duplicate bitmaps merged, bitmap sets named gclocals.<md5> and dupok so the linker dedups; bitmap bytes in godoc 1326600 → 245580, binary −9%). Liveness got 10x faster in 1.4 (7aa3031eba). Go 1.4 emitted write barriers (fcb4cabba4: *p = x becomes runtime.writebarrierptr(p,x); “the goal is to slow things down (and be correct)”, BinaryTree17 +10.7%), with 2/3/4-word specialisations (a3416cf5cd), elision for *x = T{}-style zeroing (3c40ee0fe0) and for x = x[0:y]/x = append(x, ...) (1552e62d70); the interface representation changed so that the data word holds only pointers (950ad4fa2b, 75b72b1b27 re-enabled IfacePointerOnly). In 1.5 barriers are emitted “at lower level” (0ad4f8b1f7, preparation for inlining), with the writeBarrierEnabled check inlined (653d56075d), no barrier for *tmp when tmp=&PAUTO (a7bb393628), a barrier in copy of function parameters to heap (e5ef657264), //go:nowritebarrier (557a61d270). Go 1.6 added go:nowritebarrierrec (3a765430c1, special-case allocm 402e37d4a9), 1.8 added go:yeswritebarrierrec (a9e6cebde2) and go:notinheap (77527a316b): no new(T), make([]T), append, or implicit allocation of a notinheap T, propagated to structs/arrays containing them, so stores to pointers to such types need no barrier. Go 1.7 removed PHEAP bits (b6dc3e6f66: new PAUTOHEAP pseudo-class, walkexpr rewrites references to indirections of a stack PAUTO), so liveness and the SSA back end see ordinary variables.
Timeline.
- Go 1.2 — Done:
30ecb4cd05precisestack off by default;f91e682ccashorter bitmaps. Left open: call-site pointer bitmaps “not ready in time”. - Go 1.3 — Done:
ecf700b5ee,53061193f1,daca06f2e3,96d90d0981,4676fae525,8bd8cede03(-liveflag). Left open: issues 7343, 7344 (GC bugs) and 7345 (cost); 23 temps remain ambiguously live. - Go 1.4 — Done:
fcb4cabba4,a3416cf5cd,3c40ee0fe0,1552e62d70,950ad4fa2b,75b72b1b27,7aa3031eba. Left open: elision ofx = x[0:y]andappendis a 1.4-only simplification; “for Go 1.5, will need to change the compilation” (1552e62d70). - Go 1.5 — Done:
0ad4f8b1f7,653d56075d,a7bb393628,e5ef657264,557a61d270,2050f57141;08e25fc1ba//go:systemstack,19b8aa3b5d(OASWBname). - Go 1.6 — Done:
3a765430c1,402e37d4a9,dac87e9ed3(systemstack only in runtime). - Go 1.7 — Done:
b6dc3e6f66,dec1bae916,d25c3eadea. - Go 1.8 — Done:
a9e6cebde2,77527a316b. - Go 1.9 — Done:
bdb9b945b9OASWB eliminated,d71f36b5aa,c96e94e69d1.8 etc. (see other).
Compiler data structures: Node, Nodes, Type, and the types package
Span: Go 1.5 → Go 1.9 · Status at go1.17: ir.Node and types.Type as separate packages came in later releases; the 1.9 types package is the start → continues as Types package internals: size, algorithm kind, TFlag, SIMD flags (1.18+)
Continues in: dev.regabi: from *Node struct to the ir.Node interface and concrete node types (Go 1.10 → Go 1.17)
- tracking issue #14473 cmd/compile: investigate replacing NodeList with slice referenced by 12 of this thread's commits
- discussion Reducing gc peak memory use golang-dev · linked from #14473
Design. The Go-port compiler spent two years reshaping its main data structures, mostly with toolstash -cmp as the correctness bar. Lists: NodeList linked lists were first replaced by slices in specific places (1.6), then Ian Lance Taylor built a transitional nodeSeq interface (466c948b55, “I tried to write a program to convert *NodeList to Node, but ran into too many problem cases”) and converted package by package (ca56c590d4, 2aa2da295f, 132ebeac3f, 99b6b77e22, 55c65d4a97, 80e5b52566, 65c4b55aba, 72d90d8238, 2a68c6c27c, 6c4e90a99e, f444b8a80e, 72655afb4e removes NodeList), leaving Nodes (1d5001afef for Nbody and Func.Inl). Types: Type shed linked Down/Type tricks: TFIELD types became a separate Field type (2e9369067b, c278f9302e), Type.Fields became a Fields type (517b6131b2, 0d2e92c2ca, 1c2bdfb7d9), Func.Inldcl, In/Out/This tuples were removed (c837761b52, dbed1c6361), constructors typArray, typSlice, typChan, typPtr, typMap encapsulated fields (eb98e51563, 09c672d50a, fdf6761e01, 76e72691a0), TSLICE split from TARRAY (40f1d0ca9f), and f38f43d029 “shrink gc.Type in half” by moving etype-specific fields into auxiliary types reached via Extra (alloc −2% to −3.4%, +1% allocs). Node shape: ODOT stores its selector in Sym instead of an allocated ONAME Right (5f525ca60d: 5000 fewer newname calls, 6.6% fewer nodes), OSTRUCTKEY and implicit OKEY removal (see literals), ODCLFIELD without Name/Param (dc46b882d5) and constructing Fields directly when importing (d553c29dc1), 166b1219b8 allocating Name/Param/Func together with Node (allocs −5%), ed70f37e73 packing bool fields into bitsets (alloc −2.4 to −4.1%), then Node.Class, Typecheck, Initorder, Embedded, Walkdef, hasVal, Likely into flags (386765afdf, 502a03ffcf, e2560ace3c, af7da9a53b, d286399641, 2fb2ebc32e, 7f0757b394), Ullman→HasCall (870d079c76), Sym flags as bitset8 (a5a1fd4bc9, b2c391b70c) and Used moved to Name (fc08a19cef). The big structural split came in f68f292820 (2017-04-04): “factor out Pkg, Sym, and Type into package types”, creating cmd/compile/internal/types with a types/utils.go of hooks and two conversion functions between *gc.Node and a dummy types.Node to break cycles; follow-ups moved the dcl stack (fd44d872de, 48163968b2), typepkg (24c52ee570), unexported Nopkg/PkgMap (62a2bee7a5, 39a132cb2f), removed Sym.Link, FieldName, IterFields and Cmptmp (1368977a08, 5280dfbfad, 5b38923eba, 3158583713). Type caching: pointer/slice types are cached (78a267e379: stack slot reuse relies on Type identity), disabled in the back end (f9fb4579e1) for concurrency, with 2805d20689 replacing ptrto by typPtr. Haspointers caches were removed (944d56d763, e82c925f5e) and dowidth ran more in the front end (0b6a10ef24, 8dafdb1be1 WidthCalculated, c51559813f, b1b4f67169).
Timeline.
- Go 1.5 — Done: Node splits and field moves (see first thread),
Val.Uinterface (13485be939),d970bea885startssyntax.gofor the syntax tree definitions,96c91fa9dbString methods,e64764c8d0cache commonly usedPtrtotypes,8b3670ffc6. - Go 1.6 — Done:
[]*Nodemigrations (703bd83623,22452ac592,dab0dac01a,391cc54da8,bab01a0b4b,d5fe165ca0,a2119aca7d,b9dbb030d5,dd42eff8fe), bool conversions. - Go 1.7 — Done:
466c948b55..72655afb4e,6c4e90a99e,52d9479e3b,2e9369067b,517b6131b2,f38f43d029,5f525ca60d,40f1d0ca9f,eb98e51563,09c672d50a,e3c7497327(typWrapper),fdf6761e01,76e72691a0,8640b51df8(Type.Elem),1624a9c9e7,3efefd9395,e76fc1b921,007b12977a(Maplineno out of Type),b83618f964(Type.Nname),b2b5e779f5(ignore receiver in Eqtype; moves receiver check intoaddmethod),62e26e7511,b594b8b039,1765863e57(TypeList→slice),34699bc7a8(reduce**Nodeparams: Template allocs −15.7%, Compiler −17.5%),7e8e9abe0a,a4be24cbe6/edca4cda88/removingNod(OXXX,...),3621600c92magic.go,9d7b2b7b10universe.go,4720f49e18relocate Type code,11d916b157(Node.Nointerface),e3a9dca7cc,3da1a26fba(‘any’ no longer leaks into user package);1220ac27ce,68c86a0096. Left open: Type still lives in package gc. - Go 1.8 — Done:
78a267e379,add3ff549a,dc46b882d5,d553c29dc1,bba1ac4fd9,2b687a7df8(interface methods not treated like functions),d89b70d433,70d685dc72;1fcad29341(OREGISTER),a7c84668c8(Label type removed),dc53ea7772(IsHiddenClosure),dc5f9311be,f8a3444388(EscScope),3be166dc70,d58219e50b,2b49d129c4,41fa42b447,82703f84e4/d7012ca282/584978f4b5/073d248bf5/fc47ee2332(unexport helpers and globals),42b37819a1(mkbuiltin generates code),3f2cb493e5. - Go 1.9 — Done:
f68f292820(types package),fd44d872de,24c52ee570,ed70f37e73,386765afdfand the Node flags series,166b1219b8,a5a1fd4bc9,b2c391b70c,236ef852be(split SetInterface from SetFields),07de3465be(recursive interfaces),b1b4f67169/8ee2d5bc00(SetFields/Width safety),944d56d763,e82c925f5e,efc47819c0/371aa23d10(noTrecur),0b6a10ef24,ecc6a81617,3a89065c6c,3c0072e056,97b89dc055,fdef951116,00f4cacb49. Left open:Nodestill carries every node kind (the commit message of756b9ce3a5says Phase 3 is “planned for eventual removal”).
Compiler performance, formatting and concurrency
Span: Go 1.7 → Go 1.9 · Status at go1.17: backend concurrency via -c, with cmd/go setting it; later default → continues as Compile-time performance, concurrency and the self-PGO’d compiler (1.18+)
Continues in: Concurrent compilation and frontend performance (Go 1.10 → Go 1.17)
- tracking issue #15756 cmd/compile: parallelize compilation referenced by 5 of this thread's commits
Design. Compile time was tracked by compilebench (Template, Unicode, GoTypes, Compiler, MakeBash). In 1.7 ad4c55c076 replaced fmt.Sprintf with concatenation, 65b4020403 stopped creating 2 Syms and 2 Nodes per string, 135109d241 reduced slice-header allocation for :=. In 1.8 f542576b9e added compiler phase timing (-bench flag writing benchmark-format records like BenchmarkCompile:go/types:fe:parse), 6e759ad2e2 added runtime/trace support, and the fmt.go printing layer was reworked: a printer experiment (dc2a0d59a2, f7ac5da495, allocations up 10%) was abandoned in favour of fmt.Formatter/fmt.State for *Node, Op, Val, *Type, *Sym, Nodes (adcd34c732, 9e1f6a326e, 97ba3c8242, 8d0bbe2b48, a0d2010208, 266c6223df, 0ca5f269d4 removes the printer), then 37d452c3e9/0cd3ecb016 brought allocations back below the pre-change level for issue 16897 (reflect.go uses the plain tconv string method). In 1.9 723ba180b3 removed the fmtmode and fmtpkgpfx globals (they “stand in the way of making the compiler more concurrent”) by encoding the mode as named types (fmtNodeErr, fmtNodeDbg, fmtNodeTypeId), after weighing and rejecting struct wrappers (allocate on interface conversion), %*v precision, fmt.State context and a full rewrite; efc47819c0 threads a recursion depth instead of Trecur. Then 756b9ce3a5 (2017-03-19) added the initial backend concurrency: phases 5–8 (SSA, lowering, genssa, assembly) run per function in parallel using -c; order/walk proved hard to make safe, so with c>1 all functions finish phase 4 before any later phase starts, auto-generated functions (wrappers, eq/hash) after the first batch are compiled serially, and c=1 has no goroutines at all so cmd/go could “simply have cmd/go set c=1 always” if problems appear. A handful of mutexes were added; supporting changes: disabling typPtr caching in the backend (f9fb4579e1), per-function autotmp numbering (b87fcc6e06), typenamesym not touching Sym.Def and signatlist as a map sorted for reproducibility (91433eb577 reverted to 6d9c77f5dd after non-deterministic builds #19872), liveness variable indices in a map instead of Node.Opt (794d29a46f), 61336b78c1, -d compilelater, f5c878e030 randomised compile order under the race detector, 0b6a10ef24. Other perf commits: 302474c61c disable memprofile when unused, da67c23fbb flag to disable DWARF (−2.8% alloc), d62c6c3c39, f8b0231639 always optimise when building the runtime, 22f1b56dab -c flag, 8eb14e9de5 string debug flags, f9be63b9ba -d help listing keys.
Timeline.
- Go 1.7 — Done:
ad4c55c076,65b4020403,135109d241,d447613875,0373128318,1a9373bc57,ea5091fcd7,f32161daf8. - Go 1.8 — Done:
f542576b9e,6e759ad2e2,adcd34c732and the Formatter series,37d452c3e9,0cd3ecb016,2b5c18c99e,09686a5873;37d452c3e9. - Go 1.9 — Done:
723ba180b3,756b9ce3a5,f9fb4579e1,b87fcc6e06,6d9c77f5dd,794d29a46f,61336b78c1,302474c61c,da67c23fbb,f5c878e030,22f1b56dab,98b3e3a064(match tool versions),f8b0231639. Left open: “Concurrent backend compilation still defaults to off”; “In future work, cmd/go will automatically set -c”; order and walk remain serial; some mutexes “may still be eliminable”.
Pragmas, directives and compiler flags
Span: Go 1.1 → Go 1.9 · Status at go1.17: //go: pragma set persisted and grew → continues as Compiler debugging infrastructure: bisect/hash debugging, flags, dumps (1.18+)
Continues in: Directives and pragmas in the frontend (//go: handling) (Go 1.10 → Go 1.17)
Design. Pragmas are recognised in the lexer (then in noder): //go:noescape for extern funcs (fd178d6a7e, 1.1), //go:nosplit and //go:linkname, //go:cgo_* (fd2bc95d53, 1.5; linkname requires import "unsafe"), //go:nowritebarrier (557a61d270), //go:systemstack (08e25fc1ba, restricted to runtime by dac87e9ed3), //go:noinline (a92543e1a1), //go:nowritebarrierrec (3a765430c1), //go:yeswritebarrierrec (a9e6cebde2), //go:notinheap (77527a316b). pragmas tracked in the lexer (3c0fae5306), handled immediately by noder (ee161e8591, 55875977eb), with bad combinations reported earlier (5f5d882f5c), and directives must start the line (d390283ff4). Flags: -pack (b022334029), -live (8bd8cede03), -d accepting comma-separated name=value lists (6c328efc4c), unknown -d flag aborts (516d9ef53b), -d disablenil (01512b3edb), -importmap (7bcc6a1615), -buildid (0f6da8923f), -memprofilerate (00d4a6b35d), new flag syntax (8a072ada84, d5ff441d9a), -msan (0c69f1303f), -linkobj (feb6131b1a), -dolinkobj (005c77dde8), -importcfg (4d6b08de70, “a generalization of and supersedes -importmap, -importsuffix, and -I”), -C, -c, -bench, -d help, -d compilelater, -trimpath documented (f2eb3de636), -A removed (832082b44e). Position-independent code for -buildmode=c-shared on arm (876b7cc227) and -buildmode=shared on linux/386 and arm (3ae4dc8a75, 78c05b8657) were small compiler pieces.
Timeline.
- Go 1.1 — Done: user-visible
fd178d6a7enoescape;041fc8bf96race instrumentation-b;80dbe74360go.weaksymbol prefix. - Go 1.3 — Done: user-visible
b022334029-pack,8bd8cede03-live. - Go 1.4 — Done:
516d9ef53b. - Go 1.5 — Done: user-visible
fd2bc95d53,557a61d270,08e25fc1ba,7bcc6a1615,6c328efc4c,0f6da8923f,01512b3edb. - Go 1.6 — Done: user-visible
a92543e1a1,3a765430c1,0c69f1303f,dac87e9ed3,876b7cc227,3ae4dc8a75,78c05b8657. - Go 1.7 — Done:
feb6131b1a,3c0fae5306. - Go 1.8 — Done:
a9e6cebde2,77527a316b,832082b44e,49b2dd583b(remove legacy debug flags). - Go 1.9 — Done: user-visible
4d6b08de70,005c77dde8,22f1b56dab,2a5cf48f91’s-C,f9be63b9ba,da67c23fbb,98b3e3a064,3c1914fc46(distinguish.aand.oby content).
Race detector and sanitizer instrumentation in the frontend
Span: Go 1.1 → Go 1.7 · Status at go1.17: racewalk pass (later instrument) → continues as Compiler debugging infrastructure: bisect/hash debugging, flags, dumps (1.18+)
Continues in: checkptr instrumentation and compiler debugging flags (Go 1.12 → Go 1.17)
Design. racewalk.c walks the typechecked AST and inserts calls to the race runtime around memory accesses. It arrived in Go 1.1 (041fc8bf96, 431 lines, enabled by -b), with PC passed directly to racefuncenter (ce287933d6, encoding/json race benchmark ~1.9x faster) and &&/|| instrumented (c0b3c17184). Go 1.2 fixed tail-call wrappers (e440354c40, 269b2f2d4d) and arrays (3be794cdc2). Go 1.6 generalised racewalk to instrument for other tools (9e902f0f3a) and added -msan (0c69f1303f); Go 1.7 made insertion careful (c3b3e7b4ef) and Go 1.9 randomised compile order when race-enabled (f5c878e030).
Timeline.
- Go 1.1 — Done: user-visible
041fc8bf96,ce287933d6,c0b3c17184. - Go 1.2 — Done:
e440354c40,3be794cdc2,269b2f2d4d. - Go 1.6 — Done: user-visible
9e902f0f3a,0c69f1303f. - Go 1.7 — Done:
c3b3e7b4ef.
Diagnostics and error messages
Span: Go 1.1 → Go 1.9 · Status at go1.17: ongoing; types2 later supplies messages → continues as Error reporting: codes, messages, and sub-errors (1.18+)
Earlier history: Diagnostics, error recovery and compiler plumbing (Go 1.0 → Go 1.0)
Design. A continuous stream of message-quality work: replacing “typechecking loop” with real diagnostics (892fa3ae6c, 6363fc5aa6), better line numbers (bf59aafddc composite literals, dd166b9437 “no new variables”, e2711cb202), removal of the word “ideal” (703bd83623-era: 703b897f78), “have/want” signatures for argument and return count errors (2d573eee8a, ec5b6406b7, 19d2061d50 suppress when types unknown), interface satisfaction messages (2254785c3e, 574e0f9a48, 1c2021ca14 suggests *T), unknown-field message (7b4545653c), import errors (d06dcd4595, 8d530f2472, 85195e2ccf, 5be1821a31, 9fda4df9a0 deterministic), and in 1.9 duplicate-error suppression (d62c6c3c39, 3218b1aa6f, f62c608abb, d55f528826, 2e60882fc7), correct redeclaration position (d79bb78a71), assignment count mismatch messages (88cf932e98, 73a44f0456, 3c7a812485), init direct invocation (cb6e0639fb).
Timeline.
- Go 1.1 — Done:
892fa3ae6c,6363fc5aa6,d06dcd4595,1c2021ca14,a7a3fe7238(oversized arrays),c208a3a263,bd0bb2bc39,79a3b561b51.6… see other items. - Go 1.2 — Done:
703b897f78,d00bd1d1f4,2254785c3e,8d530f2472. - Go 1.3 — Done:
a599b4890a,1d2b71ce83,656a402545,574e0f9a48.
Changes in this slice that are not part of a thread are listed on the release pages: 1.1 · 1.2 · 1.3 · 1.4 · 1.5 · 1.6 · 1.7 · 1.8 · 1.9
Compiler frontend (Go 1.10–1.17)
Reader: Claude Sonnet. Cites 1,071 of 1,353 commits in this slice; every non-noise commit is cited, plus 30 larger commits the noise filter had set aside, which a separate gap reader described. Read the design-heavy messages, subject lines and a few full messages, and checked the -G/AllowGenerics behaviour against the go1.17 source. No diffs were read, so the typechecker, walk, inlining and types threads are thinner than the IR, export-data and generics threads.
Release digest for this slice
- Go 1.10 — Export-data diet (skipping unreachable/duplicate inline bodies), better syntax-error recovery and line directives groundwork, and many small typechecker/map-lowering improvements; frontend still C-to-Go-translated
gc. - Go 1.11 — Indexed export format added and made default, syntax package made independent with column-aware line directives, concurrent compilation of all functions, method-set sorting O(N+M).
- Go 1.12 — Binary export removed,
-langintroduced, constant folding restricted to Go constants, typechecker tracing and new node dumper. - Go 1.13 — Go 2 number literals and signed shifts, evconst consolidation, spec-compliant package init order, multi-value
f(g())rewriting moved to typecheck,-newescapedefault. - Go 1.14 — Untyped constant conversion rewrite,
-d=checkptr, overlapping interfaces gated by-lang, columns in export data, scanner error limiting. - Go 1.15 — Misplaced-directive diagnostics, new syntax source reader,
ODDDARGremoval, mid-stack inlining in recursion cycles, slicesym/gdata cleanup. - Go 1.16 —
//go:embed,go:notinheaphardening, type-switch and method-value inlining, early devirtualization, export-data hash as fingerprint, init-cycle reporting fix. - Go 1.17 — The largest frontend restructure: dev.regabi (Node interface,
base/ir/typecheck/noder/inline/staticdata/reflectdata/pkginitsplit, go/constant), dev.typeparams (syntax type parameters, types2,-G, irgen, first stenciling),unsafe.Add/Slice, and typecheck info in export data.
dev.regabi: from *Node struct to the ir.Node interface and concrete node types
Span: Go 1.10 → Go 1.17 · Status at go1.17: done: ir.Node is an interface with ~60 concrete node types (ir.Name, ir.Func, ir.CallExpr, …) and generated DoChildren/EditChildren/Copy; Left/Right/List accessors are gone; Nodes is a plain slice → continues as Old typechecker and IR node-model cleanup (1.18+)
Paths not taken: The dev.regabi Node-accessor demonstration (superseded)
Earlier history: Compiler data structures: Node, Nodes, Type, and the types package (Go 1.5 → Go 1.9)
Design. Through Go 1.16 the whole frontend used one fat gc.Node struct (Left/Right/List/Rlist/Ninit plus Name, Func, Param sub-structs, and overloaded Etype/Xoffset/Opt fields). Go 1.10–1.15 only chipped at it (stringer for ops 3231d4e4ef, Node.copy 19ee2ef950 and the copy/rawcopy/sepcopy split ce58a39fca, moving ONAME-only flags into Name 06b12e660c, removing Addable 46be01f4e0 and PDISCARD 9f4fb68152, Node.Etype overloading fix e4de522c95). In Nov–Dec 2020 the [dev.regabi] branch turned that into a typed IR in a strictly mechanical sequence, most steps produced by rf scripts (“[generated]”) and verified with toolstash -cmp / buildall.
The sequence: (1) add getters/setters for every field (d166ef6876), rewrite all callers to use them and unexport the fields (acb4d1cef1); (2) make the pointer type an interface: first INode (4d0d9c2c5c), then rename so ir.Node is the interface implemented by an unexported *node (41f3af9d04, with types.Node→types.IRNode c26aead50c); (3) peel concrete implementations off the struct, starting with a hierarchy of custom node types for type syntax (4e7685ef1a), ir.Name as the ONAME node (862f638a89), ir.Func as ODCLFUNC (c4bd0b7474), ir.PkgName (f6106d195d), statements (ffa68716a0, be3d8b40b5) and expressions (9a5a11adfa), ir.Closure/CallPartExpr (4eaef981b5, e5c6463e20), a lighter ConstExpr (a2058bac21) and BasicLit (c8610e4700) so that Name only represents declared constants; OMETHEXPR stops overloading ONAME (ee6132a698, 4f9d54e41d), ONAMEOFFSET/NameOffsetExpr replaces Name.Offset abuse in static init (c76be2a24e, ffb0cb7044), OTSLICE etc. type nodes (f0001e8867). (4) Replace the generic child accessors by reflection-free generated traversal: ir.Visit/DoChildren/EditChildren visitors (0d1b44c645, d855b30fe4, 4725c3ffd1, bb5aa2b664), Copy per node (18f2df7e81), all generated from struct definitions by ir/mknode.go (2cec6c4a8c, generalised in 499851bac8, 5cf3c87fa6); ir.Dump uses reflection and prints field names (4090af83c5, 6d783e7440 exports all fields first). (5) Remove the generic operations: ir.Nod (6f27d29be0), Node.Left etc. (14d667341f adds type assertions on every n.Op() == X branch and deletes the accessors from the interface; f9d373720e replaces the remaining uses with named fields), Nodes becomes []Node (114af2a044, 440308ffd7), SliceExpr.List, SliceHeaderExpr.LenCap, RangeStmt Key/Value, CaseStmt vs CommStmt get named fields (d1d64e4cea, d19018e8f1, 27b248b307, 2ecf52b841, a59d26603f), {Selector,CallPart,Method}Expr merge (4629f6a51d).
A parallel line of work removes identity ambiguity: one *Name used to stand for both a declaration and each use, so SameSource/Uses/DeclaredBy helpers (d9cb84c84b, 133b03e1c3) prepared ir.Ident for not-yet-resolved names (63bc23b545, 4c2d66f642, 94cfeca0a5 no more ONONAME on Name). Closures get a first-class representation: Func.ClosureVars replaces OCLOSUREREAD/ClosureEnter/ClosureType (7fd84c6e46, 9ed1577779, d9acf6f3a3, 9821838832), closures are transformed during walk (41352fd401), and Func.Nname is removed from types (c754f25241, c50c7a8c06).
Timeline.
- Go 1.10 — Done: only groundwork: stringer-generated
OpandClassnames (3231d4e4ef,79dbc1cc7b,6e9960ea63), generic AST walking factored (12c9d753f8),OXFALLeliminated (4347baac7d),Localflags removed from Type/Node (b2e7eae7c4). Left open: nothing noted. - Go 1.11 — Done:
Node.copy(19ee2ef950) and removal of manual copies (60fee0153f); constant-node constructors centralised (fdf33730e1); inline fields moved to a separateInlinestruct (562a199961);Field.Nname.Posreplaced byField.Posto stop allocating an ONAME per struct field (7759b32a62). Left open:Nodestill a single struct. - Go 1.12 — Done:
OCMPIFACE/OCMPSTRops removed (28fbbf4111,a0d6420d8b); alternative node dumper for debugging (5d444e36a6); labels represented as bareSyms (2dda040f19);TPTR32/TPTR64merged intoTPTR(62e5215a2a). Left open: nothing noted. - Go 1.13 — Done:
ORESULTadded andOINDREGSPremoved (336f951b07);nodl/newnameltake named fields (e92853523d,24a6478be3). Left open: nothing noted. - Go 1.14 — Done: some ONAME-specific state moved to
Name;AddableandPDISCARDremoved (see above);-d-controlled “line number printing for nodes” (c1b7f508b0);%vused for Node formatting (2c47caa900);DDDarray types removed (616c39f6a6). Left open: nothing noted. - Go 1.15 — Done:
ODDDARGremoved by callingfixVariadicCallbefore escape analysis (080a3ee8b2,a44d06d3b4). Left open: nothing noted. - Go 1.16 — Done: function nodes no longer declared / pushed onto
Func.Dcl(a4171d85d7,ace37d35f1);-d=dumpptrsfor Dump (c31540364c). Left open: nothing noted. - Go 1.17 — Done: the entire dev.regabi sequence above, Nov 2020 to Jan 2021: getters/setters
d166ef6876→acb4d1cef1; interface41f3af9d04; concrete node types862f638a89,c4bd0b7474,ffa68716a0,9a5a11adfa; visitors and generated methods0d1b44c645,2cec6c4a8c; removal ofLeft/Right14d667341f,f9d373720e;Nodesas slice114af2a044;ir.Ident/BasicLit/ConstExpr(63bc23b545,c8610e4700,a2058bac21);Name.Optmoved toName(289da2b33e);OSTMTEXPRadded (45f3b646d4) then removed in April (7735ec96c1);OSELRECVremoved (aeedc9f804);OBLOCK/OEMPTYmerged (ec5f349b22,ecc8d15bc5);ONEWOBJremoved (ab3b67abfd);TailCallStmtadded (87845d14f9);ir.StaticValue/OuterValuemade safer (e09783cbc0,9aa950c407). Left open: IR still carries both syntax-derived nodes and typechecker-created nodes;ir.CurFuncand theNtypemechanism survive (33801cdc62,3512cde10aonly reduce their use); the old typechecker still runs after noding.
dev.regabi: breaking up package gc into base, ir, types, typecheck, noder, inline, staticdata, reflectdata, pkginit
Span: Go 1.17 → Go 1.17 · Status at go1.17: done; layout of cmd/compile/internal/* as it remained → continues as Old typechecker and IR node-model cleanup (1.18+)
Paths not taken: The dev.regabi Node-accessor demonstration (superseded)
Design. cmd/compile/internal/gc held everything (flags, error reporting, IR, typechecker, noder, inliner, static data, reflection data, init). Splitting required a dependency order. Russ Cox’s mechanical sequence of 19-23 Dec 2020: first base for flags, Debug, Ctxt, Exit and error reporting (26b66fd60b), then ir for node definitions and the TINT8 alias removal so each name shows its package (84e2bd611f), then “collect global compilation state” into a struct ir.Pkgs-style (1a3b036b83) and a series of “separate X more cleanly” prep CLs: exportsym, noder, nowritebarrierrec, dowidth, typecheck, various (85ce6ecfe3, 4836e28ac0, 1a523c8ab0, 7c8f5356ab, 3b12c6dc08, 572f168ed2, 51ba53f5c2). Helpers then migrated to base (ead4957892), types (9ee309255a, and type size calculation dac0de3748, replacing an import-cycle hack) and ir (527a1895d6), after which packages were cut out: typecheck (b9693d7627), inline (575fd6ff0a), noder (fbc82f03b1), staticdata (4dfb5d91a8), reflectdata (de65151e50), pkginit (3d8a3cb06b). typecheck1, a 1,747-line function, is split so each case is its own function (0256ba99a8), later restructured so typechecking sits in noder to be interleaved with noding while non-typechecking passes go back to gc (0f1d2129c4, with deadcode in its own package). Printing of Type/Sym moves to types (bb4a37bd93), FmtFlag/FmtMode are untangled (70155cca81, 3904a62829), and the ir↔︎types interface is narrowed (fb17dfa43d); types get constructors so IR code stops building Type literals (77a71e0057, c10b0ad628, 5ffa275f3c “first pass at abstracting Type”, e1047302bd) and mkbuiltin.go is updated for them (63c96c2ee7, 5898025026).
Timeline.
- Go 1.17 — Done: all of the above (see hashes), plus linksym helpers so
ir/staticdata/reflectdatado not need*ir.Namefor symbols (25c613c02d,ec59b197d5,0ffa1ead6e,4a4212c0e5,82b9cae700),ir.Pkgstrimmed (7e0fa38aad),go.map/go.tracksymbols created directly (a2f825c542),NewNamedandsetUnderlyingmoved intotypes(f37aa5e4e2,63a6f08b39). Left open: noder was still the legacy syntax-to-IR walker alongside the new types2irgen(see generics thread);gcstill hostsMain, ssagen glue and many leftovers.
Indexed export format and the export-data lifecycle
Span: Go 1.10 → Go 1.17 · Status at go1.17: the indexed (iexport) format is the only compiler export format, now carrying positions with columns, type information on inlined bodies, closures and ABIs → continues as Unified IR: one serialization for noding, stenciling, inlining and export (1.18+)
Earlier history: Binary export data and the object-file split (Go 1.1 → Go 1.9)
Design. Up to 1.10 the compiler wrote a sequential “binary export” (bexport.go): importing a package processed every declaration and every inline body in order, even if the importer used none of it. In large Go programs the export data was big because of transitive type declarations and inline bodies. The indexed format (ca2f85fd3f) writes an index of declaration and inline-body offsets so iimport lazily loads only what compilation touches; the commit’s benchmarks compare -iexport=false and -iexport=true across -c and -l settings. It is read lazily through Sym.Def placeholders created by the importer; dd71e3fef4 and ae2a2d12f6 consolidated how imported declarations and init functions are wired up so both importers share code.
Before iexport there was incremental work to make export cheaper: skip duplicate inline method bodies already imported (f0b3626904, which for a protobuf-heavy package cut compiler RSS from ~12GB), don’t export unreachable inline method bodies (8684534321), record InlCost in export data so the importer does not recompute (a509cae90d), and simplify exporting of the universal error type, OTYPE and ONAME nodes (13772edbbd, 577967799c, c64e793850). Export data also had to be position-faithful: exported constants and declarations got precise positions (b976859b47, 3124439b3a, a5b759aab8, 26e0e8a840, 1c439e6e37).
Subsequent evolution: package “height” (longest import chain) recorded in export data to order method sets deterministically across packages (07029254a0, 49ed4cbe85); fingerprints for the linker’s index consistency check first from a build id, then from a hash of export data (aefd99de0b, 7795523910 [dev.link]); column information added at ~4% export-size cost, though importers like go/internal/gcimporter only read it (95b8cbfee9); from 2021 export began to include enough information to avoid retypechecking inline bodies (1129a60f1c), field notes (c7d708e42e, e12b0afa54), ABIs (67d565d281) and closures (1760d736f6, 5f3dabbb79, b98ce3b606, eb433ed5a2).
Timeline.
- Go 1.10 — Done: shrinking export work as described:
f0b3626904,8684534321,a509cae90d,13772edbbd,577967799c,c64e793850,3628c2d52f(no Markdcl/Popdcl in bimport); export-position precisionb976859b47,3124439b3a,a5b759aab8. Left open: still the sequential bimport/bexport format. - Go 1.11 — Done:
ca2f85fd3fadds the indexed format (flag-iexport),a3c75d9b31makes it the default,eec8fb5ef3forbids mixing-iexportvalues,ce1252a610collapsesExport/Package/ExportedSym flags to oneOnExportList,07029254a0/49ed4cbe85add package height,bcc8edfd8asimplifies reexport, and fixesf125052ad5(exportingforloops),011ea87921(recursive inimport),cc422e64d0(missing inline body),8d5fd871d7(width not calculated). Left open: the binary format was still retained as fallback and (perfa913a36a21.12) inlining of autogenerated wrappers had to be disabled with iexport. - Go 1.12 — Done: the old binary export is disabled then removed (
d546bebe34,433496615f), the-iexport-style flags-i(b4150f7614) and-dolinkobj(965fa3b191) go; export ofFunc.Endlineno(c374984e99); inlining of(*T).Mwrappers re-enabled (fa913a36a2). Left open: nothing noted. - Go 1.13 — Done: export of rewritten
f(g())calls fixed (916e861fd9); alias export metadata fix (2d357d8da8). Left open: nothing noted. - Go 1.14 — Done: columns in export data (
95b8cbfee9), no export-mark for send-only channels (48e482ef0c), OPTRLIT no longer exported (fd5ba54f7c); [dev.link] symbol indices propagated through export data (53b7c18284,286d744246). Left open: importers outside the compiler ignore columns. - Go 1.15 — Done: fingerprint read cleanups (
8627b4c9b5). Left open: nothing noted. - Go 1.16 — Done: export-data hash used as the package fingerprint, unifying the linker’s plugin/shared-object hash (
7795523910);//go:notinheapannotation exported to the object file (a9c75ecd3d); [dev.link] defined-type symbols referenced by index (69748f0ce4); fingerprint-read cleanup (84a62453e5). Left open: nothing noted. - Go 1.17 — Done: type information on exported bodies (
1129a60f1c), described as an enabling change for generics: “the current typechecker can mostly go away in favor of the types2 typechecker”; closures exportable (1760d736f6,5f3dabbb79), inlining of closure-containing functions disabled for now (8027343b63); ABI export (67d565d281); struct-field note info and separate param/field encoding (c7d708e42e,e12b0afa54); nil exported simply (c6de5d8d1f),iexportavoidsmap[ir.Node](e885df2731), export debug mode (b60a3a8cfb),OSLICE2ARRPTRexportable (5f1df260a9), method-expression import (6d8ba77896), duplicate-import detection (b6df58bd1f), width fix for imported types (fee3cd4250), re-export of parameters (d89705e087),exportWriter.qualifiedIdenttightened (cb34026a95). Left open: the format still serializes the oldirnode tree; generic bodies and shapes need a different carrier.
Generics bring-up in the compiler (dev.typeparams): parser, -G, types2, irgen, first stenciling
Span: Go 1.17 → Go 1.17 · Status at go1.17: generic code is parsed and type-checked only when the undocumented -G flag is given; stenciling of simple generic functions and types exists but is experimental and not enabled by default → continues as Generics via GC-shape stenciling and runtime dictionaries (1.18+) and Bringing up generics in types2 (1.18+)
Paths not taken: Generics implementations not taken: contracts parser, go2go, early stenciling demos (superseded)
- proposal #43651 spec: add generic programming using type parameters listed in Go: A Documentary
- design doc Type Parameters Proposal listed in Go: A Documentary
- design doc Generics implementation - Stenciling listed in Go: A Documentary
- design doc Generics implementation - Dictionaries listed in Go: A Documentary
- design doc Generics implementation - GC Shape Stenciling listed in Go: A Documentary
- discussion Implementing Generics golang-dev · listed in Go: A Documentary
Design. The prototype from the dev.go2go branch was ported in stages. (1) Syntax: TParamList on TypeDecl/FuncDecl and File.EOF (617b633917), parsing of type parameters behind a syntax.AllowGenerics mode (b627988b0c), and a decision (73f529845c) to represent every instantiation T[P1,P2] as an IndexExpr with a ListExpr index, dropping a CallExpr.Brackets hack; later ~T as an operator and ~/| interface elements (4bbe046aad, 4638545d85), type parameters must always be named (7909d6ec28). (2) The -G flag lets the compiler accept generics (48755e06aa, “for now … only parses and then exits”). (3) A copy of go/types adapted to the compiler’s syntax tree is checked in as cmd/compile/internal/types2 plus an importer package (ca36ba83ab), and -G runs it for type checking only (87eab74628). -G levels (6b4da14dd3): -G/-G=1 parse and typecheck; -G=2 also noding; -G=3 continue to the backend. (4) A types2-based noder, “irgen” (ef5285fbd0), builds IR guided by types2 Info (types, selections 5aff757efc) skipping constant and type expressions and syntax checking, while still calling the old typechecker for desugaring; go test std cmd nearly passes with -G=3. Over Jan-Apr 2021 the old typechecker is replaced by transform functions invoked from noder2 (0265b6475f, e7e0995cba, b587b050ca, 84162b8832, 46ffbec1d6) so that nodes whose operands have type-parameter types can have transformations delayed until instantiation (eeadfa2d38), and OXDOT is resolved in noder using Selection (12cd9cf7e0). (5) Stenciling: generic functions are instantiated on demand (dcb5e0392e), including calling other generics (0fbde54ea6), methods on type parameters (12e15d430d), conversions (fdf3496fcc), generic types with methods (20050a15fe), OFUNCINST/OTYPEINST nodes (e633f343ba), inferred type arguments (3f845b3b45, fdded79e6e, 1318fb4a32), closures (d8e33d558e, f432d3fc41), interfaces (a70eb2c9f2), channels/maps/builtins (dca9c11845, c236095638, 70d54df4f6), untyped constants (90b1ed1602) and pragma propagation (083a26c7d2). Each instantiation is a full copy of the body specialised for the concrete type arguments; a stencil name is built from targ.Type.String() (c0aa7bd760).
Timeline.
- Go 1.17 — Done: parser/syntax/
-G617b633917,b627988b0c,48755e06aa,73f529845c; types2 + importerca36ba83ab, type-check generic code87eab74628; scaffolding6b4da14dd3,5aff757efc;irgenef5285fbd0; types2Sizesmatching the compiler’s struct padding (2e8f29b79d);OLISTfor multiple type args (3d5c715bf2), generic type arg in call parse (13a7412983); first stencilsdcb5e0392eonwards; type info threaded intotypesandir(2440dd457a,0aafd69124);allMethodsreplacestypes.Interface.Fields(a4b8241d97);RParamsoverhead reduced (519f223aa2);comparablein constraint (832a01aad4);types2.Instantiatefor imports, “experimental … not executed unless we enable generics” (9e0facd26e). Left open: generic code not accepted without-G; type lists vs.~unions only reached the parser late (4bbe046aad); “inlining functions with closures disabled for now” (8027343b63); generic export/import and dictionary-based sharing do not exist yet — every instantiation is a separate full stencil.
types2 port of go/types: reviews, error-message parity and language-version support
Span: Go 1.17 → Go 1.17 · Status at go1.17: types2 is used for -G builds only; the legacy typechecker is still the authority for ordinary compilation → continues as Sharing code between go/types and types2 (1.18+), Error reporting: codes, messages, and sub-errors (1.18+) and Bringing up generics in types2 (1.18+)
Design. types2 began as a port of go/types (with generics from dev.go2go) to the compiler’s syntax package: syntax.Pos replaces token.Pos, positions compare with cmpPos (later Pos.Cmp 8f1099b585, and pos.go moved into syntax 93466cc1b6), errors take a poser (6e98406ac3), and Scope.Squash was added (41ff51ae00). The working method is a file-by-file “review of X.go” CL (a dozen in Oct 2020: 38af45b4cb, 6e98406ac3, 41ff51ae00, … then Dec–Mar: f38da2cbb6 unify.go, 3b5918c757 predicates.go, 196102d046 typexpr.go, bab3461123 infer.go, 1758780181 sizes.go, c2314babb8 type.go, d6bdd1aeef typestring.go, 5a0e4fc4e7 conversions.go, c69515c9fd expr.go, 68f8e1af29 call.go, 607f99904e api.go, ddcdbb417b, 0fc595ec99, 34ef294b76, 34fb2b2ed5, 135c9f45ec, 6454b2720f, 93dcaba119, 01821137c2) making each file diff-minimal against go/types, so fixes can flow in both directions (7bedd47798, f893f35d9f, 6082c05d8b are go/types counterparts).
For types2 to replace the old checker it had to emit the compiler’s error strings, which are tested by test/*.go // ERROR comments. A Config.CompilerErrorMessages flag (87bc85a846) selects compiler-flavoured wording; a series of CLs adjust particular messages (07d32c8183, 810957b155, 6812eae2e2, 43c7b214db, edf80c4209, 036245862a, 67bf62d939, ece5935364, 6afa0ae4e5, 785a8f677f) and the error machinery gets an accumulating error_ type replacing tab-indented “secondary” errors (acd7cb5887), source-order error processing in tests (836356bdaa), unused imports in source order (217a461f56), package qualifiers disambiguated (42812a2fee). Config knobs are retired as the generics work stabilises: IgnoreBranches added (bdc4ffe9a8), InferFromConstraints and AcceptMethodTypeParams removed (7d5c54eee4, 1395432f23), “finals” removed (41245ab283), MethodSet code removed (a49e941027). API ergonomics: converter methods replaced by functions (5e4da8670b, 653386a89a, 099374b55e), predeclared any as alias for interface{} (f03f934ede), parenthesised constraints (0458d8c983), type-parameter ids from a global atomic counter (8dcc071063), Named.SetTParams/Orig (892cad7a9b), a single infer function combining function-argument and constraint inference (bce85b7011, 3f4977bd58, 190cb937f7, a6d95b4508), unsafe.Add/Slice (14056d0d00), untyped constant overflow at 512 bits then 2048-bit limit (370e9f5843, a59cb5109d, c910fd7b77) and language-version checks (1ff2fdaaf1, f37b0c6c12, ddec18cf82, a9705e157b, 962d5c997a).
Timeline.
- Go 1.17 — Done: initial check-in
ca36ba83ab; review series above; compiler-message mode87bc85a846; language-version support1ff2fdaaf1;-langpassed in721488498a; sorted-methods criteria shared with the compiler (6923019a71,5347241b5e); constant overflow8fbdacf64c,0123c9b321;types2.Instantiate9e0facd26e; fixes from all.bash, e.g. tag-less fields copying the last tag and switch case-scope end (44d1a8523a); decl-cycle resolution aligned with go/types (6521c7b378); delayed recording of untyped operands against type parameters (51e4bb236c,8f19394b62); type-switch with type parameter case (2c25cd5ba7); removal of pointer designation / implicit type arguments / disabled type-list code (fbc4c6a3ae,c4f0da5750,9546596d77). Left open:CompilerErrorMessagesexplicitly “needs to be removed” later by adjusting either typechecker or tests (87bc85a846); types2 is not used outside-G.
The syntax package: parser, scanner, source reader, positions and error recovery
Span: Go 1.10 → Go 1.17 · Status at go1.17: stable parser with optional generics (AllowGenerics), a fast reader, and pragma handling delegated to the noder → continues as The syntax package (parser, scanner, tree) (1.18+)
Earlier history: The syntax package, position representation and parse-time checks (Go 1.8 → Go 1.9) · Parser: from yacc to a hand-written recursive-descent parser (Go 1.1 → Go 1.8)
Design. cmd/compile/internal/syntax is the compiler’s own parser producing a compact tree with position info. Its design points in this period: (a) independence: in 1.11 it dropped cmd/internal/src and gained its own simple Pos/PosBase so it could stand alone or replace go/parser some day (5c08b9e8bd), and removed ParseBytes (e87f2a1b70); (b) line directives: /*line file:line:col*/ and //line :line:col (ac45cb9aa0, 6fa6bde924), relative column printing from a prior directive’s column (0c884d0810), GOROOT replacement and original+absolute names recorded (27e80f7c4d, ca2a886cba), documented (e65d6a6abe); (c) error recovery: function nesting considered (68e390304e), missing closing parens (0b2cb89196), missing type (670494827c), missing function call in go/defer (1a22738749), missing expression (dca0d03b9c), if header errors (be9a1774f2, 4637699e92), assignment in value context (ffc0573b85), plus BadExpr where needed (e0cb80e4d1); (d) lexical errors: BasicLit.Bad and at most one scanner error per number literal (117400ec09, 5411953df5, cdd2c265cc), better scanner messages (bfb903f252), more than one rune unread for the new number syntax (58365b34bb); (e) performance: stringer for operators and tokens with a tokStrFast to avoid scanner regressions (c879153831), “faster and simpler source reader” rewrite of source.go from an early-2019 rewrite (4de606b55f), noder long-summation optimisation (506386fd37), noder slice preallocation (33fac9bad8); (f) pragma API: instead of a uint16 bitmask, syntax hands the noder pragma text and the noder decides placement, which enables “misplaced compiler directive” errors (768201729d).
Timeline.
- Go 1.10 — Done: source buffer refilling bug (
e06a64a476), function-nesting recovery (68e390304e), list-parsing factor-out (645c661a54), missing-paren recovery (0b2cb89196), semi position (08e342d62c), function syntax representation documented (4b1f2bb688). Left open: nothing noted. - Go 1.11 — Done: independence from
cmd/internal/src(5c08b9e8bd),ParseBytesremoval (e87f2a1b70), line directives with columns (ac45cb9aa0,6fa6bde924,0c884d0810), stringer tokens (c879153831), error-recovery and message improvements,~no longer assumed to mean^(33eb0633e1), naming conventions (f04eebfdf5). Left open: nothing noted. - Go 1.13 — Done: scanner accepts Go 2 number literals via a liberal grammar (
ceb849dd97, see constants thread); recovery after:=in declarations (4145c5da1f); unread of more than one rune (58365b34bb). Left open: nothing noted. - Go 1.14 — Done:
Badliterals and lexical-error limiting (117400ec09,5411953df5,cdd2c265cc); missing-expression recovery (dca0d03b9c). Left open: nothing noted. - Go 1.15 — Done: new source reader (
4de606b55f), scanner messages (bfb903f252), pragma interface and misplaced directive diagnostics (768201729d). Left open: nothing noted. - Go 1.16 — Done:
BadExprplacement and handler fix (e0cb80e4d1). Left open: nothing noted. - Go 1.17 — Done: generics parsing and tree changes (
617b633917,b627988b0c,73f529845c), printing of channel types and of type parameters/lists (e9e58a4d49,a99ff24a26),Posmethods and testing helpers (5e46c6a10f,6ff16fe3ee),syntax.Walkvisitor moved from types2 (d017a1b649),ShortStringremoval (822aeacd9e), exportedNewName(3a912f279f),~operator and union elements (4bbe046aad,4638545d85),...-without-type message (a63ff398d5). Left open: generics still gated byAllowGenerics(set when-G).
Constants: Go 2 number literals, evconst, untyped conversion and go/constant
Span: Go 1.11 → Go 1.17 · Status at go1.17: the compiler’s constants are go/constant.Value; Ctype/Val/Mpint representation gone; untyped types are types.Ideal{int,rune,float,complex}; rational arithmetic enabled → continues as Frontend support for new language features and spec changes (1.18+)
Earlier history: Constant arithmetic, Mpint/Mpflt and floating-point constants (Go 1.1 → Go 1.9)
- design doc Proposal: Go 2 Number Literal Changes linked from #12711
- proposal #19308 proposal: spec: binary integer literals referenced by 2 of this thread's commits
- proposal #28493 proposal: permit blank (_) separator in integer number literals referenced by 3 of this thread's commits
- proposal #29008 proposal: Go 2: hexadecimal floats referenced by 2 of this thread's commits
- proposal #12711 proposal: different octal base literal representation referenced by 3 of this thread's commits
- proposal #19113 proposal: spec: allow signed shift counts referenced by 2 of this thread's commits
- design doc Proposal: Permit Signed Integers as Shift Counts for Go 2 listed in Go: A Documentary
Design. The legacy frontend represented constants as Val{U interface{}} holding *Mpint, *Mpflt, *Mpcplx or string/bool/NilVal, with a Ctype tag (CTINT, CTFLT, CTRUNE, CTNIL, …). evconst folded expressions. Work in this period (a) made it spec-correct and (b) retired it in favour of go/constant, which types2 uses, so the two typecheckers agree.
Go 1.13 Go 2 number literals: one liberal scanner grammar
[prefix] digits ["." digits] [exponent] ["i"]with later diagnostics for malformed ones (ceb849dd97),iaccepted on all numbers (4ad5537bfa), workarounds for0oand_removed once the syntax package handled them (a77f85a618,fbc5acbd70); shifts by signed amounts (585c9e8412). Constant folding was consolidated intoevconst(3def15cd20,a1b5cb1d04,6fa7669fd7,7fa195c1b9), keeping folding within OADDSTR (0a04c0430e) and keeping non-Go constants (e.g. results of unsafe/-asmhdr) as plain expressions (1602e49701,eb6c433eb3,33ac854481), mixed float precision fixed (041d31b882). Go 1.14 rewroteconvlit/defaultlit:convlit1now follows the standard “setn.Type = nilon error” convention to eliminate follow-on errors, with context passed down (581526ce96); the singleTIDEAL“untyped number” type becameIdeal{int,rune,float,complex}kept in sync withVal().Ctype()for precise messages likestring(1.0)(e710a1fb2e);iotainside functions’ ConstSpec (55c0ad4b62), complex truncation (52cff70100,34314280e4).Go 1.17 dev.regabi:
CTNIL→ONILandCTRUNEremoved (88a9e2f9ad,c767d73227,4af2decf30),Ctypereplaced byconstant.Kind(742c05e3bc) andValbyconstant.Value(7d72951229, mixed benchmark effect), non-mutatingevconst(6826287c6b), overflow reporting incl. unknown values and^/^x(259fd8adbb),okforconst(331b8b4797), workarounds for go/constant removed (171fc6f223), rational arithmetic enabled (6a4739ccc5).
Timeline.
- Go 1.11 — Done: constant constructors and rewriting refactored (
fdf33730e1,0250ef910f); constant pointer comparison fix (fe77a5413e); untyped boolean typechecking (d3f6d11d84,e057680542). Left open: nothing noted. - Go 1.12 — Done: index-bounds error (
a37d95c74a); non-Go constants not folded (1602e49701,eb6c433eb3). Left open: nothing noted. - Go 1.13 — Done: user-visible new number literals
ceb849dd97,4ad5537bfa, signed shift counts585c9e8412, and-langgating (762953be28); evconst consolidation3def15cd20. Left open: nothing noted. - Go 1.14 — Done: untyped conversion rewrite
581526ce96, precise untyped kindse710a1fb2e,2da9c3e0f9improved errors for const conversions,ORUNESTRfolding (ac1d440ea6),iotain function ConstSpec (55c0ad4b62). Left open: nothing noted. - Go 1.15 — Done: rune bounds checked as int32 (
173dce8d20), complex conversion fix (34314280e4). Left open: nothing noted. - Go 1.16 — Done: typecheck sets correct untyped type (
0dc369b127), untyped mixing refactor (06f7e655d1). Left open: nothing noted. - Go 1.17 — Done: the
go/constantswitch (742c05e3bc,7d72951229,259fd8adbb,6a4739ccc5); types2 limits integer precision to 512 bits then 2048-bit overflow error (370e9f5843,a59cb5109d) and compiler refuses excessively long constants (c910fd7b77). Left open: old typechecker still folds viair.ConstExprnodes.
Language version gating (-lang) and language changes implemented in the frontend
Span: Go 1.12 → Go 1.17 · Status at go1.17: -lang enforced by both checkers (old typechecker and types2) with errors naming the required version → continues as Per-file language versions and version gating (1.18+) and Frontend support for new language features and spec changes (1.18+)
Earlier history: Language changes and rules as implemented in the compiler (Go 1.1 → Go 1.9)
- proposal #28221 cmd/go, cmd/compile: record language version to support language transitions referenced by 1 of this thread's commits
- design doc Proposal: Go 2 transition Ian Lance Taylor · linked from #28221
- tracking issue #31793 go/types, types2: provide configuration support for different language versions referenced by 3 of this thread's commits
Design. Go 1.12 added -lang to the compiler (2e9f0817f0) so the go command can pass the go.mod language version; first just a check that type aliases need go1.9. Corrections: correct validation (7ebe35093d) and “by default accept any language” so the bootstrap compiler isn’t limited to 1.4 (69397422c0). Features then check -lang: Go 1.13 number literals, shifts, _ separators (762953be28); 1.14 overlapping embedded interfaces (8d4b685ab5 allow, 97edf77903 refactor expandiface, 7f907b9cee require -lang=go1.14); better error text (27fc32ff01); restrictions not applied to imported packages (b7d097a4cf). Go 1.16 //go:embed needs go 1.16 in go.mod (0575e35e50). In 1.17 types2 got the same: 1ff2fdaaf1 (checks), 721488498a (pass -lang), f37b0c6c12 (alias requires go1.9), ddec18cf82 (overlap requires 1.14), a9705e157b (slice-to-array-pointer conversion needs 1.17), 962d5c997a (unsafe.Add/unsafe.Slice need 1.17 in both cmd/compile and go/types).
Language changes realised in the frontend: Go 1.13 numeric literals and signed shift counts; Go 1.14 overlapping interface embedding; Go 1.15 print/println(f()) with multi-value f (af686da46f); Go 1.16 //go:embed (8bde9b320e — the go command passes an “embed config” mapping patterns to files; the compiler lays out contents as static data of type embed.FS, string or []byte; later restrictions 54198b04db no embedding of function-local vars, ec9470162f any string or byte slice type); Go 1.17 unsafe.Add and unsafe.Slice (fadad851a3, with 4bb0847b08 making unsafe.Slice((*T)(nil), 0) return []T(nil)), slice-to-array-pointer conversion (5f1df260a9, a9705e157b), and the shadowing rule that := may redeclare dot-imported names (1.10, f22ef70254). An earlier change allowed non-constant shifts as indices (088a9ad543).
Timeline.
- Go 1.10 — Done: user-visible
:=may shadow dot-imported names (f22ef70254), non-constant shift indices (088a9ad543),main.mainmust be a function (3c375f1b7e). Left open: nothing noted. - Go 1.12 — Done: user-visible
-langflag2e9f0817f0, validity check7ebe35093d, default accept-all69397422c0;//go:linknameallows bodyless functions (ca3749230b). Left open: “no consistent support for changes made before 1.12” (2e9f0817f0). - Go 1.13 — Done: user-visible go1.13 features guarded by
-lang(762953be28);internal/goversionintroduced (64e29f94e2). Left open: nothing noted. - Go 1.14 — Done: user-visible overlapping interfaces
8d4b685ab5,7f907b9cee;-langnot applied to importsb7d097a4cf. Left open: nothing noted. - Go 1.15 — Done: user-visible multi-value
printargsaf686da46f. Left open: nothing noted. - Go 1.16 — Done: user-visible
//go:embed8bde9b320e,ec9470162f,54198b04db,0575e35e50. Left open: nothing noted. - Go 1.17 — Done: user-visible
unsafe.Add/Slicefadad851a3,14056d0d00,962d5c997a,4bb0847b08; array-pointer slice conversion5f1df260a9,a9705e157b; types2 language-version support1ff2fdaaf1,721488498a,f37b0c6c12,ddec18cf82. Left open: version checks are per compilation, not per file (the go:build-based per-file model arrives in 1.21).
Package initialization order, static initialisation and init functions
Span: Go 1.10 → Go 1.17 · Status at go1.17: spec-compliant init order (initorder.go), static maps/slices/structs emitted as data where possible, fninit earlier → continues as Static initialization and package init (1.18+)
Earlier history: Static initialization, composite literals and init (Go 1.1 → Go 1.9)
- motivating issue #22326 cmd/compile: incorrect package initialization order for spec example referenced by 3 of this thread's commits
Design. The classic algorithm for ordering package-level variable initialisation did not match the spec (issue 22326). Go 1.13 rewrote it (5d0d87ae16): dependency graph over variables and functions (references via function bodies), emission in spec order, and cycle diagnostics that include referenced functions “like go/types does”. The reporting algorithm later exploded exponentially on real programs (explores all paths through call graph; 600x slower than Go 1.12, 2+ minutes for a 7,000-line program), fixed in 1.16 (6598c65646). In 1.17 the logic was reworked again by moving the init pass earlier: fninit is called earlier (f4936d09fd), 68e6fa4f68 fixes package-initialization order after the IR change, 7fde0d2b50 removes Initorder/Offset Node fields used by initorder, and pkginit becomes its own package (3d8a3cb06b).
Static init (sinit.go): 1.13 turned its functions into methods over InitSchedule (ee2836048c, d23bf3daa9), map literals are evaluated incrementally rather than by evaluating all keys then all values into temporaries (ee59c06acb) with static entries only (85387aa364), sparse slice literals initialized dynamically (6fff980cf1, 1.12), static copy fix (4a1a783dda: staticcopy of struct/array should recurse into itself, which had duplicated slice backing arrays since Go 1.2), blank struct fields not initialised (2693b42466, 0031fa80a3, 0f47c12a29), and avoiding statictmp collisions with user vars (08831b150c). Go 1.14-1.15 refactor slice symbols into slicesym and delete gdata (7096b1700d, 0a18cbc2e6, 12d1c9b863) and mark static arrays noalg (2222e0601a, 54cbb6b0c2). Go 1.12 hides compiler-generated init functions in tracebacks by treating them as wrappers, splitting variable initialisers into a separate non-autogenerated function to preserve line numbers (eafe9a186c; ~0.2% bigger go binary); 1.13 reverted a related runtime ordering change (6105e8b419). Earlier: improved static map initialisation in 1.10 (91cb9edd5e) and saved escape info for map literals (098126103e).
Timeline.
- Go 1.10 — Done: static map initialisation (
91cb9edd5e),098126103e, map creation with small hints (fbfc2031a6,06a78b5737). Left open: nothing noted. - Go 1.12 — Done: sparse slice literals (
6fff980cf1), static copy fix (4a1a783dda), hidden init in tracebacks (eafe9a186c), earlyinitsymbol (b52db19b98). Left open: nothing noted. - Go 1.13 — Done: user-visible spec-compliant init order
5d0d87ae16; incremental map initee59c06acb;sinitas methods (ee2836048c,d23bf3daa9);isStaticCompositeLiteralfix (004fb5cb8d); static entries of slices (a9e107c85c). Left open: nothing noted. - Go 1.14 — Done: static temporaries not used for small slice literals (
77f5adba55) or string vars (c33d45a898). Left open: nothing noted. - Go 1.15 — Done: slicesym refactor and
gdatadeleted (7096b1700d,0a18cbc2e6,12d1c9b863), static arrays markednoalg(2222e0601a,54cbb6b0c2), blank fields not emitted (0f47c12a29). Left open: nothing noted. - Go 1.16 — Done: exponential init-cycle reporting fixed (
6598c65646),fninitcalled earlier (f4936d09fd, with237410547bmaking funchdr/funcbody save and restore arbitrary Curfn/dclcontext). Left open: nothing noted. - Go 1.17 — Done: initorder state off Nodes (
7fde0d2b50),68e6fa4f68,pkginitpackage (3d8a3cb06b), blank var ICE (983ac4b086),ONAMEOFFSETfor static addresses (c76be2a24e),LinksymOffsetExpruse (99a5db11ac,4c835f9169), dynamic export of writable static temps (7a1e963058), lookup of redeclared dot-import symbol (c1cc9f9c3d). Left open: nothing noted.
Concurrent compilation and frontend performance
Span: Go 1.10 → Go 1.17 · Status at go1.17: backend compiles functions concurrently via the compile queue; frontend is serial → continues as Compile-time performance, concurrency and the self-PGO’d compiler (1.18+)
Earlier history: Compiler performance, formatting and concurrency (Go 1.7 → Go 1.9)
Design. Concurrent backend compilation arrived in 1.9; in this range it is completed. fa3e9d27f3 (1.11) removes the serial path for autogenerated functions (“as of this CL … no functions are compiled serially”), a particular win for packages with many short generated functions (e.g. benchjuju). cc90e7a51e (1.17) always uses the compile queue. c274a7c03b limits noder goroutines (1.17). The frontend remains serial except for parsing, so heavy-lift reductions are memory and algorithmic: sorting method sets earlier so that interface satisfaction is O(N+M) instead of O(NM) (91bbe5388d), noder scope-marker optimisation (3fca7306f4), file-handle throttling with EMFILE/ENFILE limits (99414a5b1d), duplicate inline body discards (f0b3626904), type printing buffer pooling and string interning because earlier uniquified deep type names regressed memory 3-5% and CPU 1-2% (2248fc63ab, 5d8a61a43e, f77e7ed7e3), symbol formatting with bytes.Buffer (211ee9f07c), types.sconv optimisations (b003a8b1ae, 11f5df2d67, 5c59e11f5e), -smallframes diagnostic flag (037ac2bd84: stack-allocation threshold from 10M to 128k for declared variables, 64k to 16k for implicit allocations).
Timeline.
- Go 1.10 — Done:
99414a5b1d,f0b3626904,506386fd37. Left open: autogenerated functions serial. - Go 1.11 — Done:
fa3e9d27f3concurrent for all;91bbe5388d;3fca7306f4. Left open: nothing noted. - Go 1.13 — Done:
-smallframes037ac2bd84. Left open: nothing noted. - Go 1.14 — Done: type-printing perf (
2248fc63ab,5d8a61a43e,f77e7ed7e3),33fac9bad8,3ad350820dsize diagnostic in benchmark format. Left open: “addresses some, but not all, of the CPU time regression” (f77e7ed7e3). - Go 1.15 — Done:
211ee9f07c. Left open: nothing noted. - Go 1.17 — Done:
cc90e7a51e,c274a7c03b,b003a8b1ae. Left open: nothing noted.
Directives and pragmas in the frontend (//go: handling)
Span: Go 1.10 → Go 1.17 · Status at go1.17: pragma handling is an interface between syntax and the noder with misplacement diagnostics → continues as The syntax package (parser, scanner, tree) (1.18+)
Earlier history: Pragmas, directives and compiler flags (Go 1.1 → Go 1.9)
Design. //go:linkname’s second argument became optional so a symbol can be exposed (e.g. ABI0 wrappers for assembly, non-static in gccgo) without renaming (dde7c770ef). //go:cgo_import_dynamic permitted anywhere (41d3d153eb), cgo directives encoded as JSON between compiler and linker (8f6ae33796). 768201729d (1.15): syntax gives the noder an interface{} pragma, and the noder reports “misplaced compiler directive” if a directive sits where it has no effect (must be on a line by itself immediately before the declaration). //go:notinheap evolved: write barrier omission for []T (3a446d8652, 1.10), alias to notinheap types allowed (4f915911e8), friendlier cgo message (37f261010f), implicit propagation to containing types (22053790fa), exported to object file (a9c75ecd3d), pointers stored indirectly in reflect/interfaces (009d714098, 091257def9). //go:nocheckptr and //go:nosplit (80a6fedea0, 9979366e07) interact with checkptr; //go:registerparams was added as a limited pragma for ABI development (861707a8c8) and pragmas propagate from generic to stenciled functions (083a26c7d2).
Timeline.
- Go 1.10 — Done:
3a446d8652,8554fd6e7d(reserved import paths documented),41d3d153eb1.11 (1.11). Left open: nothing noted. - Go 1.11 — Done:
8f6ae33796,41d3d153eb. Left open: nothing noted. - Go 1.13 — Done:
dde7c770ef. Left open: nothing noted. - Go 1.15 — Done:
768201729d. Left open: nothing noted. - Go 1.16 — Done:
4f915911e8,37f261010f,22053790fa,a9c75ecd3d,009d714098,8bde9b320e. Left open: nothing noted. - Go 1.17 — Done:
861707a8c8,083a26c7d2. Left open:registerparamsis limited to development.
Inlining-related frontend work: export of bodies, type switches, closures, devirtualization
Span: Go 1.10 → Go 1.17 · Status at go1.17: inliner handles type switches, method values and (re-enabled for the new export format) closures with limits → continues as Old typechecker and IR node-model cleanup (1.18+)
Earlier history: Inlining (Go 1.1 → Go 1.9)
- proposal #19348 cmd/compile: enable mid-stack inlining referenced by 1 of this thread's commits
- design doc Proposal: Mid-stack inlining in the Go compiler David Lazar, Austin Clements, 2017-03-10 · linked from #19348
Design. Inline bodies are the main reason export data is large. 1.10: limit exported inline bodies (8684534321, f0b3626904), and -l=2’s debugging role of eagerly typechecking unused inline bodies becomes -d typecheckinl (7092a312e5). 1.11: Inline struct separated (562a199961) and unneeded interface-method-expression wrappers omitted (80bbad015d). 1.12: autogenerated (*T).M wrappers inlined (fa913a36a2: encoding/binary −22%, bufio WriterFlush −11%), which restored perf lost between 1.10 and 1.11. 1.15: mid-stack inlining allowed in recursion cycles, tracking functions already inlined at a call site (ed7a8332c4); -d optimizer logging for inlining events (4d0ed149ff). 1.16: OCALLPART inlining (8fe372c7b3), type switches inlining with export/import (5736eb0013, using the iexport Vargen mechanism for per-case variables), early devirtualization of interface method calls (5cc43c51c9). 1.17: closures export (see export thread) with temporary disabling (8027343b63), ImportedBody flag to avoid creating new closure functions when typechecking inline bodies (06b86e9803), inlining of stenciled functions (6d2a557a4d), field tracking panic fix replacing map by Node.Opt (5b0ec1a6ac).
Timeline.
- Go 1.10 — Done:
8684534321,7092a312e5. Left open: nothing noted. - Go 1.11 — Done:
562a199961,80bbad015d. Left open: autogenerated wrapper inlining unsafe with iexport. - Go 1.12 — Done:
fa913a36a2. Left open: nothing noted. - Go 1.15 — Done:
ed7a8332c4. Left open: nothing noted. - Go 1.16 — Done:
8fe372c7b3,5736eb0013,5cc43c51c9. Left open: “inlinable type switches are probably too uncommon to” optimise their variable encoding (5736eb0013). - Go 1.17 — Done:
06b86e9803,8027343b63,6d2a557a4d,5b0ec1a6ac1.16. Left open: inlining functions with closures disabled “for now” (8027343b63).
The legacy typechecker: error quality, alias/recursive-type handling and type checking order
Span: Go 1.10 → Go 1.17 · Status at go1.17: still the authoritative checker outside -G; heavily incrementally improved → continues as Old typechecker and IR node-model cleanup (1.18+)
Earlier history: Typecheck/walk separation and package-level declaration order (Go 1.0 → Go 1.0)
Design. Two threads of work: incremental message improvements and bug fixes, and attempts to make declaration processing sound. Messages: assignment mismatches (b77d9fe0ea, f7a633aa79, ae9c822f78, 60736733ec), struct literal hints (5f29a7a705, 25d22d9aba, ae37f5a397, 6d781decad), shadowed builtins (1e308fbc1a, 4a095b87d3), ambiguous selectors (3d501df441), embedded fields (42ecf39e85, 5538ecadca, 6761b1eb1b), variadic misuse (a7af474359, cd47e8944d, df73945fd2, fd4b587da3, 844e1fc6f1), “cannot assign” reasons (7ee35cb301), &&/|| operands (23573d0ea2), typekind in invalid operation (754776850a), untyped operation (785a8f677f), make args (ad0ab812f8), unexported name once (d3f6e2f300), and Go-1.18-style “terminate compilation if type-checking fails” (d159d6108c). Error-column fixes: label redefinition (0b63086f64), composite literal key position (363bcd7b4f).
Declaration ordering: 9ce87a63b9 (typecheck types and funcs before consts so consts like I(T{}) see methods) was reverted in 1.12 (70dd90c4a9); 62c52a5ee1 simplifies typecheckdef; 1.14 a71967e4c5 replaces copytype by setUnderlying, 380ef6b759 simplifies defer/resume checkwidth, b136267b87/e87fe0f1f5 handle n.Type.Nod, 97bc039c9c emits an error for broken types. Alias cycles: correct detection (48987baa09), then work-around reintroduced for cyclic alias declarations (e6305380a0, “the more general problem remains”, issue 25838), crash on recursive types/interfaces (bb2f0da23a, dc0388c565, 7f3313133e, 25159d3af9), 0e85fd7561 reports a type loop for invalid recursive types (1.16) and c216ae80c9, dadfc80bc1 (findTypeLoop), plus “typecheck set correct untyped type” etc. Typechecking cleanups of Go 1.17: do not set type for OPACK/OTYPE/OTYPESW/ONAME-in-type-context (12a405b96a, 4b8b2c5864, 51d8d351c1, c082f9fee0), fbee173545, 1d0256a989, c9f43507c6, 9e6b1fcd0a, 70b277cf2e, 80098ef00c — all needed by the types2-driven noder.
Timeline.
- Go 1.10 — Done:
d05a1238d6,bb2f0da23a,25159d3af9,b77d9fe0ea,5f29a7a705,efa9efe8e4. Left open: nothing noted. - Go 1.11 — Done:
48987baa09,d159d6108c,c65a2781be,7b177b1a03,950a56899a,b3f00c6985,3d501df441,1e308fbc1a. Left open: nothing noted. - Go 1.12 — Done:
e6305380a0,62c52a5ee1,a37d95c74a,5538ecadca,6761b1eb1b,e25823edce(typecheck tracing). Left open: “the more general problem remains” for alias cycles (e6305380a0). - Go 1.13 — Done:
dc0388c565,4145c5da1f,60736733ec,6d781decad,bea58ef352. Left open: nothing noted. - Go 1.14 — Done:
a71967e4c5,97bc039c9c,047141797c,c302785df9,efd395f9fb. Left open: nothing noted. - Go 1.15 — Done:
7cbee12444. Left open: nothing noted. - Go 1.16 — Done:
0e85fd7561,c216ae80c9,7ee35cb301,dc59469f51,ad0ab812f8,d3f6e2f300,0dc369b127. Left open: nothing noted. - Go 1.17 — Done:
12a405b96a,4b8b2c5864,51d8d351c1,c082f9fee0,0c1a899a6c,785a8f677f,fd4b587da3,dadfc80bc1. Left open: checker remains legacy for non-generic code.
Lowering in order/walk and the shape of runtime calls emitted by the frontend
Span: Go 1.10 → Go 1.17 · Status at go1.17: the frontend lowers many constructs to specialised runtime calls; some previously frontend work moved to SSA construction → continues as Method wrappers and promoted-method sharing (1.18+) for wrappers only; otherwise no direct continuation
Earlier history: Walk-level lowering and runtime-call optimisations (Go 1.1 → Go 1.9)
Design. The frontend’s order/walk rewrites high-level constructs and decides the runtime call signatures. 1.10: makechan/makemap called with int arguments where possible to avoid int64 conversions on 386 (8a6e51aede, cbc4e5d9c4), small-hint map creation (fbfc2031a6: if hint <= BUCKETSIZE only hash0 initialised, and a makehmap heap helper; godoc −36kB), race calls for pointer-free types (53c8be4a8d), needwritebarrier removed from the frontend (e0111bb0f4). 1.11: select open-coded into selectsend/selectrecv/selectdefault (004260afde, with runtime 3aa53b3135, 6658219b7e), range loops no longer produce a past-the-end pointer (837ed98d63), map-clearing range idiom to a single runtime call (aee71dd70b: not for key types with NaN), len([]rune(s)) (b9a59d9f2e), convT2E/I taking integers by value (22ff9521da) then strings/slices by value (0e9f8a21f8) and shrunk call sites (5848b6c9b8), order.go refactored into methods (26708439ec), temp reuse in order (389e942745, 63e964e174, 240a30da1b), makeslice callers (020a18c545). 1.13: f(g()) multi-value rewrite moved to typecheck (d96b7fbf98, redone as c0cfe9687f after crypto/ecdsa -l=4 and net/http/pprof -N regressions) so the rest of the compiler no longer handles multi-value calls outside OAS2FUNC; callnew ported to SSA conversion with a new op (23b476a3c8); inline checknil (1e58bb1491); better write-barrier removal for new objects (ca36af215f). 1.15: make+copy fused to makeslicecopy (6ed4661807), staticuint64s replaces staticbytes (19ed0d993c), pass only ptr+len to runtime calls (b6feb03b24), isSmallMakeSlice checks cap only (7b30a2d268). 1.16: unified reflect/string/slice copy (790fa1c546). 1.17: selectnbrecv returning two values (4048491234, 86deb459de), assert{E,I}2I calling conventions (e52149822b), interface conversion function selection made ABI-insensitive (cf148f3d46, 49e933fc57), racefuncentry via getcallerpc and gorecover via getcallersp (a22bd3dc73, fb03be9d55), multi-valued a, b = f() through temporaries when types differ (3249b645c9, 326ea438bb), HasCall replaced by walk.mayCall (78e5aabcdb), closures transformed in walk (41352fd401), earlier deadcode before addrtaken (6ddbc75efd).
Timeline.
- Go 1.10 — Done:
8a6e51aede,cbc4e5d9c4,fbfc2031a6,e0111bb0f4,53c8be4a8d,5a4b6bce37. Left open: nothing noted. - Go 1.11 — Done:
004260afde,837ed98d63,aee71dd70b,22ff9521da,26708439ec,dcaf3fb134,2dbf15e88e. Left open: nothing noted. - Go 1.12 — Done:
0e9f8a21f8,5848b6c9b8,389e942745,020a18c545. Left open: nothing noted. - Go 1.13 — Done:
d96b7fbf98/c0cfe9687f,23b476a3c8,1e58bb1491. Left open: nothing noted. - Go 1.14 — Done:
ac1d440ea6,c33d45a898. Left open: nothing noted. - Go 1.15 — Done:
6ed4661807,19ed0d993c,b6feb03b24. Left open: the “s must be a variable” restriction of6ed4661807. - Go 1.16 — Done:
790fa1c546,82c45eb681. Left open: nothing noted. - Go 1.17 — Done:
4048491234,e52149822b,cf148f3d46,49e933fc57,3249b645c9,326ea438bb. Left open: nothing noted.
checkptr instrumentation and compiler debugging flags
Span: Go 1.12 → Go 1.17 · Status at go1.17: -d=checkptr implied by -race/-msan; Debug is a struct → continues as Compiler debugging infrastructure: bisect/hash debugging, flags, dumps (1.18+)
Earlier history: Race detector and sanitizer instrumentation in the frontend (Go 1.1 → Go 1.7)
- proposal #22218 proposal: add GOEXPERIMENT=checkptr referenced by 2 of this thread's commits
- tracking issue #34972 all: get standard library building with -d=checkptr referenced by 3 of this thread's commits
- motivating issue #34964 cmd/compile: enable -d=checkptr as part of -race and/or -msan? referenced by 2 of this thread's commits
- discussion Dynamic unsafe pointer checking available at master golang-dev · linked from #34964
Design. -d=checkptr (80a6fedea0, 1.14) inserts runtime checks that (1) conversions of unsafe.Pointer to *T are aligned for T, and (2) pointer arithmetic results point into the same Go heap object as one of the unsafe.Pointer operands. Disabled in runtime and by //go:nocheckptr; follow-ups recognise (*[Big]T)(ptr)[:n:m] (7b58581a23), disable it for cgo_unsafe_args and nosplit functions (8c6876e9a4, 9979366e07), enable under -race/-msan (dded58760d; 87a3ac5f53 lets explicit -d=checkptr=0 win), enable on Windows (656f27ebf8), fix &^ handling (e94544cf01). Debug flags: Debug becomes a struct instead of a 256-entry ASCII array (3bac5faa4a), -d=dumpptrs (c31540364c), -d=typecheckinl (7092a312e5), open-coded defer toggle (e617b2b0dd), -clobberdead resurrected (8628bf9a97, “TODO: make it GOEXPERIMENT?”), typecheck tracing (e25823edce), -W printing fixes, GOSSAFUNC cached (e34f660a52), obsolete flags removed (3e428363c4 -s, c68e3bcb03 -f, 5185744962 safe mode, eliminate -abiwraplimit feb844f1ea), GOEXPERIMENT check fix (bd983a6d2e).
Timeline.
- Go 1.10 — Done:
7092a312e5,bd983a6d2e,f3d4ff7ddc. Left open: nothing noted. - Go 1.12 — Done:
e25823edce,e34f660a52,c68e3bcb03,5185744962. Left open: nothing noted. - Go 1.14 — Done: user-visible
80a6fedea0,dded58760d,7b58581a23,8c6876e9a4,9979366e07;3e428363c4. Left open: nothing noted. - Go 1.15 — Done:
656f27ebf8. Left open: nothing noted. - Go 1.16 — Done:
e94544cf01,3bac5faa4a,c31540364c. Left open: nothing noted. - Go 1.17 — Done:
87a3ac5f53,e617b2b0dd,8628bf9a97,feb844f1ea,b60a3a8cfb. Left open:clobberdeadTODO.
Types package internals and type printing
Span: Go 1.10 → Go 1.17 · Status at go1.17: types hosts type constructors, size computation and printing → continues as Types package internals: size, algorithm kind, TFlag, SIMD flags (1.18+)
Design. 1.10-1.12: stringer for EType (6e9960ea63), HasHeapPointer recursive (316e3036a7), Type.NumResults (2dd1f87d38), TPTR merge (62e5215a2a), types.Identical extracted from gc (2d58fbac2f), Pkg/SetPkg (03f546eb60), Type.Val→Elem (2083b5d673), Funarg field removed (7500b29993), SubstAny copies all fields (9e619739fd: previously f and g with identical signatures shared a generated Result type so instantiating with different-size types corrupted offsets), SoleComponent (9892ccff23), documented internal fields (3377b4673d). 1.14: type name uniquing for really deep types (2248fc63ab) and recursive types printed correctly (5d8a61a43e); TDDDFIELD removed (a2cf16d42c). 1.12: nesting-depth limit for type descriptors increased (99e4ddd053). 1.16: TRESULTS variable-length SSA type (f554eb7bc3). 1.17: size calculation moved in (dac0de3748), constructors (77a71e0057, c10b0ad628), IsScalar (7e17b46c58), RParams (519f223aa2), allMethods (a4b8241d97), gcSizes.Sizeof zero-size struct (5cd8a34495), types.Sym function flag from 1.12 (16e6cd9a4d).
Timeline.
- Go 1.10 — Done:
2dd1f87d38,316e3036a7,f260ae6523,a53e853964. Left open: nothing noted. - Go 1.11 — Done:
2083b5d673,7500b29993,03f546eb60,6e9960ea631.10. Left open: nothing noted. - Go 1.12 — Done:
62e5215a2a,2d58fbac2f,9e619739fd,99e4ddd053,16e6cd9a4d. Left open: nothing noted. - Go 1.14 — Done:
2248fc63ab,5d8a61a43e,f77e7ed7e3. Left open: partial CPU regression. - Go 1.16 — Done: variable-length
TRESULTStype for SSA (f554eb7bc3),IsUintptr(518369601c). Left open: nothing noted. - Go 1.17 — Done:
dac0de3748(size calculation into types),a4b8241d97,519f223aa2,7e17b46c58,5cd8a34495. Left open: nothing noted.
Register-ABI plumbing in the frontend
Span: Go 1.12 → Go 1.17 · Status at go1.17: ABI wrappers generated per ir.Func, ABIs exported across packages → continues as Method wrappers and promoted-method sharing (1.18+)
- tracking issue #40724 cmd/compile: switch to a register-based calling convention for Go functions referenced by 10 of this thread's commits
- design doc Proposal: Register-based Go calling convention Austin Clements, 2020-08-10 · linked from #40724
- proposal #18597 proposal: cmd/compile: define register-based calling convention linked from #27539
- discussion Bug in new amd64 ABI golang-dev · linked from #40724
Design. 1.12: types.Syms for functions are flagged so obj.LSyms get the right ABI (16e6cd9a4d). 1.17: dev.regabi (the name came from the branch though the ABI work lives in another area) landed: cabffc199d internal ABI spec in the tree, 6f5e79f470 memory layout, ABI analysis utilities (89f38323fa), abiutils used for all receiver/in/out frame offsets (77973863c3), ABI info plumbed to ssagen (7a2f3273c5), function values reference ABIInternal (1e8fff0f7b), funcsyms tracked by ir.Name (33b4ffc357), ABI-wrapper restructuring storing ABIs on ir.Func rather than global maps with export across packages (67d565d281), ir.Name.Func set in more cases (0d1423583b), R14/X15 reservations documented (0ad46889a1, fcf8a6640b, 478277f812, 80ddc17ae1).
Timeline.
- Go 1.12 — Done:
16e6cd9a4d. Left open: ABI info not yet used. - Go 1.17 — Done:
cabffc199d,89f38323fa,77973863c3,67d565d281,1e8fff0f7b,33b4ffc357,0d1423583b,861707a8c8. Left open: nothing noted.
Changes in this slice that are not part of a thread are listed on the release pages: 1.10 · 1.11 · 1.12 · 1.13 · 1.14 · 1.15 · 1.16 · 1.17
Compiler frontend: the types2 type checker (Go 1.18–1.28)
Reader: Claude Sonnet. Cites 929 of 1,108 commits (all non-noise ones). Mechanism descriptions come from commit messages, not diffs. Some timeline bullets of the generics bring-up thread are thin.
Bringing up generics in types2 (type-parameter operands, core/structural types, tparam-as-interface)
Span: Go 1.18 → Go 1.28 · Status at HEAD: complete; core types no longer used by the checker (removed in 1.25), residual fixes only
Paths not taken: Generics implementations not taken: contracts parser, go2go, early stenciling demos (superseded)
Earlier history: Generics bring-up in the compiler (dev.typeparams): parser, -G, types2, irgen, first stenciling (Go 1.17 → Go 1.17) · types2 port of go/types: reviews, error-message parity and language-version support (Go 1.17 → Go 1.17)
- proposal #70128 spec: remove notion of core types referenced by 6 of this thread's commits
- proposal #60994 proposal: go/types: add func CommonUnderlying(Type) Type, (formerly CoreType) linked from #70128
- design doc Type Parameters Proposal listed in Go: A Documentary
Design. types2 is the compiler’s copy of go/types (same code, different AST: cmd/compile/internal/syntax). The 1.18 cycle is mostly the merge of the dev.typeparams branch, about 400 commits, most of them tiny. A *TypeParam is a type whose bound is a constraint interface. After the experiment 39bc666430 / c09d854f09 / 787708a6ff, the underlying type of a type parameter is its constraint interface (the internal tparamIsIface switch was first added disabled, then turned on, then the flag and the dead code were removed). Because of this, assignability had to special-case type parameters (56dcf97656, c88e3ff648).
Operations on operands of type-parameter type are checked over the whole type set rather than one underlying type. The first helper was optype(), later under/singleUnder; d611f09200 and its follow-ups replaced the asT converters with under. bbc059572d added singleType/structure, which became structuralType (8a3be15077), which became coreType/coreString (2bf5ae0c28). Builtins, range, slicing, composite literals, conversions, channel ops, delete, close, make, copy and append then accept type sets with a single core type: 2d205ebb96, c526cf8c1e, 12e4404a0a, 16318df4a2, ff33d3dc3a, 6511922a14, 5f0ea40c67, 95f8e64fc0, 93285c89d1, 0811108670, 39bbf08e71, a304273d74, 7e69c5decf, 4cc6a91907, cfcd71790f ([]byte|string slicing). underIs/typeset.is (3f1b0ce6bb) iterate type terms for the rest.
The last two points concern the end state. In Go 1.25 the checker stopped using core types: 7194caf11b, 6adf08f747, 4b1ac7bbfe, 26ba61dfad, 05354fc3b4, 7e81bcf39f, e5d3ece35d, and the replacement helper commonUnder (8b7e376e71, with an optional condition callback and an error cause that is only allocated on failure). commonUnder is a type-set-wide “all underlying types are identical” test. 1.24 had already moved underIs/coreType/coreString onto typeset iterators (1e5a72e980, 681751a1fe); 1.26 made typeset itself return an iterator (6b32c613ca).
Timeline.
- Go 1.18 — Done: user-visible full generic support in the checker. Ops on type-parameter operands (listed above). Constant conversion to a type parameter (
d39c873966,f9285818b6string conversion). Field access through struct core types (61014f00f2); this was disabled again in 1.19 (b8248fab891.19). Method calls on pointers to type parameters are rejected (18135150b0). Embedding a type parameter or a pointer to one is rejected (4ff0e04c2e,37d2219960).anyis accepted anywhere (1e57748892). Local defined types in generic functions are supported (1ba2074440). Thenomonocheck for infinite instantiation was ported (519c0a2323). Theimplements/Satisfiesmachinery was factored out (e08aae2ee4). Aliases to generic types were disallowed at first (68152359fd). About 45 further commits are error-message polish for type-parameter code, for example89cc528e43,283991bd7f,2639f2f79b,91edf2b7f2,3d3f5d912b. Left open: field access via core types, and an interface-typed operand switch for type assertions on type-parameter values (f9dcda3fd8makes it an error). Fixes in this period also report recurring infinite-recursion and “broken alias” gaps, tracked in the other threads. - Go 1.19 — Done: field access through type parameters disabled (
b8248fab89), because it was not part of the accepted semantics. Inference disabled for type instances (28fab5ef21). Fixes for composite-literal key duplicates with a generic key type (2138124143: numeric key values are mapped to the smallest numeric type that represents them, so0and0.0collide). Thecomparableoperand check, pointer base types and alias-to-constraint handling were adjusted (3a5e3d8173,3ebb1720d9). Left open: nothing noted beyond the follow-on threads. - Go 1.22 — Done:
27316739acfixes~[]Epassed to the unsafe builtins;6f87db509afixes a(*T)(nil)-to-interface conversion bug. Left open: nothing noted. - Go 1.25 — Done: removal of the checker’s use of core types (see Design). Left open: nothing noted.
- Go 1.26 — Done:
6b32c613camakes typeset return an iterator;0c14000f87removesunder(Type)in favour ofType.Underlying(). - Go 1.27 — Done: unconstrained type parameters in type-set ranges now yield
(nil, nil)and are handled inappend,copyandNewSignatureType(a6949e942c).674ceb7c7bfixes the conversion error for a pointer to a type parameter. Left open: nothing noted.
Type sets, union terms, interfaces and constraint satisfaction
Span: Go 1.18 → Go 1.28 · Status at HEAD: stable; comparable satisfaction by non-type-parameter interfaces since 1.20
Earlier history: Interfaces, type switches, assertions and comparability (Go 1.0 → Go 1.0)
- proposal #52509 proposal: spec: allow interface types to instantiate `comparable` type parameters referenced by 3 of this thread's commits
- proposal #56548 spec: allow basic interface types to instantiate comparable type parameters referenced by 2 of this thread's commits
- proposal #45346 spec: generics: use type sets to remove type keyword in constraints referenced by 1 of this thread's commits
- motivating issue #50646 spec: document/explain which interfaces implement `comparable` referenced by 2 of this thread's commits
- motivating issue #51257 spec: `any` no longer implements `comparable` referenced by 1 of this thread's commits
- design doc Type Parameters Proposal linked from #51257
Design. In 1.18 the representation of constraints changed three times within a few weeks of the dev.typeparams merge. First came embedded “interface elements” (5770d7a637). Then the Sum type was replaced by Union (589e32dbdf). Then 4b5fdb0b7a introduced the _TypeSet abstraction, computed per interface by computeTypeSet (fac21803ce); bba460499c stopped exporting it. A type set is a method set plus a termlist. term (2fa8f00915), termlist (e5fe769be1, bb5608dd5d) and ff0c0dbca6 (unions as terms) implement ~T and union intersection with explicit tilde handling. The bottom type was replaced by the empty union (848b58e473). 9bd1817e41 limits term-list lengths, 4cda05d41a externalizes union type sets and 1afa432ab9 records union types in Info.Types. comparable became a bit on the type set instead of a ==() method (c751e2e6ba). Embedded interfaces of the form ~T where T is defined or an interface are rejected (10d6b36ca3). The old type-list syntax was removed from the parser and checker (f05c67f182, 925ea2dfc4, 440b63bd6f).
Checker.implements (e08aae2ee4, 2e30c4b4bb, 25b4b862f2) is the one constraint-satisfaction predicate, used for both interface implementation and instantiation verification (155dc0e541, 8f0578ef39, eda3de0f79). Interface identity considers the full type set (dd8bdf4a1f). missingMethod was shared with go/types (d5bd3f9a6c, 7c9885def5) and simplified over the 1.18 and 1.21 cycles.
Timeline.
- Go 1.18 — Done: user-visible type-set based constraints as above. Strict
comparable: “does not satisfy comparable” is delayed until needed (a2004de088), and a “dynamic” flag on the comparable predicate distinguishes Go-comparability from static comparability (163da6feb5: an interface does not implementcomparable, because a component interface is only dynamically comparable). Further fixes:comparablemust not be visible before 1.18 (1cd505c353), “all interfaces implement comparable” tests (38729cff96),67dd9ee92c(empty type set for invalid~T),c3561dd346(comparable in union), union-cycle checks (13f3c57cef), delayed union element checks (c90ead97ad),4fea5935f5(real/imag/complexdisallowed on type parameters). Left open:848b58e473notes the intersection “does not always compute the largest possible intersection”. - Go 1.19 — Done:
0807986fe6and7dc6c5ec34(comparable in type-set intersection),35fb79be6a(overlap test for term lists),41fe746857(underlying type used in union computation),d4fb93be87(print|rather than a union symbol),269bf7e855and3507805bcd(better type-not-in-type-set / constraint-misuse messages),2ea9376266(split the “term cannot be a type parameter” message),86fa2551fb(parentheses around types in interfaces). - Go 1.20 — Done: user-visible new
comparablesemantics.5a3900b23cadded an alternative semantics underConfig.AltComparableSemantics(experiment, off by default).15e705ea96made it the default,2ca32a5b99reverted it, and8fd2875c3ereland it, with the flag renamedOldComparableSemanticsand inverted. The commit also adds the exported predicateSatisfies; the compiler flag-oldcomparablewas announced as temporary (“will be removed for Go 1.21”).642fd5f7ceuses strict comparability for type-set intersection. Other:f60c77026b(empty type sets in operand descriptions),0789ca4951(signature instantiation when all type arguments are given). Left open: the flag removal was announced in the message; no removal commit appears in this bucket. - Go 1.21 — Done:
b44f2222b5(methods considered when unifying a type parameter against its constraint) and the missing-method rework (09852e75ac,c10ba768fe,9f2fe2d721,2f9e38a1be,4ad72feb92,c6cdfdabefambiguity message). - Go 1.24 — Done: typeset iterators replace
is/underIs(1e5a72e980,681751a1fe). - Go 1.25 — Done:
commonUnderreplacescoreType(see previous thread). - Go 1.26 — Done: typeset returns an iterator (
6b32c613ca);1abc6b0204permits type cycles through type-parameter lists (the old restrictioncc14fcac2b1.18 from 1.18 existed only because of a type-inference deadlock, #49439, and type inference for generic type arguments had since been removed). - Go 1.27 — Done:
a6949e942chandles unconstrained type sets;1ca1b6e866substitutes receiver type arguments into method type-parameter bounds, soG[int].MwithP interface{~*T}is~*int(generic-methods work; the language sidee84da0405bis outside this bucket). Left open: nothing noted.
Instantiation, Named types, Context deduplication and lazy expansion
Span: Go 1.18 → Go 1.27 · Status at HEAD: Named has an explicit state machine, fromRHS/underlying lifecycle enforced since 1.26
- tracking issue #52728 go/types: guarantee that a finite number of distinct instances are reachable via the API referenced by 6 of this thread's commits
- proposal #47916 go/types: additions to support type parameters referenced by 2 of this thread's commits
- design doc Additions to go/types to support type parameters Rob Findley, Robert Griesemer, 2021-08-17 · golang/proposal
Design. A *Named is either a declared type or an instance of one. Instances carry an inst record (origin, type arguments, a Context) and are expanded lazily: the underlying type and methods are substituted via subst only when needed. 1.18 started with an instance helper type and InstantiateLazy, then merged instance and Named (473e493d18, 166b691b65, 3100f54f20) to avoid a sanitization pass. The public API settled as Instantiate(ctxt, orig, targs, validate) returning an error (fc27eb50ff, 69d8fbec7a, 22e9265467, c7e354d9d1), with an opaque Environment renamed Context (bd97763577, a1f6208e56, 99d5d8ab6b). Context dedups instances by a type hash (30e9bfbcef, 437362ccec, 489f58779c, 633d8c120b). Hash collisions are resolved with Identical (a52e4b9c7e, 313cae3861) and signatures are deduplicated as well (a17a21c190). TypeHash was exported, then unexported (9fc28892cb, 8b66b3d49f).
Methods of instances are instantiated lazily, and from b66bc0a9d5 each method is independently lazy through a methodList guarded by per-method sync.Once, because “method signatures can introduce a significant number of edges into the type graph”. Later versions replaced Named.once with a monotonic state field and Named.mu (846f971daa, 1323b0e8f0, 02e69cfa96). Named type identity stopped being canonical, so method-set computation looks up types by Identical rather than pointer (f088f4962e), and Var/Func objects got Origin() (1170771074). An invariant keeps instances created during expansion in the same Context as the expanding type, so infinite expansion chains terminate on a previously seen instance (47e34ca533, ensure that named types never expand infinitely).
Timeline.
- Go 1.18 — Done: user-visible
InstantiateAPI andContext(above). Methods are instantiated with the type (d1fd3eb40e),af80af22b5forbids new methods on instantiated types,73418bca34records all instances inInfo.Instances. Fixes for recursion:f2ed30c31e(recursive substitution must terminate),93b5309f0a(rename type parameters in self-recursive instantiation),ad99d8840e(invalid recursively expanding generic types),7520c080b4(SetUnderlyingsetsfromRHS),48ec6df16c(mutating an instance panics),186f375ecf(constructed type parameters are immutable),3c00a2839a(length mismatch is an error).2175e2f573added lazy import resolution for types2 (Scope.InsertLazy,NewTypeNameLazy,InstantiateLazy) for the unified-IR reader. Left open:2175e2f573says the sync.Once-based laziness is “fragile” and unification with the generic lazy-instance mechanism is possible. - Go 1.19 — Done: a type-lookup-by-identity fix for method sets (
f088f4962e),OriginforVar/Func(1170771074), expansion no longer infinite (47e34ca533,70668a4144), Named state simplified (846f971daa,1323b0e8f0,02e69cfa96,d5ae7a6487),1a2ca95ad2(instance context only set if packages match),43b09c096a(record all instances even duplicates). - Go 1.20 — Done: user-visible
ddd8bc1b07makes the instance lookup inLookupFieldOrMethoduse a small inline array before a map: −60% time and −99% allocated bytes on the microbenchmark, ~5% faster type checking of std packages with ~10% fewer allocations.0789ca4951instantiates signatures if all type arguments were provided.70f585f018marks invalid generic types invalid. - Go 1.21 — Done:
ac9137f8d3(NewCheckerdoes not mutate its arguments);1dd24d8216/2ce84c3a6einterface and missing-method fixes. - Go 1.22 — Done:
b6898dde3dinstantiated interfaces must be concurrency safe;d2ee7821d3no panic during interface completion. - Go 1.23 — Done:
7020beeffdoptimizes Named method lookup;210f051d6bdocuments the deterministic method order. - Go 1.24 — Done:
818515fd3eNamed.cleanuphandles aliases;91af7119cdforbids new methods on generic alias and instantiated types;2ad53d5a19forbids methods on cgo-generated types. - Go 1.26 — Done: a refactor of the type-declaration lifecycle by Mark Freeman.
1099436f1bdefinesNamed.fromRHSas the RHS type expression and setsNamed.underlyingonly once the underlying type is computed (before,underlyingcould temporarily point at another Named). Followups:4bdb55b5b8(Named.underbecomesresolveUnderlying),cf826bfcb4(set exactly once),39fd61ddb0(guarded byNamed.mu),b8aa1ee442/d09a8c8ef4(fewer locks),8401512a9b/9fcdc814b2/03bd43e8bbrename namedState values andresolvetounpack,b2af92270fverifies state-mask transitions in debug mode,d8a32f3d4b(wrapfromRHSintoNamed.rhs). The documented lifecycle also removes the package-levelunder(Type)function in favour ofType.Underlying()(0c14000f87). Also:7b53d8d06eadds aloadedstate between loader calls and constraint expansion, to fix a deadlock whenSetConstraintis called from a lazy loader that recurses back to the loaded type. - Go 1.27 — Done:
bdd2182ec5does not reuse declaredFuncs for expanded methods.3b00b08c44stashes the receiver on method selections to restore theInfo.Instancesinvariant that instantiatingUses[id].Type()withInstances[id].TypeArgsgives an equivalent ofInstances[id].Type.efddb5ac61user-friendly panics inInstantiate.183e201251sets underlying for imported types.
Type inference and unification
Span: Go 1.18 → Go 1.27 · Status at HEAD: new unifier-centred inference since 1.21; reverse inference, interface inference and untyped-constant defaulting shipped; assignment-context refinements in 1.27
- proposal #58650 spec: a general approach to type inference linked from #58671
- proposal #59338 spec: infer type arguments from assignments of generic functions (reverse type inference) referenced by 6 of this thread's commits
- proposal #58671 spec: type inference should be more lenient about untyped numeric literals referenced by 2 of this thread's commits
- proposal #60353 spec: when unifying against interface types, consider common methods referenced by 2 of this thread's commits
- motivating issue #57192 spec: interfaces that have different-size method sets never unify (but they possibly could) referenced by 3 of this thread's commits
Design. Function type inference infers missing type arguments from (1) typed function arguments, (2) constraints, (3) untyped constants’ default types. In 1.18 it had two entangled phases (function argument inference, “FTI”, then constraint type inference, “CTI”) around a unifier with per-parameter slots. Pitfalls were handled with local fixes: masks against infinite recursion (435718edd9, partly reverted by 5780be401f), renaming of type parameters when the call is self-recursive (93b5309f0a; made unconditional by e738a2f19b, because the heuristic for self-recursion was wrong when function literals clobbered the environment), and unification of core types for unbound type parameters (f03ab0e014, which has a kill switch enableCoreTypeUnification).
In 1.21 Griesemer rewrote it as infer2 (683b2c4600), made the only implementation by 93f5335be9 and 969c3ba839 (“use new type inference algorithm exclusively”), and deleted infer1 (d81ae7cfc7, 997dbcf6ba). The new algorithm uses one unifier holding a type parameter => type map; it is fed all facts, order-independently (8fd6cc8bb5 removes argument sorting): (1) unify every typed argument with its parameter; (2) unify each type parameter with its constraint’s core type (or, with 726d898c92 in 1.24, also its methods) iterating until fixpoint; (3) only as a last resort apply the default type of untyped constants; (4) substitute inferred types until no type parameters remain. Unification now has modes: assign for parameter passing (inexact at top level) and exact for component types (ee402e9882 removed the need for the recursion depth limit introduced for #59740). The unifier also detects no progress (4cba0bd74a), handles pointer identity (35a4d1b3bc), and uses a map instead of a type-parameter list (4b7f7eef3f).
Timeline.
- Go 1.18 — Done: user-visible function and constraint type inference with core-type unification (
f03ab0e014,5bd734839d); ~20 fixes: argument-order independence for named/unnamed (68b3d36ff4, disabled at first, enabled byb004c739b51.19 in 1.19), “do not run CTI before FTI” (3d3f5d912b),b00447038ashorter list for the 2nd FTI phase,bf0bc4122fperf (context string not re-evaluated per argument),9133245be7detect constraint-inference cycles,73a062c3e7recursive type-parameter constraints,3a07ab70a2inference of type instances (disabled again in 1.19 by28fab5ef211.19),5140ad104bupdate the recorded function type after inference,9284279b44useIdenticalrather than unification inmissingMethod,eab9a77a60defined-type unification fix. Left open:68b3d36ff4leaves order-independence disabled “pending decision”. - Go 1.19 — Done:
0807986fe6correct tilde handling in CTI (an imprecise~core type cannot determine an unknown type argument, but a known one must be unified against the underlying type; the whole loop is iterated untilunknownsstops decreasing).b004c739b5makes inference independent of parameter order. - Go 1.20 — Done: user-visible
0b323a3c16clearer CTI failure message;e738a2f19balways rename type parameters. - Go 1.21 — Done: user-visible the big inference release (proposals #58650, #59338, #60353, #58671).
683b2c4600(infer2),969c3ba839(exclusive use; two unifier tweaks: use underlying type when the other side is a type literal or basic type, and always continue with the core type for unbound type parameters). Reverse inference of generic function arguments in assignments (cc048b32f3, behindConfig.EnableReverseTypeInference; flag removed byfc106b016cwhen proposal #59338 was accepted), corrected to model the assignment as a single function-typed argumentg'(func(t1…))so parameter types must be identical (3367475e83, #60688). Generic functions as arguments (099f5a985fpermits partially instantiated functions,ea9097c9f7reverse inference for function arguments,8337ca094brename generic function arguments,13201d5728). Untyped constants: the minimum default type is inferred (3c3b1d39be, from proposal #58671) and2e4fe8bbf0removes the version check. Interface inference (#60353):c4afec232cand948f11b8a8unify against interfaces by shared methods,527d0e8a91reverted one attempt,6b7aab7750enabled it,1d3daebc5f/d49017a7c3/7183e77cc0fixes,d2db8267f4keeps inferring from constraints for-lang < go1.21. Smaller:a5350558e6exclude untyped nil early,d9dce0cd26check for nil targs,4cba0bd74a. Left open:c4afec232caddedEnableInterfaceInferenceas a config flag, later made internal; in 1.229070f270391.22 disables interface inference for versions before 1.21 after60dd8311031.22 reverted the constant removal. - Go 1.22 — Done:
1f8f2ab966removes order dependency with channels;f2f5979253correct parameter list in argument passing;51cb717d27no implicit modification of an argument function’s type;b34059032eno inference error for invalid arguments; error messages for reverse inference (2643a59172,0ac1e3b245). - Go 1.23 — Done:
e85968670ebetter error when inference fails in a call; alias handling in unification (ee29dbe43e,0d478d8e07). - Go 1.24 — Done:
726d898c92always infer over methods when the type argument is fully known (fix for #66751);0253c0f4acerror message change;7703db647ctracing. - Go 1.25 — Done: nothing substantive besides core-type removal (previous thread).
- Go 1.27 — Done:
f757de83f4fixes inference “irregularity in certain assignment contexts” by briefly permitting generic expressions betweengenericExprandassignment(removesexprWithHint);96bc97f6a3allows type-argument inference for map keys;3d4ee07f7ffails interface inference against generic methods (a generic method never satisfies an interface method). - Go 1.28 — Done:
49c3ea6464unification should never see nil types; target-type threading (see “Composite-literal elision” thread).
Generic type aliases and Alias type nodes
Span: Go 1.22 → Go 1.27 · Status at HEAD: Alias nodes always on (GODEBUG gotypesalias removed in 1.27); generic aliases enabled
Earlier history: Type aliases (the => experiment and type A = B) (Go 1.8 → Go 1.9)
- proposal #46477 spec: generics: permit type parameters on aliases referenced by 5 of this thread's commits
- tracking issue #67547 go/types, types2: audit type assertions for potential Alias bugs referenced by 8 of this thread's commits
- proposal #76472 remove gotypesalias, asynctimerchan GODEBUG flag for 1.27 referenced by 1 of this thread's commits
- tracking issue #65294 x/tools: get tests passing with GODEBUG=gotypesalias=1 referenced by 2 of this thread's commits
Design. type A = T used to bind A’s object directly to T. *Alias (an explicit node whose actual points to the RHS, resolved through Unalias(t)) makes error messages mention A, helps with cycles and is the only place type parameters of aliases could live. Every type switch must Unalias first, so a long tail of commits adds missing Unalias calls (816b6031fe, 4b778470f8, ca17bda856, 5ab8f90745, 8d464e4ae3, 13e3068b9c, 3ea2be1e47, 0d478d8e07, ccb6077d11). Cycles are resolved in three phases (a555ac6332 reverted to three-phase alias resolution after d186dde818). Generic aliases (1a6498e1cb, f294ddeb29, bf279b71e2) share type-parameter plumbing with Named via genericType (3c8f925606).
Timeline.
- Go 1.22 — Done:
bea55136b2introduces unexported_Aliasand_Unaliasbehind_EnableAlias; tests run in both modes (4346ba34df).30de0b5ef4exportsAlias/Unalias(proposal #63223) gated byGODEBUG=gotypesalias=1, off by default;acc8cb6a5fmarks the setting undocumented;8e658eee9cmakes the compiler calltypes2.Unaliasto prepare for it. Left open: unset default still meant no alias nodes; no generic alias. - Go 1.23 — Done:
15cec430d7flips the default togotypesalias=1in types2 (go/types had its own flip earlier in the cycle), though “the compiler still uses the non-default setting due to a panic” (9101bf1916controls creation viatypes2.Config).1a6498e1cbinitial parameterized aliases,f294ddeb29instantiation,4ed358b57erepresentsanyusingAlias,d68d485405gates alias type parameters onGOEXPERIMENT=aliastypeparams,bf279b71e2addsAlias.{TypeParams, SetTypeParams, TypeArgs, Origin},9b9de261bdaddsAlias.Rhs,13c49096fdrejects uninstantiated signature aliases,f1039180bdenables aliases for TestStdlib. Left open:1a6498e1cblists “instantiation of alias types” and API additions as missing at that point; the dev experiment remained. - Go 1.24 — Done:
9b4b4ae585fixes a named type instantiated with a generic alias (#68580),5a1de4ed34checks that alias type arguments satisfy constraints,e3cbda934cprints alias type parameters,91af7119cdforbids methods on generic aliases. - Go 1.26 — Done: alias handling folded into the type-declaration lifecycle (
1099436f1b). Also:d28b27cd8eusesnilrather thanInvalidfor incomplete explicit aliases, which also lets Invalid aliases be memoized. - Go 1.27 — Done:
6edb9f9c51removes thegotypesaliasGODEBUG flag (37 files, −619 lines),7239eead28traverses aliases in the completeness check,37bce6617falias tests.
Type declaration cycles, valid-type detection and the object path
Span: Go 1.18 → Go 1.27 · Status at HEAD: validType uses a type nest; setDefType removed and replaced by “pending” checks in 1.26; finite-size check at value observation
Design. Invalid recursive types (type T struct{ f T }, or generic types that expand infinitely, type T[P any] struct{ f *T[T[P]] }) are detected by validType (0328b4f4ca moved it to validtype.go). The 1.18 algorithm with a global typeInfo map was wrong; 07eca49055 replaced it by the type nest (the stack of embedding types), compares with Identical, tracks []*Named paths and caches valid types in Checker.valids (#52698). ad99d8840e kept infinite expansion from looping by working on origin types (it knowingly misses some invalid generic types, tracked as #48962). 83b2b47b5d fixes nest-slice overwrites (#66323). Declaration order and cycle detection moved from an object colour (object.color) to Checker.objPathIdx (ddd8558e61) in 1.26. 3531ac23d4 and ff2fd6327e replaced setDefType (which set T.fromRHS as soon as the top-level shape was known) by a check that no value of type T is used before its RHS is complete (#76383, #76384). 1274d58dac adds the finite-size check at value observation (delayed to the end of type checking unless used in unsafe.Sizeof), ffb50fb716/72c83bcc80 put it behind Named.mu as varSize, a977717393 extends it to map values.
Timeline.
- Go 1.18 — Done:
fe85c24431and671e1150c6add a stop-gap “broken alias” side table so the compiler does not crash on aliases that depend on incomplete recursive types (#50259 and others);2abfa30f9e,cc14fcac2b(disallow cycles through type-parameter lists),9062a5298b,ad99d8840e. Left open:fe85c24431says the correct fix “will likely require some form of forwarding type”;ad99d8840eleaves undetected cases (#48962). - Go 1.19 — Done:
07eca49055,fc97075949(simplify),7751883379,114d5deac2,70668a4144. - Go 1.23 — Done:
a66a3bf494tracing,9f9008ce66disable an incorrect optimization in validType,13e5fd95f5better position for infinite types,83b2b47b5d,d186dde818/a555ac6332alias cycles. - Go 1.24 — Done:
bdc6dbbc64,bfc8c5b85acycle error reporting;87023bb27fdeterministic init-cycle output. - Go 1.25 — Done:
5e7f0b947cinfrastructure to record declaration positions for panics (off by default);608e9fac901.26 (“flip on position tracing”, 1.26 by log) enables it after compilebench showed no significant change (geomean −0.77%). - Go 1.26 — Done: the lifecycle refactor (
1099436f1b,57362e9814direct cycles checked as a separate phase,1f4d14e493package-level object sort as its own phase,4fef9f8b55object path for grouped declarations,3531ac23d4,ff2fd6327e,c048a9a11f,1274d58dac). - Go 1.27 — Done:
a977717393,eb845eca72instantiated-cycle errors include type arguments,5fb2392a6f.
Per-file language versions and version gating
Span: Go 1.21 → Go 1.24 · Status at HEAD: Info.FileVersions; version computed per file from //go:build lines
Earlier history: Language version gating (-lang) and language changes implemented in the frontend (Go 1.12 → Go 1.17)
- proposal #57001 extended forwards compatibility for Go referenced by 1 of this thread's commits
- design doc Proposal: Extended forwards compatibility in Go linked from #57001
- proposal #56986 extended backwards compatibility for Go linked from #57001
- design doc Proposal: Extended backwards compatibility for Go listed in Go: A Documentary
- design doc Proposal: Go 2 transition Ian Lance Taylor · listed in Go: A Documentary
- tracking issue #63974 go/types, types2: switch to using go/version once we can use it in the compiler referenced by 2 of this thread's commits
Design. Before 1.21 the checker had one global Config.GoVersion. 804d786a30 makes both type checkers track a version per file: a file’s //go:build go1.N can lower its semantics below the module’s go 1.M only when M >= 21 (for compatibility with toolchains that never applied downgrades). Version checks go through Checker.allowVersion(at, v) and versionErrorf; errors for the same feature appear once per declaration. e59eaee2e3 adds Info.FileVersions and 56c91c0502 replaces the local version parser by go/version. 1fc45e9a2b makes types2.Info.FileVersions map to version strings.
Timeline.
- Go 1.18 — Done: user-visible
d3070a767b1.19 (“check go.mod” hint fortype parameter requires go1.18),242d02dd5e,3e41b18a46,eb3ac1f5a41.19 hint forany;1cd505c353hidescomparablebefore 1.18. - Go 1.21 — Done:
804d786a30,4f9a966926(fix version downgrade bug withoutConfig.GoVersion),ade3f3f5ef(check builtins even if there is a version error),b490bdc27drecordConfig.GoVersionforPackage.GoVersion. - Go 1.22 — Done: user-visible
e59eaee2e3(Info.FileVersions),1fc45e9a2b,12f3d6858edocs,6146a73d27range-over-int errors for version < 1.22,11677d983eenables it without GOEXPERIMENT,008ab9adb8fixes allowVersion for invalid pos. - Go 1.23 — Done:
8121604559do not fail fast on version errors,133c8fc9bbno version checks for embedded types of imported interfaces,5e00352b9bsingular wording,502347f121duplicate-method error in go1.13. - Go 1.24 — Done:
0b4ab20d2c(only use fileVersion if >= 1.21), reverted by2693f77b35, replaced byaeac0b6cbf(usemax(fileVersion, go1.21)if a file version is present),9b1f8f32b8(go/types: compute effective Go version independent oftoken.Pos). - Go 1.26 — Done:
06e57e60a7only report version errors ifnew(expr)is otherwise valid.
Language features as seen by the type checker (by release)
Span: Go 1.18 → Go 1.28 · Status at HEAD: generic methods (1.27) and string(int) restriction (1.28) are the latest; untyped composite literal inference in progress
Earlier history: Constants and multi-precision arithmetic (Go 1.0 → Go 1.0) · Builtins and unsafe (Go 1.0 → Go 1.0)
Design. Each language change lands in types2 and go/types together with new test cases in the shared internal/types/testdata/{check,spec,fixedbugs} and an operand-mode or builtin change. Many were gated through version.go feature tables.
Timeline.
- Go 1.18 — Done: user-visible generics (other threads);
1e57748892anyanywhere; type-switch/assertion improvements (cf51fb5d68,254c497e5c). - Go 1.20 — Done: user-visible
ba5deb408funsafe.String/StringData/SliceData(+ tests8c8429fe41);cd8aa40149slice-to-array conversions;5c834a2eb0clearbuiltin;f80b12667cinteger constant literal overflow check;5a3900b23c→8fd2875c3ecomparable. - Go 1.21 — Done: user-visible
8c37d486c8refuses pointer-to-array forclear(theclearbuiltin itself,5c834a2eb01.20, is in the 1.20 bullet);b5515eef56min/max(b3ca8d2b3crecords the final type for arguments;8abc6e25971.22 in 1.22 rejects untyped value arguments); reverse inference (inference thread). - Go 1.22 — Done: user-visible range over int (
11677d983e,5f949c4f2fconstant range expressions,25a59decd5). - Go 1.23 — Done: user-visible range over func:
e15cc7ab82iteration variables may be omitted,26ed0528c7error for floating-point iteration variable,4e77872d16,fd99157f9drefactor ofrangeStmtfor clarity; generic aliases (alias thread). - Go 1.24 — Done:
c9afcbade7requires iterator yield to return bool (work-around);8a4b439ee6adds a README.md. - Go 1.25 — Done: user-visible core types removed from the language spec: checker side in “Bringing up generics”; Parser-detected invalid
...(ad7b46ee4a). - Go 1.26 — Done: user-visible
a27261c42fnew(expr)(#45624; version gate inversion.go);06e57e60a7. - Go 1.27 — Done: user-visible
9f7e98d263promoted field names as keys in struct literals (#9859).710014bcc3adds a small generic trie (trie.go) to detect overlapping selectors in such literals.238d7bddebtheyieldfunction in range-over-func cannot be variadic. Generic methods:79cae3bd1a,3d4ee07f7f,1ca1b6e866(spec change ine84da0405b, which is outside this bucket).ed3ec75df4limits constant string addition to 10 GiB;d8cab4c45adisables the length check because go/constant avoids constructing string constants and the check would eagerly build them (“may need a new API”). - Go 1.28 — Done: user-visible
f095da59e4string(x)for integer x only permitted if x is byte or rune typed, or an untyped rune constant (“starting with Go 1.28”, #3939), withconstConvertibleTomade an operand method.
Composite-literal type elision via target types (#12854)
Span: Go 1.27 → Go 1.28 · Status at HEAD: in progress; targets threaded through assignments, calls, struct literals, sends, switch, delete/append/copy and comparisons
- proposal #12854 spec: type inferred composite literals referenced by 6 of this thread's commits
- proposal #77245 spec: function type inference should work in all assignment contexts referenced by 1 of this thread's commits
Design. To type untyped composite literals ({1, 2} with the type inferred from context), the expression-checking functions get a target that holds the assignment-context type. Before this, only function-typed contexts passed a target T (reverse inference) plus an exprWithHint/U argument. 17810c616f threads a composite-literal target through Checker.expr and relatives, 54539e7c9e reorders channel sends so the element type is known first, 39cc89aa11 adds the “check for composite literal type target” in literals.go. 8af6b7616d makes target hold the assignment-context type and removes the extra U; ef3608b90e uses it for hints (hint flag), fba9e4b2d0 deletes the remaining hint parameters; 48e387d5e0 adds tests that execute every newTarget/newHint call.
Timeline.
- Go 1.27 — Done:
96bc97f6a3(map-key inference “will be more relevant when implementing #12854”),f757de83f4. - Go 1.28 — Done:
17810c616f,54539e7c9e,c7abbff510,73bc5e8ef6(struct literals),c33ea07d92(function calls),d87b733482(target may hold any type),b0434e1e9a(target.sigreturns Type),f1220f3337(delete),08a51e4d9b(append),96ef5b334c(copy),205624aac7(switch),430d19f07a(comparing an untyped composite literal with a typed operand flows the other operand’s type in). Left open: both-untyped or neither-typed comparisons fall back to the usual mechanism (430d19f07a).
Method receiver checking
Span: Go 1.18 → Go 1.27 · Status at HEAD: receiver handled in collectRecv (1.24 rewrite)
Earlier history: Embedded fields, method sets and receivers (Go 1.0 → Go 1.0)
- tracking issue #51343 go/types, types2: simplify type-checking of method receivers with type parameters referenced by 5 of this thread's commits
Design. ea82219d1c (1.24) rewrites receiver checking: Checker.collectRecv analyses the receiver parameter manually; collectParams only collects names and variables and does not declare them; funcType becomes a linear sequence; the receiver and parameters are declared after type parameters so no temporary scope or Scope.Squash (removed) and no recvTParamMap is needed. unpackRecv strips only one *. Since parenthesized and pointer receiver expressions were no longer recorded in types, 86bec1ec19 records them (generic receivers), and 385e963e70 records receiver type parameters as Uses.
Timeline.
- Go 1.18 — Done:
c0840a7c72receiver tparam count must match,7c694fbad1delay receiver validation,a7d3a0e971identifier map for receiver type params,8cfbb58bc7removesSetRecvTypeParams. - Go 1.19 — Done:
9b90838712preserve parent scope when substituting receivers. - Go 1.24 — Done:
e0ca2e04b8,1b7285d1ab,ea82219d1c,86bec1ec19,385e963e70,b631b8e674error positions. Left open: the parser can optionally keep parentheses in type expressions (disabled by default, per86bec1ec19). - Go 1.27 — Done:
1ca1b6e866and3b00b08c44(see Named thread).
Error reporting: codes, messages, and sub-errors
Span: Go 1.18 → Go 1.28 · Status at HEAD: compiler and go/types share messages and error codes (internal/types/errors)
Earlier history: Diagnostics and error messages (Go 1.1 → Go 1.9) · types2 port of go/types: reviews, error-message parity and language-version support (Go 1.17 → Go 1.17)
- tracking issue #55326 go/types, types2: remove discrepancy between type-checker and compiler error messages referenced by 7 of this thread's commits
Design. Until 1.19 types2 printed gc-style messages when compilerErrorMessages was set and go/types printed its own. Go 1.20 removed this duality. f4a587ba6e gives every types2 error site an error code, 6688efd5df moves to the shared internal/types/errors package, 388fbf287c uses a zero code for “unset”, ad3ea0134f records the code in the Error struct, 5612215d32 removes compilerErrorMessages. Message wording was reconciled in about 20 commits: 2da95e0ec8 (“undefined: x”), 605148c0fb, 3b5188ed2c, 435652b468, dbe56ff6c7, 545adcfe89 (“generic” not “parameterized”), 22f4471599. 1.23’s 96e9838f39, 5e3c4016a4 separate formatting from error handling and call the handler for each sub-error. 1.25 added a typeError cause type (232dfd226b, 5af3658eaa) and rewrote messages for range, calls, send/receive, copy, make, slices and qualified identifiers (d45d502fbb, 549a88fa53, 584e631023, a4fcfaa167, 2d097e363a, a588c6fba6, ae4c13afc5, 5eaeb7b455).
Timeline.
- Go 1.18 — Done: ~60 message commits (e.g.
c25bf0d959types in mismatched call/return errors,cf5d73e8a2restore “too many return values” with have/want,b14fd720a8,e052044d6b,63e833154c,2e2ef31778append,8070e70d64). - Go 1.19 — Done:
d4fb93be87,73475ef035qualified names in cycle errors,f9747b7f73, test tweaks. - Go 1.20 — Done: user-visible unification of messages with go/types (above),
b52783c1e9,4a954fafa3,79d0d330a9(field with the name of a missing method),4b993bffb8,de0f4d190f(no unneeded error strings inimplements). - Go 1.21 — Done:
ad3ea0134f,1079a5c08abetter inference failure message;dbdb3359b5,c6cdfdabef; test-framework:5cd805c6dfdistinguishes substring vs regexp error patterns,3af3810a3e,d4639ecdfc. - Go 1.22 — Done:
58c28ba286avoid “have m(T), want m(T)”,0b3dd75f6cunexported missing method,25c5f6f159. - Go 1.23 — Done:
96e9838f39,5e3c4016a4,dc6a5cfca1quote user-supplied names,f81e498673better errors for non-existing fields or methods. - Go 1.24 — Done:
7d9802ac5equalify named types by kind (compositeKind),3dc146da7f,bfc8c5b85a,76f3e0ac8d,bcb934ad11. - Go 1.25 — Done: the rewrite listed above;
18ad74dd36dumps the position stack on non-bailout panics. - Go 1.26 — Done:
cae45167b7,532e320349(go/types: diagnostics for type shadowing). - Go 1.27 — Done:
2d37c20778field selected on type,803d53a53c,28279274c8. - Go 1.28 — Done:
28a19a0327consistent overflows/truncated messages;c8abe73eb7oversized non-constant shift counts (case ordering bug: the untyped-constant case was shadowed);cd46a98014,2c02670704.
Sharing code between go/types and types2
Span: Go 1.20 → Go 1.28 · Status at HEAD: most go/types files are generated from types2
Earlier history: types2 port of go/types: reviews, error-message parity and language-version support (Go 1.17 → Go 1.17)
- tracking issue #54511 types2, go/types: share tests referenced by 6 of this thread's commits
- tracking issue #69673 go/types: position-independent type checking referenced by 2 of this thread's commits
Design. types2 is the primary source; go/types files carry a // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. header. Testdata moved first: the three directories of .go2 / .src files (check, examples, fixedbugs, spec) were consolidated into one shared internal/types/testdata (bbaf0a514e, 9ad772033f, 17211c355f, 9649a4119c, 57ade1fd0b), after which tests are loaded by both checkers. Then production code: 1.21 factored platform-specific helpers into util.go (248950f192) so more files could be generated (9251822631 under.go, f52b8fa83f infer.go, d45df06663 object_test.go, 7da4675dad hilbert_test.go); 1.23 added generation of builtins, conversions, typestring, assignments, operand, mono, initorder, typeset (81609c454b, cc276a768f, 6c979d2522, 55bb3d1c10, f278f756bd, ff8a2c0ad9, 629a6f5ae0, 691f5b8e74); 1.24 factored literals and recording (0fb35efe5b, a17356cd23, 0fc3b127a0, 31e692be43, 1b6bb779ef), 1.25 range (8a7742e78c), and 1.28 union.go, sizeof_test, typestring_test, typeset_test and more (5040c0ac0c, 19533bd74e, a2306b638e, 16bdff37a8).
Timeline.
- Go 1.20 — Done: test-data consolidation (above) and
157aae6eedfor checker-specific local tests. - Go 1.21 — Done: first generated files and
util.go. - Go 1.23 — Done: eight generated files.
- Go 1.24 — Done:
0fb35efe5b,a17356cd23,0fc3b127a0;7ad9a2c65f; Scope methods5fe3b31cf8/80316510d3/6ad3933e28removing dependency onScope.LookupParent. - Go 1.25 — Done:
8a7742e78crange.go. - Go 1.28 — Done: the “remove tech debt” series (4 commits) plus
55f39ab788,0446ca4652,a89a200850,de246da3f3test cleanups. Left open: nothing noted.
Checker performance, memory and API ergonomics
Span: Go 1.18 → Go 1.28 · Status at HEAD: ongoing micro-optimizations driven by gopls and compilebench
- proposal #61035 go/types, types2: fix SizesFor("gc", ...) to match actual gc behavior referenced by 2 of this thread's commits
Design. A set of independent optimizations: fewer delayed actions (054710ce46, 1.18), 6b609110fd sorts to reduce the complexity of initOrder, bf0bc4122f avoids re-evaluating the call context string, c641d48afd uses lazyregexp for the version regexp (init −48% time, −29% bytes, GoTypes). ddd8bc1b07 (1.20, see Named thread). b2110bcdde/0592ce5f69 use strings.Builder. 9189921e47 (1.25) externalizes the used flag of Var and PkgName into two maps on the Checker: these were in the Objects, which raised memory per type-checked package and caused a data race (#71817) when objects were reused by CheckExpr/Eval. 8002a0da7c (1.28) adds Scope.Objects iterator and caches Scope.Names in an atomic pointer; 6446eeb686 records the Id in each MethodSet entry (NewMethodSet −27%, Lookup −69% to −73% for unexported names, 0 allocs). d6dc9d3ace makes Selection more compact, 522ebc8370 fixes a data race in Unalias on alias instances. 5fa4aac0ce/14a3ffc3d2 (1.22) add gcsizes.go so the compiler uses types2.Sizes and not its own struct-layout code (fixes #60431 and others).
Timeline.
- Go 1.18 — Done:
054710ce46,6b609110fd,bf0bc4122f,0a39e4a89dstructural-type fast path,b66bc0a9d5lazy methods. - Go 1.20 — Done:
ddd8bc1b07: LookupFieldOrMethod −60% time, −98.8% bytes on a microbenchmark;c641d48afd1.21 (1.21 by log). - Go 1.22 — Done:
5fa4aac0ce,14a3ffc3d2,832212df9a(compiler usestypes2.InitOrder),294e1b260e. - Go 1.25 — Done:
9189921e47andfe9b292b11(used maps allocated ininitFiles);4ac729283c/1cf6386b5e(interface methods not registered inInfo.Types, then reverted). - Go 1.28 — Done:
8002a0da7c,6446eeb686,eeaa094535parallel tests.
Robustness: invariants, incomplete types and importers
Span: Go 1.18 → Go 1.28 · Status at HEAD: invariant checker in tests; new types2 importer in progress
Design. b98d22c17f (1.28) adds checkInvariants to TestCheck and TestStdlib. It walks scopes, Info.Defs/Uses/Implicits/Types and asserts no nil Type(), *Func have *Signature, no nil components, accessors never panic, and Typ[Invalid] is only published if an error was reported (TestStdlib +~1 s total). de3b79e425 enforces it: Alias.Underlying, Rhs, TypeParam.Constraint panic on incomplete types, and the post-check cleanup normalizes incomplete types to Typ[Invalid], reporting an internal error if none had been recorded, so gopls and objectpath don’t hit nil pointers. 201f360765 invalidates operands after constant overflow so recording into unsafe.Pointer assertions can’t trigger. For importers: eff66248ea added package height (1.18, removed by 398d46d538), 2175e2f573 lazy resolution, 183e201251 (1.27) sets underlying for imported types, 8a856e477e (1.28) a new importer for types2 tests that builds with go build and reads the “u” export format, with ac059878bc pointing the tests at it.
Timeline.
- Go 1.18 — Done:
eff66248ea,2175e2f573,3db4888a05(types2.Unsafein gcimports),1b193598b3fail early ontypes2.Invalid. - Go 1.20 — Done:
398d46d538removes package height. - Go 1.27 — Done:
183e201251,8c4c897d0arepeat of an importer change for types2,efddb5ac61. - Go 1.28 — Done:
b98d22c17f,de3b79e425,201f360765,be104ed62f,8a856e477e,ac059878bc,49c3ea6464,6939463d82. Left open:8a856e477esays “a second CL will swap out the existing types2 importer for this one”.
Changes in this slice that are not part of a thread are listed on the release pages: 1.18 · 1.19 · 1.20 · 1.21 · 1.22 · 1.23 · 1.24 · 1.25 · 1.26 · 1.27 · 1.28
Compiler frontend: syntax, IR, unified IR and the generics implementation (Go 1.18–1.28)
Readers: Claude Sonnet, plus a Sonnet gap pass. Cites 1,326 of 1,551 commits (all non-noise ones). The gap pass grouped the 1.18 stenciler burst and later small commits by subject line, without reading each message.
Generics via GC-shape stenciling and runtime dictionaries
Span: Go 1.18 → Go 1.28 · Status at HEAD: shipped design since 1.18 (first built on the old typechecker/-G=3, reimplemented on unified IR in 1.20); shape sharing is still “underlying type, pointers collapsed”, with occasional shape/reshape bug fixes through 1.27
Paths not taken: Generics implementations not taken: contracts parser, go2go, early stenciling demos (superseded)
Earlier history: Generics bring-up in the compiler (dev.typeparams): parser, -G, types2, irgen, first stenciling (Go 1.17 → Go 1.17)
- design doc Generics implementation - GC Shape Stenciling linked from #50182
- design doc Generics implementation dictionaries Go 1.18 listed in Go: A Documentary
- design doc Generics implementation - Dictionaries listed in Go: A Documentary
- design doc Generics implementation - Stenciling listed in Go: A Documentary
- proposal #43651 spec: add generic programming using type parameters referenced by 1 of this thread's commits
- discussion Implementing Generics golang-dev · listed in Go: A Documentary
Design. A generic function F[T] is compiled once per GC shape, not once per type argument. A shape type (package go.shape, types.IsShape/HasShape flag) is the type argument’s underlying type; all pointer types collapse to a single go.shape.*uint8 shape. Shape types are named with a go.shape. prefix (b730a26729, 137543bb93), integer signedness is kept distinct because shift semantics differ (8767b87ab5), and since 1.22 the symbol uses a hash of the underlying type’s link string when that string would be absurdly long (8c1349baf7). The shaped instantiation takes a hidden first .dict parameter (7b876def6c added the dictionary argument, before the receiver). The dictionary is a read-only global [N]uintptr holding everything the shaped body cannot know statically: *runtime._type for every type derived from a type argument, sub-dictionary pointers for callees (ddb09af1b8, f503740ccf, 6dec18cc75), itabs for conversions to non-empty interfaces (02c0172500, ac3ba97907), and method-expression closures for calls through bounds (7fc38802e1, f326964824, fc72b7705d). F[int](...) becomes F[go.shape.int](&.dict.F[int], ...); the non-shaped F[T] is a wrapper.
Conversions of shaped values to interfaces, .(T) assertions and type switches use ir.DynamicType/ODYNAMICDOTTYPE (f4f503e0a3, ca3c6985cd, 0e2f1abf5b) so the type comes from the dictionary instead of the (shape) static type. Dictionary format is computed on the instantiated function after transforms rather than on the generic one (59a9a035ff), because the set of CONVIFACE nodes depends on which type arguments are interfaces. Instantiated functions are DUPOK so the linker drops duplicates (7160e32529), and dictionary/method-set survival under linker pruning needed explicit handling (2fe4b14795, 301f6c8019). DWARF carries dictionary entries (72bb8185b5), and ir.Name.DictIndex tells Delve where a derived-type local’s rtype sits in the dictionary (07cf24bdfe).
A non-obvious cost: the interface conversion the compiler inserts to call a method through a type-parameter bound would heap-allocate the data word for non-pointer-shaped types; e550c30545 removed that allocation (later reverted in 3f69cc7d77 when it proved wrong and replaced by method-expression closures stored in the dictionary).
Timeline.
- Go 1.18 — Done: Generics were first brought up on the old typechecker (
-G=3, types2 type-checks,noder/irgen+stencil.gobuild IR and substitute with a type substituter(*subster)). Export/import of generic types and function bodies (15ad61aff5,8e6dfe1b31, new export version7b3ee6102d,fd2f4b58b3,f90a42b410, kept the old format if no generics are exportedc2c1b53b39/40ba119e3f). Initially every distinct type-argument tuple was fully stenciled, then dictionaries were added (7b876def6c,bad388744b), then GC shapes (8767b87ab5,a7a17f0ca8,9b85985d36): same-underlying-type types share a shape (40e561d933), all pointers one shape (0b8a9ccb25), pointer-to-array and notinheap pointers separate shapes (d4e0e8e4a4,fcf6afb82d1.19 in 1.19), shapes live in their own package (b730a26729). Method-on-shape handling went back and forth (48cf96c256no methods on shapes,dfd875d015allowed without bodies). Generic code transformed lazily (6acac8b685“delay all transforms for generic funcs”), plus the generics/inlining interaction (931e84af40: only dictionaries and shape instantiations of types referenced by exported inline bodies need exporting, not the types) andde61465156/6fefb7f9f3(missing inline bodies became a graceful fallback).-G=3enabled by defaultc9912780ab;-lang=go1.18gates generic syntax2aea44204e. Left open:6fefb7f9f3says perfect identification of inlinable bodies is “much harder with generics”; the structure is duplicated in-G=3/unified IR paths.- Stabilization burst (about 250 commits, mostly by Dan Scales and Cuong Manh Le, grouped here): the
-G=3stenciler needed a long tail of mechanisms. (a) Delayed transforms: types2 results are used to build IR innoder/irgen.go, but operations whose semantics depend on the concrete type (calls, assignments, composite literals,==) are transformed only after substitution, viadelayTransform/transformCall/transformAssign/transformCompLit(07b30a4f77,0d838ea5a2,c94543b85f,4edefe9568,6acac8b685,cfa233d76b). (b)gfInfo/getInstInfocaches per-generic-function information (derived types, subdictionaries, bound calls vs field access, itab-needing conversions) used to build dictionaries (ddb09af1b8,4a7975e73a,f88c3b9f4d,f154f8b5bb);CONVIFACEnodes made explicit early in noder2 (12866bd8ea,e6d956e1c5,3fff213ac2,ba7673069d). (c) Export/import:ODYNAMICTYPE/ODYNAMICDOTTYPE(2be5b84665,394a1ad295), recursive constraints (d35ed09486), instantiated types referenced from inlined bodies (98ed916369,a80e53ec43,899d19ac83), the crawler for generic types (c9e05fdcf7,cea7a71d40,f6b5ffb5e1,ca5f65d771),MarkUsedIfaceMethodIndexremoved (0ae0d5c62e). (d) Naming: type-parameter subscripts replaced by func/type prefixes for uniqueness (0d65c272c9), blank type params kept unique (32636cd1ff),go.shapepackage-path escaping (1387b5e91d), instantiated type names (5b64381155,6226020c2f). (e) Lazy/recursive loading of types in importers (d7e2e2ec2b,2a4845257f,13c912d192,e581ec07ee). (f) Misc:comparableas a real builtin/interface (b614c05a15,d7a43e8912),anyidentity (0e1d553b4d,bc0aba9717), structural typing for field access /appendofstring|[]byte(ef4be98abd,f4aa021985,c74be77e63),ONONAME/closure handling in dead code (5a40100141,771b8ea4f4,ac78501b9c).
- Stabilization burst (about 250 commits, mostly by Dan Scales and Cuong Manh Le, grouped here): the
- Go 1.19 — Done: Unified IR gets full generic support with the same dictionary model (
0e2f1abf5bDynamicType for derived types,ac3ba97907itabs in dictionaries,7fc38802e1/f326964824method expression closures for bound calls,64b6e44ad7,fcf6afb82d).d3672054fbstops including instantiating type args in type hashes. Left open: unified IR still generated static*runtime._types from shape types at some sites (see RTTI thread). - Go 1.20 — Done: Unified IR switches to real dictionaries:
c9f2150cfbgeneratesF[T]-dictglobals, aF[T]-shapedfunction with.dict *[N]uintptr, andF[T]as wrapper;38edd9bd8dis the shape-based stenciling commit (initially shape = underlying type, one dictionary per type, shared by all methods, deliberately so that a future “itab in closure register” scheme could find the dictionary; noted drawback: dictionary entries for pruned methods stay alive, possible fix by linkerR_DICTTYPE/R_DICTUSErelocations). Pointer shapingb23d469e85,6985ab27df,07cf24bdfe, itab-section pruning9fc09d2ffb,OCONVNOPfor identical iface conversions34f0029a85, shape rtypes avoided in ssagen (5e0258c700).ca634fa2c5rejects notinheap type arguments. Left open:5e0258c700says shape rtypes are still used forruntime.newobjectof heap-escaping variables and “longer term I would like to get rid of shape rtypes altogether”; no pruning of dictionary entries for dead methods. - Go 1.21 — Done: user-visible reverse type inference enabled (
1f570787a8,767fbe01aehandlesInfo.Instancesin assignment contexts), more lenient inference of untyped arguments (956d31ecd5,4088e97fc2); instantiated generic methods recompiled in-linksharedmode (bcd82125f8); reproducible builds of aliased generic types (f58c6cccc4). Oldnounifiedfrontend and TTYPEPARAM/TUNION types removed (see unified IR thread). - Go 1.22 — Done: long
go.shapesymbol names hashed (8c1349baf7);mark instantiated runtime functions norace(5b2ddfadb2). - Go 1.25 — Done: shapify fixes: no shapify when reading a reshaping expression (
bfbf736564), relaxed reshaping (da0e8c4517). - Go 1.26 — Done: never shapify an already-shaped pointer (
a5866ebe40). - Go 1.27 — Done: shape signatures and
hasShapefor shaped functions (b4a084d328,2dbd51e3b4), nested-instantiation reshaping fix (b1772bacc7), SIMD types in instantiation (38ed614748); generic methods extend the model (separate thread).
Unified IR: one serialization for noding, stenciling, inlining and export
Span: Go 1.18 → Go 1.28 · Status at HEAD: the only frontend since 1.21; internal/pkgbits + noder/{writer,reader,unified,linker}.go; UIR at version V4 (V5 method indices added in 1.28 dev), documented with a formal grammar in 1.25
Paths not taken: Generics implementations not taken: contracts parser, go2go, early stenciling demos (superseded)
Earlier history: Export/import data format (Go 1.0 → Go 1.0) · Binary export data and the object-file split (Go 1.1 → Go 1.9) · Indexed export format and the export-data lifecycle (Go 1.10 → Go 1.17)
- tracking issue #57410 cmd/compile: remove GOEXPERIMENT=nounified referenced by 5 of this thread's commits
- motivating issue #54534 cmd/compile: design doc explaining unified IR implementation listed in Go: A Documentary
- motivating issue #68778 exportdata: support type parameterized aliases referenced by 5 of this thread's commits
Design. Before unified IR, a function body was copied four times by independent implementations: noder (syntax -> IR), stenciler (generic IR -> instantiated IR), inliner (backup copy + inline copy with renaming) and importer/exporter. 79cd1687e6 replaces these with a pipeline syntax -> types2 -> writer -> bitstream -> reader -> IR: the writer (noder/writer.go) walks the syntax tree plus types2.Info and emits a byte-oriented, section-based (strings, positions, packages, names, types, objects, bodies, …) export-like encoding; the reader (noder/reader.go) rebuilds IR from it. The same reader is used to create the current package’s functions, to read imported inlinable bodies on demand, and to read other packages’ export data for types2 (importer/ureader.go), so the “export format” and the compiler IR are the same thing. Lazy loading of types and objects, re-export of inlinable bodies without parsing them into IR, “sync” markers for debugging, and a quirks mode that matched old output byte-for-byte (859d903b06, later removed) were part of the first CL. The author estimated +6 kLOC / -14 kLOC once old code was gone, and claimed it supported inlining of more code (local types, type switches, closures) than the old inliner “without requiring any new code”.
Timeline.
- Go 1.18 — Done:
79cd1687e6(construction),cf1ae5fc36(-d=unified), GOEXPERIMENT knob804ecc2581, documentation6fa0437958,TestUnifiedComparetoolstash-style comparison test (3f7a3133da), incremental typecheck while reading (a18726a648), wrappers generated inside unified IR (f4198f85d5,d44ed5d144, delayed to walk20a04f6041), unified export data written after the iexport data via “scaffolding for export data experiments” (2954f11ead) sogo/internal/gcimporterand x/tools importers keep reading iexport. Avoids redundant method wrappers for imported anonymous types (7ab8754029, to stop large protobuf projects blowing build-cache limits),f118d145a5. Left open: not default; no dictionaries (stencils fully); a quirks mode existed only to keeptoolstash -cmpclean. - Go 1.19 — Done: quirks mode removed (
4f04e1d99f); sync markers simplified (6d881da9c8); coding-level logic extracted tointernal/pkgbits(7c151f3280); reader for types2 moved intoimporter(44e92e11c7), lazier import (258fc75505);-Gflag and dead old-typechecker noder code removed (302af4be8e,ad52356536,0fcb94895f,d6d2ebb7b8); pkgbits version number (d40e7bb174); fingerprints in the export format (42ca44494c) so iexport data is no longer needed for package fingerprints;9a9bd10290+e146d3eafaswitch to the final unified export format and drop backwards-compatible iexport output (GOEXPERIMENT=unified go teston generic code works without-vet=off); union types for the backend (efbe17d6f1). Reentrancy fix for function body reading (7c292ddf1f); implicit interfaces (21998413ad). Left open:e146d3eafa: importer sets the receiver type to the underlying interface “until we make a decision on #49906”. - Go 1.20 — Done: package height dropped from the importer and symbol ordering (
3a1f1e1575,4b78ece3d7,df7cb59de4); dictionary logic pruned (29b07037b1);0a6e1fa986/ddc93a536f/aa6a7fa775fixes for shapifying recursive instantiations and reflect naming of local generic types; default-on via833367e98a(author date 2022-08-09,internal/buildcfg: enable unified IR by default, GOEXPERIMENT=nounified becomes the escape hatch); runtime dictionaries and shapes (see generics thread); pkgbitsEnableSyncbecomes a dynamic header flag (9371a65584, bumping the version; “drchase’s benchmarks show it isn’t as expensive as feared”); body pruning heuristicf995946094(include all inline bodies for… with a simple heuristic rather than crawler-based pruning);e8afb29111“temporary” readers to reuse storage;caa8e1f977type-specializedReadUvarint;6b80b62fd1rawReloc perf.8ef8b60e18stops handling type expressions as expressions. Left open:f995946094is explicitly a short-term heuristic vs. the oldcrawler.go. - Go 1.21 — Done:
4f467f1082removes the nounified knob,de9bffb5f1turns unreachable code into Fatalf,da9761303cremoves the nounified frontend,a7de684e1b+f5eb0a7a5astop creating/removeTUNION/TTYPEPARAM,13c70b12d7removesMarkdcl/Pushdcl/Popdcl,178080740cunused noding code;7240d7e9e4suppresses a union-type consistency check. - Go 1.22 — Done: early deadcode moved into the unified writer (
59037ac93a), statically-knownifstatements elided in noder (f92741b1d8), “init” function created during noding (88cb17e106), inlining “properties” written to export data for the new inliner (323cf73091, +2-3% export data on kubelet),6dce882b3a1.21. - Go 1.23 — Done: alias uses preserved in export data (
f9c0423ec8, viapkgbits.TypeNamed), materialized aliases exported/imported (b24ec88bb9),1e4de0584edescribes the export data. - Go 1.24 — Done:
830621bc09addspkgbits.Version;9e8ea567c8writes V2 bitstream withaliastypeparams; has-init / derived-func-instance / derived-info-needed fields deprecated (24fd1a043d,c586dbb8b7,5de9811f37); old indexed-format import dropped (b0bbfb1e0f); export data handling merged into newinternal/exportdata(cd35323be9,0edea47f26). - Go 1.25 — Done: formal documentation of UIR: grammar (
cad1fc5207,019d798726), sections renamed Reloc->Section (52624e533f), string/PosBase/Pkg/Name/Obj sections documented (a24f4db2a2,2ab210bc74,d93bea0e59,11660d537b,25ca686a0b), reference-table rationale (f14f3aae1c). - Go 1.26 — Done:
aliastypeparamsGOEXPERIMENT deleted (00a7bdcb55); dedup in mknode (ba840c1bf9). - Go 1.27 — Done: UIR V3 -> V4 for generic methods (
fd961d3eb3,a25e961a83revertedb7db5702b0, finalf3f3d0859a); promoted struct fields encoded for composite literals (d9a600a73b); common UIR version factored (655aa335c9); README (820c83da80). - Go 1.28 — Done: package docs (
5128514a6b); V5 export data (method indices) because V4 “encoded nongeneric methods followed by generic methods, losing source order… breaking objectpath, causing crashes” (fc987b55b9, reverted54ace3ff80, reapplied00a007d7b9);testimporterfork removed (900796a858,27a8868bc2); “p” export format preparation forGOEXPERIMENT=golistexportnewformat, default-off (528579ad20). Left open: “p” format not enabled.
Old typechecker and IR node-model cleanup
Span: Go 1.18 → Go 1.28 · Status at HEAD: typecheck is a thin library (constant folding gone, Ntype gone, ir.CurFunc gone); types2 is the only checker; IR remains ir.Node with generated node_gen.go
Earlier history: Typecheck/walk separation and package-level declaration order (Go 1.0 → Go 1.0) · The C-to-Go translation of the compiler (cmd/gc → cmd/internal/gc → cmd/compile/internal/gc) (Go 1.5 → Go 1.9) · Escape analysis and stack allocation (Go 1.1 → Go 1.9) · Closures, method values and variable capture (Go 1.1 → Go 1.7) · Constant arithmetic, Mpint/Mpflt and floating-point constants (Go 1.1 → Go 1.9) · Write barriers, precise stacks and liveness (compiler side) (Go 1.2 → Go 1.7) · dev.regabi: from *Node struct to the ir.Node interface and concrete node types (Go 1.10 → Go 1.17) · dev.regabi: breaking up package gc into base, ir, types, typecheck, noder, inline, staticdata, reflectdata, pkginit (Go 1.17 → Go 1.17) · Inlining-related frontend work: export of bodies, type switches, closures, devirtualization (Go 1.10 → Go 1.17) · The legacy typechecker: error quality, alias/recursive-type handling and type checking order (Go 1.10 → Go 1.17)
- tracking issue #19683 cmd/compile: eliminate base.Pos and ir.CurFunc referenced by 9 of this thread's commits
- tracking issue #51691 cmd/compile: remove support for "broken" IR and types referenced by 10 of this thread's commits
Design. Pre-1.18 typecheck both resolved declarations and checked expressions; ir had syntactic type nodes (Ntype, OTFUNC, OTARRAY, …). With types2 the compiler now receives fully typed trees, so the node model was progressively reduced to what the middle end needs: nodes are typed at construction, type nodes become *types.Type, declarations/constants/ODCL* pseudo-ops vanish. Mechanisms: ir/mknode.go generates Copy/doChildren/editChildren (5f5c018ca4, bd56cb90a7), “hidden” fields (RType, ITab) are visited only through DoChildrenWithHidden/EditChildrenWithHidden (f773bef9ab, 7b867b9bb7); ir.miniExpr/miniNode shrank (a7489b8648, 7a33f793e8).
Timeline.
- Go 1.18 — Done: new IR ops for desugaring (
OCONVIDATA77e0bf294c,ORECOVERFP/OGETCALLER{PC,SP}9be8303df9,OCALLPART->OMETHVALUE1b995f91a5,RawOrigExprea522bc546),StructKeyExprpoints attypes.Field(a94e4f5a85),OINLCALLflattened in walk (c45d0eaadb),Func.ClosureCalledset in escape (899b158ee9),~r0/~b0result naming simplified (e99e9a6e01). Base helpersbase.Assertf(6a931673f0).types.Type.Vargen,Extra,New,NewBasicunexported (eb6a07fcf9,3836983779,a9377183d0) andType.OrigSymgetters (68ecdc2c70). - Go 1.19 — Done: removal of the old checker’s tail:
typecheckdef/Name.Walkdef(1cfe1007cd),OIOTA(d661bdeabf),Broke/Diag/SetBrokenmachinery (da9649e6d9,7ca6902c17,515135f4c3,c10fb50894,2792a414c6,0eb2c77124),AllowsGoVersionchecks (810868c9f6),typecheck.FuncBody(489e4882ef),NewClosureExpr(f25631b490). Then a sweep removing syntactic type nodes:Field.Ntype,Name.Ntype,Name.TypeDefn,CompLitExpr.Ntype,TypeAssertExpr.Ntype,ir.FuncType/OTFUNC(73fb829f59,14fed2c8f1,a6a49d128b,e94fe09c33,3ffc230a9f,27b844f767,025a9c3438,983906fa6d),cf66a82b0bprunes remaining Ntype nodes.Type.OrigSym->OrigType(adae6ec542: “first law of frontend development: thou shalt not rely on types.Sym”),Sym.Block/Lastlinenoremoved (79103faf2d). - Go 1.20 — Done:
OFORUNTILremoved (a5370d038e),OVARKILL/OVARDEF/OVARLIVEremoved from the frontend (e21c1f7896,a726c9f662),typecheckresults stored in the syntax tree rather than a map (59bc93535b, ~3% compile time: SSA -4.0%, Unicode -9.0%),types.Rnd->RoundUp,eagerly create LSym for closures(33738ddd0a),typecheck.EvalConstremoval prepared. - Go 1.21 — Done: constant arithmetic overflow checks removed from typecheck (
fd208c8850),typecheck.EvalConstremoved (25bc96dbd2), division-by-zero no longer reported there (60e6afb689),HasBreakremoved (4c20c0a826),typecheck.Assignopstops callingbase.Errorf(374bd6a3ac),Implementsexported (13e9696437). - Go 1.22 — Done: the biggest sweep:
OFUNCINST/InstExpr,ir.Ntype,AsNode,ODCLCONST/ODCLTYPE,OSIZEOFfamily (f9410990e6,09b03117b0,7af28fa90e,36fc721419,06138963a2),OrigNode/ir.Orig/SepCopy(d2eab5ff19,729e21b24c,e50bbae2de),ConstExprin favour ofBasicLit(7f1f4a1936), old variable-capture logic (22eba6a1f8),Func.ReflectMethod(a03f1aeb55),Inl.Body(08bf6d1405),typecheck.DeclContext(4089b6a5b1),NeedRuntimeType(7b2f81eb3b). Closures always constructed typechecked (5c6fbd2c3e),ORECOVERdesugared during typecheck (52c3e8c735), go/defer normalized early with wrappers (7e2e648a2d,2c51ea11b0). Nodes constructed typed:NewNameAt(typ)(e453971005),NewBasicLit(typ)(972fc055eb),NewZero(c8396b5188),Func.DeclareParams(d18e9407b0),ir.CallExpr.GoDefer(0709f1bb00), “never returns” func flag (3d62c76736). types API overhaul: no.Slice()/.FieldSlice()(14f5eb7f31),Funargremoved (98195ed057), separate struct vs tuple printing (6f7caf8894), signature representation simplified (4b9a70a3b7),Type.Registers(c80a9f172b). - Go 1.23 — Done:
OPARENskipping more selective (6af27c49bc),wrapNameremoved (334835e6b3), remaining constant bounds check removed from typecheck (5428cc4f14). - Go 1.24 — Done:
IsHiddenClosure/IsDeadcodeClosureretired (2e8b3425a2),typecheckgetcallerpc/sp builtin sigs andOGETCALLERPCdropped (5b2f71a2c3,72739bbfa6),types.Type.rparamsremoved (5d06d165ff), tcSlice/IndexConst/checkmake simplified (d7521704ce,2d9255b0ea,e6138185db). - Go 1.27 — Done: leftover constant checking removed (
73db2f85aa,bf1b0973db). - Go 1.28 — Done:
ir.CurFuncand the typecheckfuncStackeliminated: functions are injected as parameters (066f73ad47,6fb3b12e3d,65e7b09d38,cfd344d46b; WithFunc renamed WithPosc458b06048);base.Posis saved/restored where set (dfc6f7db9b,f9f805aa29,5be815fece) with the stated goal thatbase.Posvalues map to subtrees of the compiler call graph;Diagfwithout positions (fcb91c57fc); IR fields freed after each function compiles (d86dd2ed4f, -30% peak memory on aws ec2 package: 2.7 GB -> 1.9 GB). Left open:CurFuncremoval is tracked as #19683 (ongoing);base.Posstill global.
RType/ITab fields and implicit conversions in IR (RTTI plumbing)
Span: Go 1.19 → Go 1.20 · Status at HEAD: complete; every runtime-type-needing IR node carries its RType/ITab explicitly
Design. Under shape-based stenciling, walk/ssagen cannot call reflectdata.TypePtr(n.Type()) for derived types because the node’s type is a shape. Unified IR therefore records, per IR node that will become a runtime call needing *runtime._type or *runtime.itab, explicit RType/ITab expressions (read from the dictionary for derived types). Conversions that the language performs implicitly (assignment, call arguments, returns, composite literal elements, map keys, comparisons, multi-value spills) are made explicit OCONVIFACE nodes by the writer so the right itab/rtype expression can be attached.
Timeline.
- Go 1.20 — Done: RType/ITab fields added (
5960f4ec10),reflectdata.{TypePtr,ITabAddr}refactored to prefer them (f70775ff22), ssagen avoidsreflectType(5e0258c700), set for OMAPLIT (3d432b6c4b), switch/case clauses (61ae2b734c), range assignments (d667be8831), selects (878439cfe5), writer-side implicit conversions for sends, index expr, complits, call args, assignments, returns, binary exprs and multi-valued expressions spilled to temps (5f5422a2dd,a3e474f867,711dacd8cf,a3fea7796a,421e9e9db2,c846fd8e13,3635b07d16), RTTI written to export data (9b70178d58,92798176e7,e376746e54), obsolete wiring removed (f48fa643f1), explicit nil / type-switch handling (318027044a,a4c5198a3c), function instantiations / selectors / receivers handled explicitly (2e6ffd6c5d,88635b3862,de95dca32f),f2851c67fdallows inlining to fail gracefully. Left open:f773bef9ab1.21 (1.21) notes the RType fields aremknode:"-"hidden fields “to avoid throwing off inlining cost heuristics”; “longer term we should unhide them”.
Generic methods (type parameters on methods)
Span: Go 1.27 → Go 1.28 · Status at HEAD: language feature enabled (go1.27 language version); GOEXPERIMENT=genericmethods was added 2026-04-30, default flipped on, flag deleted 2026-06-12; UIR V4 plus V5 method-index fix
- proposal #77273 spec: generic methods for Go referenced by 6 of this thread's commits
- proposal #75526 proposal: allow type parameters on methods (generic methods) listed in Go: A Documentary
Design. Methods with their own type parameters are supported in the unified IR pipeline by (1) writing generic methods separately from ordinary methods in the type’s encoding, (2) encoding method-level type-parameter dictionaries with dict.receivers (receiver type args) followed by method type args, with parameter indices offset (b9c77f8c00, 5ecf12eedf), (3) omitting wrapper functions for generic methods because their signatures are generic and the downstream wrapper machinery assumes otherwise, which costs a statically computed wrapper (dictionary pointer computed dynamically) (142f237601), (4) name-mangling instantiations (9cd372147e, 714a94dd31 puts type args in parentheses), qualifying identifiers (836b0984ee) and method expressions (cafe443251, fdb1ba1325). Interface satisfaction by a generic method is unsupported: 8ddf0031cf disallows a nointerface method to satisfy a constraint.
Timeline.
- Go 1.27 — Done: user-visible parsers stop rejecting method type parameters, type checkers do (
06dc5db75d), then “allow generic methods starting with Go 1.27” (e84da0405b). Shape helpers (b4a084d328,2dbd51e3b4),isConcreteMethod/isGenericMethod(3524089944), encoding (affadc7997,8c61ad873a,328950b13c), decoding (ae1edbeb2f,f4b87f314d,ad7d6071acimporter,ac5968dac4,57868d0019),fd961d3eb3bumps pkgbits version; experiment gating87fe5fafbafixes use of the compiler’s own build experiment instead of the user-code experiment;4e4b780652hoists a version assertion (otherwise generic methods are silently dropped on old UIR versions);f3f3d0859amakes V4 default (V3 on opt-out),e212a16d1eflips the experiment default,fdd592745dtests. Left open: the experiment was explicitly “not included in the Go 1.27 release”; wrappers omitted (perf optimisation missing). - Go 1.28 — Done: fixes: OMETHEXPR construction (
fdb1ba1325), alias-receiver qualification (ea7d327c80), shared-wrapper receiver qualification (61b3e65bd2), V5 export data (fc987b55b9).
Static initialization and package init
Span: Go 1.18 → Go 1.28 · Status at HEAD: staticinit with inline-aware static init (enabled in 1.21), outlined map init for deadcode, init splitting redone in 1.28 cycle
Earlier history: Initialization and static data (Go 1.0 → Go 1.0) · Static initialization, composite literals and init (Go 1.1 → Go 1.9) · Walk-level lowering and runtime-call optimisations (Go 1.1 → Go 1.9) · Package initialization order, static initialisation and init functions (Go 1.10 → Go 1.17)
Design. staticinit.Schedule turns var x = <expr> into linker data where possible. Extensions over time: staticcopy of var b = a is now invalidated once an initializer that may modify a package variable has been seen (afa3f8e104, with -d=staticcopy diagnostics); static initialization of inlined calls (b1678e508b handles simple inlined calls, bed970b3ff integer conversions, 249e51e5d9, a141c58c85 string concatenation) so var myErr error = &myError{"msg"} stays static even if wrapped in an inlinable function; large global map literals are extracted into a separate map.init.N function called through a weak relocation, so the linker can dead-code-eliminate unreferenced big maps (b46e44a399, 269bdcd568 moves the switch to -d=wrapglobalmapctl).
Timeline.
- Go 1.18 — Done: pkginit “init” and “inittask” logic separated (
6c5f028242);opendeferinfo symbol content-addressable (d9952ff511). - Go 1.20 — Done: inlined-call static init (
b1678e508b,bed970b3ff,249e51e5d9,c85848a4a6), initially unstable:152119990fadds-d=inlstaticinitand temporarily disables it (“Google-internal testing is hitting additional failure cases”),f89b39c0afre-enables; coverage vars special-cased in init order (4fb35d6cee); Left open: fixes for hidden RType fields (f773bef9ab1.21) still pending. - Go 1.21 — Done: hidden-field fix
f773bef9ab; wrap global map init enabled (b46e44a399); inlstaticinit disabled again (b7736cbceb) then re-enabled (20c349e534) with fixes (abd55d8483substituted arguments,89138ce740unhides closure funcs moved to staticinit,3161081c12);5b603f79fbdrops special treatment of cover vars in initorder;3494a72600no DWARF for static vars. - Go 1.22 — Done:
afa3f8e104staticopy safety;88cb17e106buildsinitduring noding (removingInitTodoFunc);079c0441d5/611c3af30daddrtaken/closure fixes. - Go 1.23 — Done: user-visible constants before variables in init order (
8f618c1f53, a types2 change affecting program behaviour); static-init safety fixes (973befe714ODEREF,5038ce82b6OASOP inmayModifyPkgVar); init fixesbe152920b9. - Go 1.24 — Done: no static init of strings in FIPS mode (
5ec1457941,dea12628e6removes debugging). - Go 1.26 — Done: global
new(expr)fix (a8291eb614), dead code removal (317be4cfeb). - Go 1.27 — Done:
1b7e5836adsplits large init functions (compile-time win for #77153) but3233439691reverts; OCONVIFACE unwrapped for OAS2 (45c6fb4b9b); embedded-field offsets in static init (e2c188568d). - Go 1.28 — Done: synthetic init splitting reapplied (
dc72b71db0, reverted2b80068e2e, reapplied31ce17fe80); offsets >= 1 GiB (LSym limit) routed to dynamic init (dd612356d8);41cb39b794movesAnySideEffectstoir;5aaedc8a79(huge param offsets ICE). Left open: the repeated revert/reland of init splitting indicates correctness problems were still being worked through.
Compile-time performance, concurrency and the self-PGO’d compiler
Span: Go 1.19 → Go 1.28 · Status at HEAD: backend concurrency = GOMAXPROCS (normally capped at 4 by go build); compiler built with PGO from cmd/compile/default.pgo, refreshed about annually; startup heap boost 128 MiB
Earlier history: Inlining (Go 1.1 → Go 1.9) · Compiler performance, formatting and concurrency (Go 1.7 → Go 1.9) · Concurrent compilation and frontend performance (Go 1.10 → Go 1.17)
- tracking issue #60234 cmd/compile: update compiler's PGO profile referenced by 5 of this thread's commits
- motivating issue #15734 cmd/go: build dependent packages as soon as export data is ready referenced by 3 of this thread's commits
Design. Concurrency work lives in gc/compile.go: functions are compiled in an ordered work list by up to nWorkers goroutines; ordering is by cost (largest first) so long compiles start early. The GC is tuned for a short-lived process.
Timeline.
- Go 1.19 — Done: fixed a compiler deadlock on syntax errors from the open-file semaphore (
5a90270d7f,370cadd0e4), 128-bit hashes for content IDs (485a572243). - Go 1.20 — Done: one manager goroutine hands out work to at most nWorkers (
2ff5fbfbd4) instead of hundreds of blocked goroutines; default concurrency =GOMAXPROCS, compiler downgrades silently if debug flags are incompatible (b725622ceb,f3d656be50, tagged flags viac81c027982“concurrentOk”); ifGOGCis unset, boost the GC to get rapid starting heap growth: ~14-17% less user build time and 3.5-7.8% wall (44cabb802a);typecheckresults kept in the syntax tree (59bc93535b, ~3%); eagerLSymcreation for closures. - Go 1.21 — Done: the compiler is built with PGO (
ad6dcf9da4; reverted298ff30958, reapplied6111ac826e, reverted6ffd135256, reapplied45b74d20a0after x/tools and ppc64 failures): Template -1.4%, Unicode -5.0%, Compiler -5.6%; SCC-reordering for inlining (f5c7416511). - Go 1.22 — Done: profile refreshed (
1926a0b573, -3.1% Template); per-package memprofile/cpuprofile into directories (0ce94d79bc,2f5bd4e4f2). - Go 1.23 — Done: PGO profile refresh (
7c52c064df, Template -3.5%, Unicode -5.1%, GoTypes -3.9%);cmd/preprofiletool to pre-parse PGO profiles (b7ae16e04b,e069587c8d); eq/hash algorithm andptrBytescomputed once inCalcSize(fcfd824e31,b40dc30d24) rather than on demand; telemetry counters (483a913a55,acda0107ba). - Go 1.24 — Done: PGO profile refresh (
3ae00f5d29); function wrappers cheaper to compile. - Go 1.25 — Done:
fece9871bbprofile refresh. - Go 1.26 — Done: starting heap boost made independent of
-cand raised to 128 MiB nominal, plus-d=gcstart=NMiB knob (ab2829ec06). - Go 1.27 — Done:
ac2b8fc093profile refresh (Unicode -6.3%);e296659b12plumbs the profile through the inliner and body reader; flags marked concurrency-ok (ba057f7950,9eb830a807);439a82ad25unsorted diagnostics flag. - Go 1.28 — Done: functions ordered by IR node count instead of top-level statement count (
6e88b3b4b6, Compiler -1.6%, SSA -2.1%); IR memory freed after each function (d86dd2ed4f);sync.WaitGroup.Go(2a74f63764); export data written before compiling function bodies so dependents can start sooner (ebe2feefc4,bcd5def4bfpreassigns symbol indices,ffee23ff7cnew-exportfdflag where the compiler writes a byte to an fd andcmd/gounblocks dependent compiles; fixes #15734) Left open: nothing noted.
Compiler debugging infrastructure: bisect/hash debugging, flags, dumps
Span: Go 1.18 → Go 1.28 · Status at HEAD: -d flags with concurrency tagging, internal/bisect-based HashDebug, astdump HTML
Earlier history: Pragmas, directives and compiler flags (Go 1.1 → Go 1.9) · Race detector and sanitizer instrumentation in the frontend (Go 1.1 → Go 1.7) · checkptr instrumentation and compiler debugging flags (Go 1.12 → Go 1.17)
Design. base.HashDebug (GOSSAHASH renovated) lets any optimization be bisected to a function or file:line (including inlining stack). Hash patterns are generic across compiler flags and, via internal/bisect, GODEBUGs.
Timeline.
- Go 1.18 — Done:
-dflag parser moved toobjabi(1c4cfd8010),-asan(85b3b4ee03),-memprofilerate(6113dacf32), always print ICE message for panics (1abe9c1c73), dumps:-W=3,c2966ae272position details. - Go 1.20 — Done: GOSSAHASH refactored to be usable outside ssa (
522f0fc425,03f6d81fc7), separator;->/(1bcfdc777a), file:line hashing incl. inlining (d33043d37d),concurrentOkflag property (c81c027982), coverage fixup mode (e6d9057e2f). - Go 1.21 — Done: HashDebug moves onto the new
internal/bisectpackage (da5a3146ec),134c9b2b17(drop FS hash form),1099644f52(extra info in bisect output),9dd0c7fc78,ef9c211de8(match exclusion),42866e566a,81a31f5dd5(godebug bisect). user-visible error URLs:7a21f799a5-url,e0db8ab6e0, enabled by defaulte7a9ca0a53and reverted42f387aae1;2cbab4e98cpasses types2 error codes through;626d478d82generates Markdown docs for each error code. - Go 1.22 — Done:
-env key=value(c14655da98), pgohash (3fb86fb864),-d=rangefunccheck=0(d411b3197c), pgo devirtualization disable (1ab9df4849). - Go 1.24 — Done: script-test facility for the compiler (
aa97a012b4,b60f88d810toolchain script conditions,8246171baeREADME generation). - Go 1.25 — Done:
2c9689ab0e(variablemakehash),e46d586edd(literalallochash) so allocation optimizations are bisectable. - Go 1.27 — Done:
-d=astdump(835d6d42c4), HTML output with collapse/expand (ae7b257f24,a3688ab13e; commit says AI-assisted),-d=ssa/phase/@keyword=valueoptions (bef396c3391.28) in 1.28. - Go 1.28 — Done:
-d=ssa/phase/@keyword=value(bef396c339), ssa html flag (6b0a207525),b13887b154compiler statistics package with a pointer-demographics pass.
Frontend support for new language features and spec changes
Span: Go 1.18 → Go 1.28 · Status at HEAD: tracks the language; most features need a noder/typecheck/walk piece plus a types2 piece owned by the fe-types area
Paths not taken: Error-handling syntax prototypes: try and ? (never landed)
Earlier history: Closures (Go 1.0 → Go 1.0) · Language changes and rules as implemented in the compiler (Go 1.1 → Go 1.9) · Constants: Go 2 number literals, evconst, untyped conversion and go/constant (Go 1.11 → Go 1.17) · Language version gating (-lang) and language changes implemented in the frontend (Go 1.12 → Go 1.17)
Design. Each feature typically has: types2 acceptance (other area), writer/reader support in unified IR, and a lowering. A common pattern is “land compiler support behind GOEXPERIMENT first, flip with the language version”.
Timeline.
- Go 1.18 — Done: user-visible generics (see above),
anyas alias likebyte(b31dda8a2a,8ff254e30b),comparablebuiltin (b614c05a15),-langgating (2aea44204e,4068fb6c21always accept 1.18 syntax but complain if not 1.18),//go:embedinto any byte slice type (4f2ebfe34b),-langcheck for embed moved to noder (8eeaf961c5),unsafe.Sizeofon type parameters (be1a693477). - Go 1.19 — Done: user-visible
//go:uintptrkeepalive(342b495301),sync/atomictyped values alignment (0f715f1ac9), unsafe.Slice open-coded (579902d0b1), constant-fold switch early (01b9ae22ed, better codegen74b52d95191.21). - Go 1.20 — Done: user-visible
unsafe.String/StringData/SliceData(c708532936), slice-to-array conversions (ceffdc8545), alternativecomparablesemantics (b95ea201d5; old removed in 1.21354c8fb4361.21),go:notinheaprestricted (ec2ea40b31) and removed in favour ofruntime/internal/sys.NotInHeap(0ee0bb1003,8bbb362f4c), reject not-in-heap type arguments (ca634fa2c5), updated error messages (“satisfies”, “missing method m”, …) andinternal/types/errorspackage (b440c15db7,49372957ab). - Go 1.21 — Done: user-visible
clear(b89a840d65),min/max(b0f15b4ac0),//go:wasmimport(02411bcd7c,aff2f4a724), reverse type inference (1f570787a8), lenient untyped-arg inference (956d31ecd5), experimental loop-variable semanticsGOEXPERIMENT=loopvar+-d=loopvar(c20d959163,5a7793b7b8flag on FOR/RANGE that preserves loop semantics across inlining), wasip1 (7f5af094f8). - Go 1.22 — Done: user-visible per-iteration loop variables for Go >= 1.22 modules (
fe1daf2e43), range-over-int (a94347a05c) and range-over-func (2fba42cb52, rewrite inrangefunc/rewrite.go) behindGOEXPERIMENT=range; laterb5e31780b6post-loop-exit check;fbfe62bc80/778880b008range-typecheck fixes; interface type-switch lowering with a single runtime call (28f4ea16a2,7499257016,b455e239ae,afd7c15c7f);//go:buildversion mismatch reporting (1f25f96463). - Go 1.23 — Done: user-visible range-over-func enabled for Go 1.23 files (
d278d5bbdd), generic alias types (477ad7dd51,31c8150082enables aliases in the type checker),len(ch)/cap(ch)viachanlen/chancap(b6753baaed,61d6817c83),-lang=go1accepted (08370dcd9a), linkname referring to instantiations disallowed (849770dec9), rangefunc robustness (5a9dabc2ba). - Go 1.24 — Done: user-visible
//go:wasmexport(1cf6e31f0d, docs32e19fc439), aliases enabled in importer (209ed1a9c7), alias type parameters written (3b36d92c96), tail-call wrapper emission (af0c40311e), dead locals pass (cc258e6785). - Go 1.25 — Done: label requirement after
goto(go/parser), scalar-allocation aggregation for heap escapes (5fc596ebe7), type-based alias analysis (11f7ea8ce0),bdef177831go/parser requires a label aftergoto. - Go 1.26 — Done: user-visible
new(expr)(7bc1935db5,0f31d742cduntyped fix), spec: cycle restriction for type parameters removed (4684a26c26) and alias RHS rule (790384c6c2),testing.B.Loopkeep-alive semantic (22f24f90b5,3fd9cb1895,509ddf3868,2ac1f9cbc3). - Go 1.27 — Done: user-visible generic methods (own thread), promoted fields as composite-literal keys (
d9a600a73b,30bfe53dd7,c0cd914383),linknamestd(46755cb4de), 1 GiB string-constant limit (543703d352), consolidated size limits (b8e0cb88c8), new line-directive semantics (a7ea4a7ecd,1926d1d95d), loopvar workarounds removed (8da2be3cd0), bloop refinements (540ccca0a7,bae9486d07), nointerface method / constraint (8ddf0031cf). - Go 1.28 — Done: user-visible untyped composite literals (
a3edc4c682syntax, test cases7ccdc93ad4),recoverworking in a range-over-func loop body (dba926f240), blank second range variable skips evaluation (dd5f863870),reflect.Value.Methodmarking (d8fec91a72).
The syntax package (parser, scanner, tree)
Span: Go 1.18 → Go 1.28 · Status at HEAD: stable; mostly error-message and parser-tolerance work
Earlier history: Lexer, grammar and statement syntax (semicolons, chan operators, conversions) (Go 1.0 → Go 1.0) · Parser: from yacc to a hand-written recursive-descent parser (Go 1.1 → Go 1.8) · The syntax package, position representation and parse-time checks (Go 1.8 → Go 1.9) · The syntax package: parser, scanner, source reader, positions and error recovery (Go 1.10 → Go 1.17) · Directives and pragmas in the frontend (//go: handling) (Go 1.10 → Go 1.17)
Design. cmd/compile/internal/syntax is the compiler’s own parser; it differs from go/parser in retaining positions via PosBase, using LineDirective semantics, and producing Nodes directly consumed by noder and types2.
Timeline.
- Go 1.18 — Done: generics syntax: embedded type literals (
81b22480cf), type-set syntax in tests (90096f445e), constraint literals with elided interfaces (5279e534b5,bb49eb3e6a,0bef30d28aarray/slice constraints), type parameter list validity (2c60a99f72,33a1a93a92,da1aa65053),go/ast-styleWalk/Inspect/Visitor(8165256bc2, used byCaptureVarsbadb98364b),PosBase.Trimmed(ab9aaf46ee), “assume generic code for std lib” (aa878ee49b),AllowTypeSetsremoved (276fb279d1). - Go 1.19 — Done: generic-specific parse modes removed (
bf408e741c),~xas unary expression (09ada1af8f), CheckBranches checksfallthrough(6b309be7ab, one-time branch/label checks666d736ecb), no parse ofGOROOT/.git. - Go 1.20 — Done: tolerant
go/deferparse (BadExprinstead of a fake callc801e4b10f, no spurious “not used” errors489f508ccf), missing-index handling (9485d4c1bd), stricter type instances (1be8fcdcdc),ErrorMap->CommentMap(1.211e005165831.21), import decl tolerance (a330ca5c54). - Go 1.21 — Done:
Crawlremoved (3c357409d1), better=vs==message (db3f952b1f). - Go 1.22 — Done:
Unparen,UnpackListExpr(d5c5808534, inlinable and stack-allocated result verified bytesting.AllocsPerRun), better type-parameter-list errors (b7a695bd68), dummy name for missing func name (b7a66be69c). - Go 1.23 — Done: KeyValueExpr start position (
4256ec1661),Pos.FileBase(8b990f2592). - Go 1.24 — Done: parentheses around constraints stripped consistently (
1e2114349d), keyword hints in errors (2eac154b1c), missing parameter type message (bae2e968e2). - Go 1.27 — Done:
//linefilenames resolve relative to source directory (a7ea4a7ecd). - Go 1.28 — Done: untyped composite literals (
a3edc4c682), empty declaration group (72b8727aa8), NUL byte after buffer refill (452f3ea690),source.segmentreturns string (a8d1c0e823), scanner ident simplification (2c3abb202a).
Package paths, -p, and build-system contract
Span: Go 1.19 → Go 1.28 · Status at HEAD: -p required; symbols carry real package paths; export-data readiness signal to cmd/go since 1.28 dev
Earlier history: Package system, visibility and import resolution (Go 1.0 → Go 1.0)
- proposal #51225 cmd/compile: require build systems to specify -importcfg referenced by 1 of this thread's commits
- tracking issue #51734 cmd/compile: cleanup code paths that aren't needed now that -p is required referenced by 7 of this thread's commits
- motivating issue #15734 cmd/go: build dependent packages as soon as export data is ready referenced by 2 of this thread's commits
Design. The compiler used to write "" as the local package path and let the linker substitute it; every "" assumption in compiler and tools was a source of bugs. a987aaf5f7 makes -p mandatory (go command already passed it; Bazel/Gazelle do too); ab8d7dd75e initialises LocalPkg.Path to it.
Timeline.
- Go 1.19 — Done: user-visible
-prequired (a987aaf5f7), default-p=mainfor main (20ba3f5de5),LocalPkg.Pathset (ab8d7dd75e) after removing""assumptions in unified IR, iexport, staticdata embed symbols,ir.PkgFuncNameandCtxt.Pkgpathfallbacks (1973be519a,e3661d5f08,499e334a28,4170084ad1,2540f4e49d),-importmapremoved (1355ea3045),-installsuffixkept after revert, command-line flags parsed earlier (b6c5a5baa7),#ifdef-style ABI notes for riscv64 (1045faa38c). - Go 1.22 — Done: fallback for missing
-peliminated (cf338eb890), vestigial importpath symbol logic removed (52a5881bee),-+flag computed from package path (fbcf43c60b),PkgSpecialsunify NoInstrument/NoRace lists (56b3b244fd,83e0704c50). - Go 1.28 — Done:
-Iand-importcfgmutually exclusive (85e6f00798),-exportfdand early export data (ffee23ff7c,ebe2feefc4).
Types package internals: size, algorithm kind, TFlag, SIMD flags
Span: Go 1.18 → Go 1.28 · Status at HEAD: types.Type computes layout, alg kind, pointer bytes and abi.TFlag once, lazily and side-effect-free
Earlier history: Compiler data structures: Node, Nodes, Type, and the types package (Go 1.5 → Go 1.9) · Types package internals and type printing (Go 1.10 → Go 1.17)
Design. types.CalcSize historically computed only size/alignment; callers recomputed eq/hash algorithm, ptr bytes and register counts on demand, which is unsafe once SSA runs in parallel. Work moved these into CalcSize or cached fields.
Timeline.
- Go 1.18 — Done:
types.RecalcSize(62f88b6dc8),PtrDataSizesimplified (c81fa001a7), types init code moved intotypes(967a3d985d1.19),Type.Extra/widthCalculatedunexported. - Go 1.22 — Done: struct size calculation refactor (
1f544ef0eb),Type.Registers(c80a9f172b). - Go 1.23 — Done: algorithm kinds simplified (
d255792933), computed inCalcSize(fcfd824e31),ptrBytescomputed duringCalcSize(b40dc30d24); “mark pointer to noalg type as noalg” (b8c76effd9); itabs generated using therttypemechanism (977803e796). - Go 1.24 — Done: GC programs removed from stack frame objects (
5a0f2a7a7c), map bucket special cases removed fromtypes.Compare(cf5ec0720f), stack-allocated swiss maps (63ba2b9d84, small maps andmakemap_small, #54766). - Go 1.28 — Done: SIMD flags stored in the
Type.flagsbitset (f0c78119ea),align128marker (c2dcde178d),abi.Type.TFlagloads constant-folded against the static type (7e9c70ae99; first attempt86eb9afa8creverted21ae06fe28), withMethodsComputedbit assertingCalcMethodsran;75f2c467f6keeps memory ABI for SVE mask types throughSetUnderlying.
Method wrappers and promoted-method sharing
Span: Go 1.18 → Go 1.28 · Status at HEAD: wrappers for promoted methods shared across receiver types (1.28 cycle)
Earlier history: Lowering in order/walk and the shape of runtime calls emitted by the frontend (Go 1.10 → Go 1.17) · Register-ABI plumbing in the frontend (Go 1.12 → Go 1.17)
Design. For embedded fields, method tables, itabs, reflect metadata and generic dictionaries need a stable entry point, historically one wrapper per concrete receiver type. Unified IR (1.18) took over generation (f4198f85d5, d44ed5d144); f534300f98 shares wrappers when the promoted method’s receiver (e.g. *X embedded at offset 0) is identical across A, B, C, qualifying shared receiver types (61b3e65bd2).
Timeline.
- Go 1.18 — Done: wrappers generated in unified IR; wrapper emission after inlining (
50f38d0405); “always generate (*T).M wrappers for instantiated methods” (4ed6317e73);132ea56d29fixes crawling of embeddable types so inline bodies for promoted unexported methods are exported; ABI wrapper comments. - Go 1.20 — Done:
a8780f94c3missing method-value wrapper;1519729c6aetc. - Go 1.23 — Done: method wrapper comments; wrapper handling for aliases.
- Go 1.24 — Done: tail-call wrappers (
af0c40311e) in the frontend;7e2487cf65avoids dynamic type when possible. - Go 1.27 — Done: skip incomplete types in
needWrapper(b77fdc333a). - Go 1.28 — Done:
f534300f98shared promoted wrappers. Left open: nothing noted.
SIMD frontend: the “midway” source-to-source translator
Span: Go 1.26 → Go 1.28 · Status at HEAD: prototype in the frontend, -d flag controlled
Design. internal/midway (analysis, deepcopy, rewrite, check) is a source-to-source translator ported into the front-end that rewrites “portable SIMD” code into per-architecture calls by re-running type checking after the rewrite (f1aa77c984: “tiny-highway v0”, 12.6 kLOC incl. emulations and tests).
Timeline.
- Go 1.26 — Done:
dev.simdbranch infrastructure: k-register support (11d2b28bff), bodyless intrinsics (88c013d6ff), devel compiler not treated as release (4150372a5d,ebb72bef44), early prototype removed (b4d1e018a8). - Go 1.27 — Done: HTML “syntax” formatter for IR (
fda1299caf), first midway translator (f1aa77c984), cleanups (e07983a299), debugging flag (7624fb3f0a), sizeof non-constant for simd types (ee5e65d491), renaming types with dependent methods (cc1ee09473), method type-checking for inference (14596908b7). - Go 1.28 — Done: fixes: ICEs with shared emulation selectors, range clauses, blank/unnamed params, zero values (
4ea26e6624,898e19087e,84fe05b3ae,d61b240b11,ad04d4de84), variadic forwarding (f51739cf2a), Midway docs (77a63bd811). Left open: SVE/arm64 mask ABI problems fixed ad hoc (75f2c467f6).
ir.StaticValue, ReassignOracle and function-variable tracking
Span: Go 1.22 → Go 1.27 · Status at HEAD: batch oracle used by inliner/escape; ongoing migration of callers
Design. ir.StaticValue/ir.Reassigned find the unique definition of a local by walking the whole function per query. ReassignOracle (8be8bfeaa2) collects the information once per function (“reduced cost in compile time”).
Timeline.
- Go 1.22 — Done:
Reassignedexported and OASOP handled (7087b8ac4c, #61502),StaticCalleeNameextracted (3be2176d92),ReassignOracle(8be8bfeaa2). - Go 1.27 — Done: singly assigned function variables treated as static callees in escape analysis, e.g.
var visit func(*Node); visit = func...(f4bfb1a9c6), generalised toFuncAssignmentswithteeHolemerging of known callees’ escape tags (5af294bac7), merged into the oracle (84e0c4965a), parens unwrapped (2f0459745c). Left open:2f0459745ccalls it “a parity step needed before more callers can switch fromir.StaticValuetoReassignOracle”. - Go 1.28 — Done: RHS nil in static value (
f192b5be2e).
(none: all substantive bodies of work are covered by the existing threads)
Changes in this slice that are not part of a thread are listed on the release pages: 1.18 · 1.19 · 1.20 · 1.21 · 1.22 · 1.23 · 1.24 · 1.25 · 1.26 · 1.27 · 1.28