Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1b8263c
Replace nodeData interface with generated AST accessors
jakebailey Oct 12, 2026
9401e5b
Compact checker type metadata
jakebailey Oct 11, 2026
3b3f3f5
Compress paged link-store references
jakebailey Oct 11, 2026
3103f2e
Batch allocations of common checker types
jakebailey Oct 11, 2026
8f37590
Presize checker type-list cache keys
jakebailey Oct 11, 2026
a81be78
Check link presence without resolving arena indexes
jakebailey Oct 11, 2026
c803170
Format checker type casts
jakebailey Oct 11, 2026
7fb7c36
Update imports for integer-format lint fixes
jakebailey Oct 11, 2026
0e65ee3
Avoid allocating normalized types on interning cache hits
jakebailey Oct 11, 2026
8d43f6f
Compact type mappers and coallocate inference mapper storage
jakebailey Oct 11, 2026
20a10e2
Move cold value-symbol links out of the hot records
jakebailey Oct 11, 2026
89d156c
Index checker members without redundant symbol maps
jakebailey Oct 11, 2026
6bab5b4
Recover concrete AST nodes from their embedded headers
jakebailey Oct 11, 2026
9cf07c1
Keep optional symbol tables out of hot symbol records
jakebailey Oct 11, 2026
4d24b66
Move optional structured type shape into cold storage
jakebailey Oct 11, 2026
ad91443
Keep optional outer type parameters out of hot node links
jakebailey Oct 11, 2026
a554837
Keep optional signature state out of hot records
jakebailey Oct 11, 2026
db1185b
Bound arena retention by bytes instead of object count
jakebailey Oct 11, 2026
5c8f28f
Use paged indexes for type-node and signature caches
jakebailey Oct 12, 2026
20e3a2d
Store ordinary relationship keys as exact type ID pairs
jakebailey Oct 12, 2026
0df9826
Share complete union and intersection property cache entries
jakebailey Oct 12, 2026
2d8289e
Reuse ordered property counts during intersection reduction
jakebailey Oct 12, 2026
d5286ca
Enforce compiler record construction and cast invariants
jakebailey Oct 12, 2026
65e89fc
Make union augmentation test independent of bundled libs
jakebailey Oct 12, 2026
05fdf40
Avoid discarded DWARF in coverage test builds
jakebailey Oct 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Herebyfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,9 @@ function goTestFlags(taskName) {
...goBuildFlags,
...goBuildTags(),
...(options.tests ? [`-run=${options.tests}`] : []),
// Go 1.27 duplicates promoted AST wrappers, exhausting CI disk under coverage.
// Tests strip DWARF when linking; omit it earlier to shrink temporary and cached archives.
...(options.coverage && !options.debug ? ["-gcflags=all=-dwarf=false"] : []),
...(options.coverage ? [`-coverprofile=${path.join(coverageDir, "coverage." + taskName + ".out")}`, "-coverpkg=./..."] : []),
];
}
Expand Down
1 change: 1 addition & 0 deletions tools/customlint/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func (f *plugin) BuildAnalyzers() ([]*analysis.Analyzer, error) {
forbidParentAccessAnalyzer,
shadowAnalyzer,
typedPathsAnalyzer,
unsafeLayoutAnalyzer,
unexportedAPIAnalyzer,
}, nil
}
Expand Down
45 changes: 45 additions & 0 deletions tools/customlint/testdata/unsafelayout/consumer/consumer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package consumer

import (
"unsafe"

"testdata/unsafelayout/internal/ast"
"testdata/unsafelayout/internal/checker"
)

type BadNode ast.Node

type NodeAlias = ast.Node

type BorrowedNode struct {
*ast.Node
}

func uses(node *ast.Node, declaration *ast.ImportDeclaration, kind ast.Kind, typ *checker.Type) {
node.Kind = ast.KindIdentifier
declaration.Kind = ast.KindImportDeclaration
declaration.Kind = ast.KindJSImportDeclaration
node.AsImportDeclaration().Kind = ast.KindImportDeclaration
declaration.Kind = ast.KindIdentifier
declaration.Kind = kind
declaration.Kind++
_ = &node.Kind
_ = &ast.Node{Kind: ast.KindIdentifier}
_ = &ast.Identifier{}
_ = new(ast.Node)
_ = new(ast.Identifier)
_ = new(NodeAlias)
_ = unsafe.Sizeof(ast.Node{})
_ = unsafe.Offsetof(ast.Identifier{}.Node)
_ = (*ast.Identifier)(unsafe.Pointer(node))
_ = *node
_ = *declaration
_ = *typ
copy := *node
_ = copy
pointer := unsafe.Pointer(node)
_ = pointer
borrowed := BorrowedNode{Node: node}
borrowed.Kind = ast.KindIdentifier
_ = &borrowed.Kind
}
102 changes: 102 additions & 0 deletions tools/customlint/testdata/unsafelayout/consumer/consumer.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package consumer

import (
"unsafe"

"testdata/unsafelayout/internal/ast"
"testdata/unsafelayout/internal/checker"
)

type BadNode ast.Node
~
!!! unsafelayout: defining a new compiler-record type bypasses checked construction; use a type alias

type NodeAlias = ast.Node

type BorrowedNode struct {
*ast.Node
}

func uses(node *ast.Node, declaration *ast.ImportDeclaration, kind ast.Kind, typ *checker.Type) {
node.Kind = ast.KindIdentifier
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind = ast.KindImportDeclaration
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind = ast.KindJSImportDeclaration
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
node.AsImportDeclaration().Kind = ast.KindImportDeclaration
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind = ast.KindIdentifier
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind = kind
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind++
~
!!! unsafelayout: incrementing a compiler tag bypasses checked tag assignment
_ = &node.Kind
~
!!! unsafelayout: taking a compiler tag's address bypasses checked tag assignment
_ = &ast.Node{Kind: ast.KindIdentifier}
~
!!! unsafelayout: a bare compiler header has no concrete payload; use a concrete factory
~
!!! unsafelayout: construct compiler records through their owning factories, not struct literals
~
!!! unsafelayout: compiler tags must be assigned by checked construction, not struct literals
_ = &ast.Identifier{}
~
!!! unsafelayout: construct compiler records through their owning factories, not struct literals
_ = new(ast.Node)
~
!!! unsafelayout: a bare compiler header has no concrete payload; use a concrete factory
~
!!! unsafelayout: allocate compiler records through their owning factories
_ = new(ast.Identifier)
~
!!! unsafelayout: allocate compiler records through their owning factories
_ = new(NodeAlias)
~
!!! unsafelayout: a bare compiler header has no concrete payload; use a concrete factory
~
!!! unsafelayout: allocate compiler records through their owning factories
_ = unsafe.Sizeof(ast.Node{})
_ = unsafe.Offsetof(ast.Identifier{}.Node)
_ = (*ast.Identifier)(unsafe.Pointer(node))
~
!!! unsafelayout: reinterpret compiler records only through checked casts or generated AST dispatch
~
!!! unsafelayout: reinterpret compiler records only through checked casts or generated AST dispatch
_ = *node
~
!!! unsafelayout: copying a compiler record by value can detach its tagged header; keep a pointer
_ = *declaration
~
!!! unsafelayout: copying a compiler record by value can detach its tagged header; keep a pointer
_ = *typ
~
!!! unsafelayout: copying a compiler record by value can detach its tagged header; keep a pointer
copy := *node
~
!!! unsafelayout: copying a compiler record by value can detach its tagged header; keep a pointer
_ = copy
~
!!! unsafelayout: copying a compiler record by value can detach its tagged header; keep a pointer
pointer := unsafe.Pointer(node)
~
!!! unsafelayout: reinterpret compiler records only through checked casts or generated AST dispatch
_ = pointer
borrowed := BorrowedNode{Node: node}
borrowed.Kind = ast.KindIdentifier
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
_ = &borrowed.Kind
~
!!! unsafelayout: taking a compiler tag's address bypasses checked tag assignment
}

87 changes: 87 additions & 0 deletions tools/customlint/testdata/unsafelayout/internal/ast/ast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package ast

type Kind int16

const (
KindIdentifier Kind = iota
KindImportDeclaration
KindJSImportDeclaration
)

type Node struct {
Kind Kind
}

type Identifier struct {
Node
Text string
}

type ImportDeclaration struct {
Node
}

func (n *Node) AsNode() *Node { return n }

func (n *Node) AsIdentifier() *Identifier {
if n.Kind != KindIdentifier {
panic("Invalid node cast")
}
return nil
}

func (n *Node) AsImportDeclaration() *ImportDeclaration {
switch n.Kind {
case KindImportDeclaration, KindJSImportDeclaration:
return nil
default:
panic("Invalid node cast")
}
}

func newNode(kind Kind, node *Node) *Node {
node.Kind = kind
return node
}

func NewIdentifier(text string) *Node {
data := &Identifier{Text: text}
return newNode(KindIdentifier, data.AsNode())
}

func badFactory() *Node {
data := &ImportDeclaration{}
return newNode(KindIdentifier, data.AsNode())
}

func escapes(kind Kind) *Node {
data := &Identifier{}
_ = newNode
return newNode(kind, data.AsNode())
}

type PretendIdentifier struct {
Identifier
}

func (n *PretendIdentifier) AsNode() *Node { return &n.Node }

func shadowedUpcast() *Node {
data := &PretendIdentifier{}
return newNode(KindIdentifier, data.AsNode())
}

func illegalWrites(node *Node, identifier *Identifier, declaration *ImportDeclaration, kind Kind) {
node.Kind = KindIdentifier
identifier.Kind = KindIdentifier
identifier.Kind = KindImportDeclaration
declaration.Kind = KindImportDeclaration
declaration.Kind = KindJSImportDeclaration
declaration.Kind = kind
declaration.Kind += KindImportDeclaration
node.Kind++
_ = &node.Kind
(node.Kind) = KindIdentifier
(node.Kind)++
_ = &(node.Kind)
}
120 changes: 120 additions & 0 deletions tools/customlint/testdata/unsafelayout/internal/ast/ast.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package ast

type Kind int16

const (
KindIdentifier Kind = iota
KindImportDeclaration
KindJSImportDeclaration
)

type Node struct {
Kind Kind
}

type Identifier struct {
Node
Text string
}

type ImportDeclaration struct {
Node
}

func (n *Node) AsNode() *Node { return n }

func (n *Node) AsIdentifier() *Identifier {
if n.Kind != KindIdentifier {
panic("Invalid node cast")
}
return nil
}

func (n *Node) AsImportDeclaration() *ImportDeclaration {
switch n.Kind {
case KindImportDeclaration, KindJSImportDeclaration:
return nil
default:
panic("Invalid node cast")
}
}

func newNode(kind Kind, node *Node) *Node {
node.Kind = kind
return node
}

func NewIdentifier(text string) *Node {
data := &Identifier{Text: text}
return newNode(KindIdentifier, data.AsNode())
}

func badFactory() *Node {
data := &ImportDeclaration{}
return newNode(KindIdentifier, data.AsNode())
~
!!! unsafelayout: newNode must pair a concrete AsNode() receiver with a compatible kind
}

func escapes(kind Kind) *Node {
data := &Identifier{}
_ = newNode
~
!!! unsafelayout: checked construction must be called directly so its allocation/tag pairing can be verified
return newNode(kind, data.AsNode())
~
!!! unsafelayout: newNode must pair a concrete AsNode() receiver with a compatible kind
}

type PretendIdentifier struct {
Identifier
}

func (n *PretendIdentifier) AsNode() *Node { return &n.Node }

func shadowedUpcast() *Node {
data := &PretendIdentifier{}
return newNode(KindIdentifier, data.AsNode())
~
!!! unsafelayout: newNode must pair a concrete AsNode() receiver with a compatible kind
}

func illegalWrites(node *Node, identifier *Identifier, declaration *ImportDeclaration, kind Kind) {
node.Kind = KindIdentifier
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
identifier.Kind = KindIdentifier
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
identifier.Kind = KindImportDeclaration
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind = KindImportDeclaration
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind = KindJSImportDeclaration
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind = kind
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
declaration.Kind += KindImportDeclaration
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
node.Kind++
~
!!! unsafelayout: incrementing a compiler tag bypasses checked tag assignment
_ = &node.Kind
~
!!! unsafelayout: taking a compiler tag's address bypasses checked tag assignment
(node.Kind) = KindIdentifier
~
!!! unsafelayout: AST kind is immutable outside checked construction; create a new node
(node.Kind)++
~
!!! unsafelayout: incrementing a compiler tag bypasses checked tag assignment
_ = &(node.Kind)
~
!!! unsafelayout: taking a compiler tag's address bypasses checked tag assignment
}

Loading
Loading