export

package
v0.0.0-...-3e5550a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: BSD-3-Clause Imports: 14 Imported by: 0

README

The export data reader and writer

This package reads the export data gc writes and writes export data gc reads, so that nanogo can compile a package that imports one gc compiled and a package gc compiles can import one nanogo compiled. See specs/015-export-data.md for why the format is gc's and not nanogo's own.

It is a port, not a rewrite. The format is undocumented outside its implementation, so a second implementation written from a description would be a second guess. This file is the record of what was copied and of every place the copy differs, so that a re-port against a later release is a file-to-file diff.

Upstream revision

Field Value
Repository https://go.googlesource.com/go
Release go1.27.0
Date Tue Aug 18 21:24:23 2026 +0000

The release rather than a commit, because the sources were copied out of the installed toolchain's GOROOT. That is also the toolchain nanogo is pinned to (driver.PinnedGoVersion), so the code that reads the format and the code that wrote it come from the same tree by construction.

What came from where

Here Upstream
pkgbits/ src/internal/pkgbits/, the container
reader.go src/cmd/compile/internal/importer/ureader.go
support.go src/cmd/compile/internal/importer/support.go
read.go written here; see below
body.go, bodyread.go, bodies.go src/cmd/compile/internal/noder/reader.go's function body half, and linker.go for how a body is reached; see below
bodywrite.go the mirror of bodyread.go; see below
bodybuild.go src/cmd/compile/internal/noder/writer.go's function body half, building a tree rather than a bitstream; see below
writer.go src/cmd/compile/internal/noder/writer.go and linker.go; see below

Which upstream reader, and why

gc's export data has two types-only readers in the Go tree, and they are the same reader twice: go/internal/gcimporter produces go/types packages and cmd/compile/internal/importer produces cmd/compile/internal/types2 packages. nanogo's checker is a fork of types2, so the second one is a port of import paths and positions rather than a translation between two type APIs. specs/015 sizes the port by the same row: 772 non-test lines for the types2 reader against 925 for its go/types twin. File for file, reader.go here is 645 lines against ureader.go's 642.

The third reader, cmd/compile/internal/noder, is the one gc itself uses and is the one that carries function bodies. Its function body half is ported in bodyread.go, so a body reaches nanogo now. Its declaration half is not ported and does not need to be: the types2 reader above is what produces the declarations.

gc reads what nanogo writes with two readers, not one. noder.readPackage walks the object list and importer.ReadPackage, the reader ported here, builds the types. Both run over nanogo's bytes in crossread_test.go.

Divergences

Every entry is a place the copy differs from upstream and the reason. A line that is not here is upstream's.

The container, pkgbits/
Change Why
encoder.go: NewPkgEncoder takes no frame count and Encoder.Sync is a no-op Upstream can write a sync marker before every field. nanogo writes none, for the reason the decoder's Sync records from the other side: the ported reader desyncs on marked data at the first object that stands in for another package's declaration, so data nanogo marked is data nanogo cannot read. The calls stay, so the writer reads as the mirror of the reader.
encoder.go: DumpTo returns its error Upstream asserts it away. The caller is writing a file the build asked for.
encoder.go: fmtFrames is not ported It formats the writer's stack for a sync marker, and there are none.
sync.go: fmtFrames and walkFrames are dropped They format the reader's own backtrace for a desync report, and the panic below carries that backtrace already.
decoder.go: SyncMarkers, TotalElems and Strings are dropped The linker calls them; neither half here does.
decoder.go: Int is back The body reader calls it. A body writes a negative length where an element list may carry keys, and a negative field index where a struct literal names a promoted field, so both widths are read.
codes.go: the Code interface and the Marker/Value methods are back Only the encoder calls them, and there is an encoder now.
decoder.go: PeekPkgPath and PeekObj are back They answer what an element is without decoding it, which is what a writer checking its own output needs.
decoder.go: NewPkgDecoder's header reads report truncation by name Upstream asserts. A file the build handed nanogo has to be reported as a file, and "assertion failed" names nothing.
decoder.go: Decoder.checkErr names the package and the element Upstream reports the error alone, because gc prints it next to the file it was reading. nanogo's driver holds only the package it was asked to compile.
decoder.go: Decoder.Sync panics instead of calling os.Exit(1) gc treats a desync as a compiler bug and ends the process. nanogo is a library the driver calls, so the same event has to come back as an error about the package being compiled.
The reader, reader.go
Change Why
Import paths point at nanogo's types2, syntax and export/pkgbits What the port is for: nanogo's checker is a fork of types2.
pos consumes the position and returns syntax.NoPos; posBases, posBase and posBaseIdx are deleted nanogo's syntax.Pos is an offset into the FileSet the compiled files were parsed with (specs/010), and a file in another package is not in it. The fields are still read: they are inline in the element, and skipping them desyncs everything after. The position base is a reference to another element, so that element is never visited. The writer has the same gap from the other side: it writes every position as absent, so SectionPosBase is empty and a gc diagnostic about a declaration nanogo compiled says the position is unknown.
base.FatalfAt, base.Fatalf and base.Assertf become panicf and assertf Same reason as Decoder.Sync.
enableAlias and its branch are removed It selects between the alias representations of two go/types releases. nanogo is pinned to one.
readerTypeBound is removed Unused upstream as well.
ObjFunc decodes a promoted generic method instead of asserting it cannot appear See below.
The body reader, body.go, bodyread.go and bodies.go

noder/reader.go decodes a body into gc's IR, type checking each node as it builds it. This port decodes the same bytes into a tree of its own. The reason is in specs/015 and the short form is three facts: the encoding has nodes no Go source can spell, types2.Info cannot be filled from outside types2 because TypeAndValue carries an unexported mode, and ir.Build takes a package rather than a function.

Change Why
The tree is export's own, named after the format's statement and expression codes The three facts above. Its consumer is 013's stenciler.
No node is type checked as it is built Upstream reads a node's type off the result of type checking it. Here the type comes out of the stream: gc writes a reshape node carrying the type in front of nearly every expression, and the decoder attaches it to the node it wrapped. That answers the four places the decoding depends on a type, which are the map descriptor after an index, the map descriptor in a range clause, the element encoding of a composite literal, and the descriptor after a call of append, copy, delete or unsafe.Slice.
The reshape node is kept on the expression it wrapped, and not only its type bodywrite.go writes it back, and the type alone cannot say whether there was one: a constant, a zero value and a conversion each carry a type of their own, which the reader falls back to when no reshape node preceded them.
A type the stream does not carry is refused rather than assumed Every one of those four branches has a default that reads fewer bytes. A guess would drop a field silently.
The decode is exact, and a body that leaves a byte or a reference is refused The oracle. See specs/015.
An operator ordinal that is not one of the 32 a body can carry is refused by number The field is gc's ir.Op ordinal and nothing translates it, so an ordinal outside the set is a stream from another release or a desync.
pos keeps the position base as an index and does not resolve it The declaration reader's gap, from the same cause. The element the index names is never visited.
The constant decoder is written here rather than called on the container pkgbits.Decoder.Value resolves a string reference through the container, which the element's reference coverage check cannot see.
The WebAssembly fields of a function's extension data are not read They are written only where the compiling toolchain targeted wasm, and nanogo reads the archives of its own target (specs/030).
bodies.go has no upstream file Upstream finds a body through global maps its own compilation filled. nanogo has no such compilation, so the two paths a body is reached by are walked directly: the private root's list and each declaration's extension data.
The extension data of a defined type is read with no branch, and a function's with one linker.go re-encodes an object's extension data when the object has a definition in gc's IR and copies the writer's bytes when it does not. A generic function has no definition and a generic type does, so a type has one shape and a function has two. gc's own typeExt reader has no branch, which is what settles it.
The body encoder, bodywrite.go

bodywrite.go writes the tree of body.go back into one element of SectionBody. It is the mirror of bodyread.go, field for field and in the same order, so the two files are read side by side rather than one against an upstream file: noder/writer.go's body half writes from syntax and the checker's record, which is a different input, and the file it produces is the stub form.

The oracle is byte identity with gc rather than acceptance by gc. Every body element of every standard library package is decoded, encoded again and compared with gc's own bytes and gc's own reference table. 9,317 of 9,317 match, the nested function literal bodies included.

Change Why
Which element a reference names is asked of a bodyRefs and is not the encoder's The layout belongs to the encoder and the index belongs to the package being written. elemRefs answers with the index the archive the tree was read from already gave it, which is what makes the byte comparison meaningful. A tree built from syntax has no such index and needs a resolver backed by the package writer, which is not built.
A string and a package are looked up in a reverse map of the section, and a section that holds one value twice is refused The reader resolves both to their value rather than keeping the index, so the reverse map is the only way back. gc's encoder interns both sections, so a repeat would make the map a choice rather than an answer. No package of the corpus has one.
A constant is written by dispatching on constant.Val's dynamic type This is pkgbits.Encoder.Value's own rule, applied here so that the string references it makes are this element's. The reader normalises a value on the way in, so a big integer that fits in an int64 comes back as one; gc writes the wide tag only where the value needs it, so nothing in the corpus round-trips to a different tag.
The encoder refuses a tree whose optional field disagrees with the type beside it A map descriptor, a range clause's conversions and a call's runtime type each follow only where the format has room for them, and the reader decides by the same test on the same type. A tree that carries one where the format has none, or leaves one out where it has room, moves every byte after it.
A function literal's body is queued rather than written The literal names an element and does not hold one, so whoever holds the elements writes each queued body after this one.
The body builder, bodybuild.go

bodybuild.go turns syntax plus the checker's record into the tree of body.go, which bodywrite.go then encodes. It is noder/writer.go's function body half with the bitstream replaced by a tree, so the two are read against each other line by line.

The oracle is gc's own tree for the same function. gc's archive holds the tree gc built out of a standard library function's source, and nanogo parses and type checks the same source, so one function has two trees that must be the same tree. Neither can supply the element indices of a package nanogo is not writing, so both are encoded through a resolver that numbers a reference by what it names, and the encodings are compared. 5,968 elements of 371 packages match and none differ.

Change Why
A generic declaration is refused Its body names types derived from the enclosing type parameters, and every such name is a slot of an object dictionary writer.go fills with four zeros. A slot written as an ordinary type reference is a type gc reads without complaint.
A loop over a function is refused gc rewrites the loop into a closure and calls into the runtime before it writes anything, so gc's tree is not a tree of that source.
An increment is recognised by identity and not by absence nanogo's parser gives ++ and -- the shared syntax.ImplicitOne as their right side where gc's parser gives them none.
A negated constant condition folds the way gc folds it, including where gc looks wrong gc returns the operand's own result for a negation rather than the negated one, and the value decides which arm of an if the element holds. No exported body has the shape the two disagree on, so the corpus cannot find this.
Every type a body names is checked not to be derived The check is what says a generic declaration was refused, rather than the builder assuming it.
The writer, writer.go

The writer is not a port of one file. noder/writer.go encodes a package from the type checker's output and produces the stub form, in which a declaration of another package is a name with no definition. noder/linker.go turns that into the linked form by copying each stub's definition out of the archive it came from, and the linked form is the only one that ever reaches a file. writer.go produces the linked form directly, so its shape comes from writer.go for the public part of a declaration and from linker.go for the extension data.

Change Why
No stub for a declaration of another package A file's export data has no stub left except the universe's and unsafe's, and every reader asserts it. nanogo has no linker pass, so a foreign declaration the exported surface reaches is written out in full at the point it is reached.
The public root lists every object in the file This is linker.go's list and not writer.go's. gc builds its stub resolution table from it, so a root naming only nanogo's own declarations leaves gc unable to resolve, say, io.Reader in a bufio signature.
pos writes an absent position The mirror of the reader's gap. See below.
No function body, and the private root lists none bodybuild.go builds a body and bodywrite.go encodes one, and neither is reached from here: export.Write takes a *types2.Package, and a body needs the files and the types2.Info the driver holds. The resolver a built body is encoded through also has to be written, and has to refuse the element it cannot allocate. See specs/015.
A generic declaration is refused by name See below.
funcExt writes no //go: directive The driver records the fourteen verbs its handler recognises, and their positions (driver/pragma.go, specs/016), and nothing carries them this far: the flag bits there are nanogo's own numbering and this field is read with gc's.
funcExt writes no linkname //go:linkname is not one of those fourteen verbs, so the driver records nothing for the writer to drop (016).
funcExt writes ABIInternal and an empty escape note per receiver and parameter Every function nanogo compiles is ABIInternal (specs/030), and an empty note parses as "leaks to the heap", which is what a caller must assume when no escape analysis has run (specs/023 is unbuilt).
typeExt writes -1 for both type descriptor symbol indices The importer finds them by name. It is what gc writes before it has assigned indices of its own.
The private root carries the initialisation flag and no function body driver/inittask.go decides the flag: an importer orders its own record after this package's only when it is set. The body list is empty because there is no body writer.
A local alias is stripped to its right-hand side Upstream does the same, to keep two local aliases from colliding on one symbol.
An empty interface is written as a reference to any Both spellings are one type. The reader has already lost the difference: types2.NewInterfaceType returns the one canonical empty interface for interface{} and for any, so the writer cannot tell them apart. Only the printed form differs.
What the writer made required elsewhere

A package that can be imported owes an importer more than its export data. gc refers to an imported type twice, directly for the runtime type descriptor and through DWARF for go:info.<path>.<Type>, and cmd/link builds the second out of the first, so both come back to type:<path>.<Type>. nanogo writes no descriptor for a declared type, and driver/types.go refuses such a package by name rather than letting the build fail at link time. The gap is specs/032 and not this package's; specs/015 records the measurement.

Why a generic declaration is refused

A generic declaration cannot be written without a function body, and the format says so rather than the implementation guessing it. linker.go writes the relocated extension data for a function as Bool(true) followed by the ABI, the escape notes and the inlining cost; but it takes that branch only when the object has a definition, and a generic function never does. For a generic it copies the stub extension data verbatim, which is Bool(false) followed by a reference to a SectionBody element. There is no third shape.

gc's reader agrees from the other side: for an instantiation it sets name.Defn and then asserts name.Defn == nil inside the Bool(true) branch, so a generic written that way fails on the first importer that instantiates it, with a message that names neither the generic nor the package.

So the writer refuses, and the message names the declaration. 100 of the 375 standard library packages are refused for it, and 4 of the 27 packages with export data in the closure of an empty main: internal/abi, internal/bytealg, internal/runtime/atomic and runtime. All four are refused by the driver for other reasons as well.

The archive, read.go

Upstream splits this between cmd/compile/internal/importer/gcimporter.go and internal/exportdata. Neither is ported.

gcimporter.go finds a package's archive with go/build's search rules, which is how a tool that was handed an import path and a source directory locates a build it did not run. nanogo is handed the file: the go command writes -importcfg and specs/050 makes reading it the driver's job. Porting the search would add a second answer to a question the build already answered.

internal/exportdata reads the archive through a bufio.Reader and assumes __.PKGDEF is the first member. read.go walks the members instead, because that assumption is not in the format, and reports each malformed shape by name. writer.go's Definition builds the same member and driver/archive.go writes it first, because that assumption is in internal/exportdata's reader and nanogo has to satisfy it.

The promoted generic method

A method with type parameters of its own is new in Go 1.27 (types2/resolver.go gates it on the go1.27 language version). gc promotes one to a package-scope object under a name no source can spell, such as (*List).Zip or Point.Map, so it appears in the export data whether an importer wants it or not. The two upstream readers do two different things with it, and this reader does a third.

go/internal/gcimporter drops it. Its objIdx returns early on any object name that holds a ., so the object is never decoded and never reaches a scope, and importing a package that declares one succeeds with the method present on its defining type and absent from the package scope.

cmd/compile/internal/importer, the reader ported here, has no such early return. It inserts the object lazily under the unspellable name and asserts the standalone bool is false when something decodes it. A reader that looks up only names a source can spell never decodes it, so the assertion does not fire there.

nanogo cannot leave it lazy. writer.go looks every name in the scope up before it asks whether the object is exported, so every name the export data declares is decoded on every package nanogo writes, and an assertion would refuse the package. ObjFunc therefore decodes the promoted object, and the scope holds it: on the fixture in export_test.go this reader's scope holds 18 names against go/internal/gcimporter's 16, the two extra being (*List).Zip and Point.Map. The type that declares the method decodes it a second time through ObjType, and that copy is the one in the method set.

What sync-marked export data costs both readers

gc built with -d=syncframes writes a sync marker before every field. Reading such an archive works until the first object that stands in for a declaration of another package, where the marker stream desyncs. go/internal/gcimporter fails on the same archive at the same offset, so this is upstream's and not the port's. export_test.go's marker fixture has no import for that reason, and ordinary export data has no markers at all.

Documentation

Overview

Package export reads the export data gc writes, so that nanogo can compile a package that imports one gc compiled.

The reader is a port of cmd/compile/internal/importer, which is the types2-shaped half of the pair whose other half is go/internal/gcimporter. See README.md for the upstream revision and for every place this copy diverges from it.

Index

Constants

View Source
const MaxInlineCost = 80

MaxInlineCost is the price nanogo offers an exported body at.

It is cmd/compile/internal/inline.inlineMaxBudget, which is the cost of the largest body gc's default budget accepts. gc reads the field as the budget the body spends and uses it twice: to decide whether to inline a call to this function, and to charge a function that calls this one when deciding whether that one can be inlined in turn.

nanogo runs no inliner and measures no hairiness (specs/024-inlining-and-devirtualization.md), so the number is a policy and not a measurement, and the policy is the conservative end of both uses. A caller is charged the most gc's budget allows, so no caller is made inlinable by an understated price. And a big caller, whose budget is 20, inlines nothing nanogo exported, which is where gc is most careful with its own bodies too.

View Source
const Version = pkgbits.V4

Version is the unified IR version nanogo writes.

It is cmd/compile/internal/noder.uirVersion, not the newest version the container knows. A reader refuses a stream newer than itself, so the version is a property of the release nanogo is pinned to (specs/000-decisions.md decision 10) and not of this package.

Variables

This section is empty.

Functions

func Definition

func Definition(header string, main bool, payload []byte) ([]byte, error)

Definition returns the body of an archive's __.PKGDEF member.

It is [read.go]'s container from the other side: the object header line, then the header lines the compiler adds, then the export data section. The blank line ends the headers, "$$B" says the section is binary and 'u' says it is the unified format.

header is the "go object ..." line the installed toolchain writes, with its newline; obj.VerifyToolchain reports it. main says the package is a main package, which is the one fact the linker reads out of the header lines.

func Payload

func Payload(archive []byte) ([]byte, error)

Payload returns the unified export data one gc archive carries.

It is Definition from the other side, and it is what a reader that wants the bytes rather than the package needs: pkgbits.NewPkgDecoder takes exactly this, and ReadBodies takes the decoder.

func ReadPackage

func ReadPackage(ctxt *types2.Context, imports map[string]*types2.Package, input pkgbits.PkgDecoder) *types2.Package

ReadPackage decodes one package from an already opened container.

imports is shared across every archive one compilation reads, because an archive names the packages its declarations mention and materialises them as a side effect. Only the package the archive is for is marked complete.

Most callers want Reader.Read, which opens the archive and turns a stream it cannot decode into an error.

func SymName

func SymName(fn *types2.Func) (string, bool)

SymName returns the name gc's linker gives a function or a method, which is the name the private root's body list names a body by.

A method is "T.M" for a value receiver and "(*T).M" for a pointer one. The second result is false for a method whose receiver is not a defined type, which no declaration has.

func Write

func Write(pkg *types2.Package, hasInit bool, src *Source) (data []byte, fingerprint [8]byte, err error)

Write encodes pkg's exported surface as gc's unified export data and returns the payload and its fingerprint.

The payload is what goes between the "$$B\nu" and "\n$$\n" markers of an archive's __.PKGDEF member; Definition wraps it. The fingerprint has to reach the object nanogo writes for the same package: an importing object records it in its Autolib entry and the linker refuses a build whose two copies disagree.

What is written is the linked form, which is the only form that reaches a file. gc writes a stub form first, in which a declaration of another package is a name with no definition, and its linker resolves every stub by copying the definition out of the archive it came from. nanogo has no such two-step, so a declaration of another package that the exported surface reaches is written out in full here. Only the universe and unsafe stay stubs, which is what every reader of the format expects.

hasInit says the object carries the package's initialisation record. An importer reads it and orders its own record after this one, so a package that has a record and says it has none is a package whose initialisation never runs, and a package that says it has one and has none is a link failure. driver/inittask.go decides it.

src is what the package's own source adds to what the checker recorded: the positions of the declarations and the function bodies an importer can inline. It is nil for a package written without either, and then every position is absent and no body reaches the file. A body the writer cannot allocate every element of is left out rather than guessed at: see [writableBodies].

Types

type AssertExpr

type AssertExpr struct {
	X    Expr
	Pos  Pos
	Type ExprType
	Src  RType
	// contains filtered or unexported fields
}

An AssertExpr is x.(T).

func (*AssertExpr) ExprType

func (e *AssertExpr) ExprType() types2.Type

func (*AssertExpr) Reshape

func (e *AssertExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type AssignKind

type AssignKind int

An AssignKind names one assignment destination encoding.

const (
	AssignBlank AssignKind = iota
	AssignDef
	AssignExpr
)

The assignment destination encodings, in the format's order.

func (AssignKind) Marker

func (c AssignKind) Marker() pkgbits.SyncMarker

func (AssignKind) String

func (c AssignKind) String() string

func (AssignKind) Value

func (c AssignKind) Value() int

type AssignOpStmt

type AssignOpStmt struct {
	Op  Op
	Lhs Expr
	Pos Pos
	Rhs Expr
}

An AssignOpStmt is an assignment that applies an operator, such as x += y.

type AssignStmt

type AssignStmt struct {
	Pos Pos
	Lhs []Assignee
	Rhs MultiExpr
}

An AssignStmt is an assignment, a short variable declaration, or a var declaration inside a function.

type Assignee

type Assignee struct {
	Kind AssignKind

	// Kind == AssignDef: the variable the assignment declares.
	Pos   Pos
	Name  string
	Pkg   *types2.Package
	Type  TypeUse
	Local Local

	// Kind == AssignExpr.
	Expr Expr
}

An Assignee is one destination of an assignment.

type BinaryExpr

type BinaryExpr struct {
	Op  Op
	X   Expr
	Pos Pos
	Y   Expr
	// contains filtered or unexported fields
}

A BinaryExpr is a binary operation.

func (*BinaryExpr) ExprType

func (e *BinaryExpr) ExprType() types2.Type

func (*BinaryExpr) Reshape

func (e *BinaryExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type BlockStmt

type BlockStmt struct {
	Open  Pos
	Body  []Stmt
	Close Pos
}

A BlockStmt is a block, with the positions of the braces that open and close its scope.

type Body

type Body struct {
	// Params is one entry per receiver, parameter and result, in that
	// order. They are the first locals, and a local is referred to by its
	// index in declaration order.
	Params []Local

	// HasBlock is false for a declaration with no body, which is a function
	// implemented in assembly or by a linkname.
	HasBlock bool

	// Stmts is the body, and Rbrace is its closing brace.
	Stmts  []Stmt
	Rbrace Pos

	// Dict is the object dictionary the declaration this body belongs to
	// needs, which [BodySource.BuildBody] fills while it builds the body.
	// It is nil for a body read from an archive, which names the slots of a
	// dictionary that archive already holds.
	Dict *Dict
}

A Body is one function body, decoded from one element of SectionBody.

The element does not say how many parameters the declaration has, so it cannot be decoded on its own: Params is as long as the receiver plus the parameters plus the results of the signature that names the body. See [ReadBody].

type BodyError

type BodyError struct {
	Package string // the package the body was read from or written for
	Name    string // the declaration the body belongs to
	Reason  string // what the reader cannot decode or the encoder cannot write

	// Writing is true for a body the encoder refused. The two halves refuse
	// different things, and a message that names one about the other sends a
	// user to the wrong side of the format.
	Writing bool
}

BodyError reports a body the reader cannot decode.

The declaration is named, because it is what a user has to work around and what specs/015-export-data.md's census counts.

func (*BodyError) Error

func (e *BodyError) Error() string

type BodySource

type BodySource struct {
	// contains filtered or unexported fields
}

A BodySource is the checker's record of one package, which is everything a body is built from.

It holds no state of its own between bodies: two calls of BuildBody are independent, because a body's locals are numbered inside the body and nothing outside it can name one.

func NewBodySource

func NewBodySource(pkg *types2.Package, info *types2.Info, fset *syntax.FileSet) *BodySource

NewBodySource returns the source of bodies for one checked package.

info must carry Types, Defs, Uses, Implicits, Selections and Instances: the builder reads a node's type, the object a name denotes, the field or method a selector resolves to, and the type arguments an inferred instantiation got, and none of the four is recoverable from syntax.

func (*BodySource) BuildBody

func (s *BodySource) BuildBody(name string, sig *types2.Signature, block *syntax.BlockStmt) (body *Body, err error)

BuildBody builds the tree of one function body.

name is the declaration the body belongs to and is what a refusal reports. sig is its signature, which is what numbers the first locals. block is nil for a declaration with no body, which is a function implemented in assembly or by a linkname.

type BranchStmt

type BranchStmt struct {
	Pos      Pos
	Op       Op
	Labelled bool
	Label    string
}

A BranchStmt is break, continue, goto or fallthrough.

type CallExpr

type CallExpr struct {

	// Method is set for a call through a method selection.
	Method *MethodCall

	// Inst is set for a call of an instantiated generic function.
	Inst    *FuncInst
	InstPos Pos

	// Fun is the callee for every other call.
	Fun Expr

	Pos  Pos
	Args MultiExpr
	Dots bool

	// RType is the descriptor append, copy, delete and unsafe.Slice need,
	// and is nil for every other callee.
	RType *RType
	// contains filtered or unexported fields
}

A CallExpr is a call.

func (*CallExpr) ExprType

func (e *CallExpr) ExprType() types2.Type

func (*CallExpr) Reshape

func (e *CallExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type CallStmt

type CallStmt struct {
	Pos  Pos
	Op   Op
	Call Expr

	// DeferAt is the defer record a defer statement runs in, and is nil for
	// a defer that uses the frame's own record and for go.
	DeferAt Expr
}

A CallStmt is go or defer.

type CapturedVar

type CapturedVar struct {
	Pos   Pos
	Local LocalExpr
}

A CapturedVar is one variable a function literal captures.

type CaseClause

type CaseClause struct {
	// ScopeClose is the position that closes the previous clause's scope
	// and is only set for a clause after the first.
	ScopeClose *Pos
	ScopeOpen  Pos
	Pos        Pos

	// Types is set for a type switch, one entry per case. A nil Type is the
	// case nil.
	Types []*ExprType

	// Exprs is set for an expression switch.
	Exprs []Expr

	// Var is the variable a named type switch guard declares for this
	// clause.
	Var     *Local
	VarPos  Pos
	VarType TypeUse

	Body []Stmt
}

A CaseClause is one clause of a switch.

type CommClause

type CommClause struct {
	ScopeClose *Pos
	ScopeOpen  Pos
	Pos        Pos
	Comm       []Stmt
	Body       []Stmt
}

A CommClause is one clause of a select.

type CompLitExpr

type CompLitExpr struct {
	Pos  Pos
	Type TypeUse

	// MapRType is the descriptor of the map being built, and is nil for
	// every other kind of literal.
	MapRType *RType

	// Keyed is false when no element has a key, which is the compact form
	// the format's version V3 added.
	Keyed bool
	Elems []LitElem
	// contains filtered or unexported fields
}

A CompLitExpr is a composite literal.

func (*CompLitExpr) ExprType

func (e *CompLitExpr) ExprType() types2.Type

func (*CompLitExpr) Reshape

func (e *CompLitExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type ConstExpr

type ConstExpr struct {
	Pos   Pos
	Type  TypeUse
	Value constant.Value
	// contains filtered or unexported fields
}

A ConstExpr is a constant. gc folds a constant expression before it writes it, so the source's operators are not here.

func (*ConstExpr) ExprType

func (e *ConstExpr) ExprType() types2.Type

func (*ConstExpr) Reshape

func (e *ConstExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type ConvRTTI

type ConvRTTI struct {
	Src     RType
	Dst     RType
	Derived bool
	DictIdx int // the itab dictionary slot, when Derived
}

A ConvRTTI is the pair of descriptors a conversion from one type to another needs at run time.

type ConvertExpr

type ConvertExpr struct {

	// Implicit is true for a conversion the source did not spell, which the
	// assignability rules of the specification require.
	Implicit bool

	Type TypeUse
	Pos  Pos
	Conv ConvRTTI

	// TypeParam is true when the destination is a type parameter, and
	// Identical is true when the two types are identical, which happens for
	// an explicit conversion that changes nothing.
	TypeParam bool
	Identical bool

	X Expr
	// contains filtered or unexported fields
}

A ConvertExpr is a conversion.

func (*ConvertExpr) ExprType

func (e *ConvertExpr) ExprType() types2.Type

func (*ConvertExpr) Reshape

func (e *ConvertExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type Dict

type Dict struct {
	// Implicits are the type parameters of an enclosing declaration, which
	// only a type declared inside a generic function has. Receivers are the
	// receiver's type parameters, which only a generic method has, and
	// TypeParams are the declaration's own.
	//
	// The three are one numbering, in that order, which is what a reference
	// to a type parameter is written in. See [Dict.TypeParamIndex].
	Implicits  []*types2.TypeParam
	Receivers  []*types2.TypeParam
	TypeParams []*types2.TypeParam

	// Derived is every type the declaration names whose identity depends on
	// a type parameter, in allocation order.
	Derived []types2.Type

	// MethodExprs, Subdicts, RTypes and Itabs are the runtime lists, in
	// allocation order. Each is a slot of the dictionary an instantiation
	// is passed.
	MethodExprs []MethodExprSlot
	Subdicts    []ObjUse
	RTypes      []TypeUse
	Itabs       []ItabSlot

	// Pkg is the package the declaration belongs to. It is what tells a type
	// declared inside the declaration from one declared elsewhere.
	Pkg *types2.Package
	// contains filtered or unexported fields
}

The object dictionary of one declaration.

A generic declaration's body names types whose identity depends on the enclosing type parameters, and it names runtime values that only exist once the type arguments are known. Neither can be an element of the package, because there is one element per type and there is one such type per instantiation. The format puts them in a dictionary instead: the body names a slot, and the reader resolves the slot against the type arguments the instantiation supplied.

This is cmd/compile/internal/noder.writerDict, with the elements left out. gc allocates a slot while it writes the bitstream, so the slot numbers are a property of the order gc's writer walks a declaration in. A slot the builder numbers differently is a slot gc reads as another type, and gc reads it without complaint, so the numbering is the whole of the problem.

The five lists are what gc's objDict writes and what the four call sites the body encoder has fill:

rtype and varDictIndex -> RTypes
itab, which convRTTI is a use of -> Itabs
a call of an instantiated function or method -> Subdicts
a method expression on a type parameter -> MethodExprs

Derived is not a runtime list. It is the type section of the dictionary: every type the declaration names whose identity depends on a type parameter, in the order gc writes their elements.

func (*Dict) Derive

func (d *Dict) Derive(typ types2.Type) (int, bool, error)

Derive returns the dictionary slot a type is named by, and false when the type's identity does not depend on a type parameter.

This is cmd/compile/internal/noder.pkgWriter.typIdx with the elements left out. gc allocates the slot of a type after it has written the element of every type that type names, so a composite type's slot follows the slots of its components, and the walk below is the order of gc's encoding rather than an order of this package's choosing. A slot numbered otherwise is a slot gc reads as a different type, and gc reads it without complaint.

One allocator answers the body builder and the export data writer, so that the slot a body names and the slot the dictionary holds cannot disagree. The error is what neither can encode, and each reports it in its own shape.

func (*Dict) Generic

func (d *Dict) Generic() bool

Generic reports whether the declaration the dictionary belongs to has any type parameter, which is the only case in which a slot can be named.

func (*Dict) ItabIndex

func (d *Dict) ItabIndex(typ, iface TypeUse) int

ItabIndex returns the slot holding the method table for typ as iface, adding it if it is new.

func (*Dict) MethodExprIndex

func (d *Dict) MethodExprIndex(tp int, sel Selector) int

MethodExprIndex returns the slot holding the method a type parameter's method expression resolves to, adding it if it is new.

func (*Dict) RTypeIndex

func (d *Dict) RTypeIndex(t TypeUse) int

RTypeIndex returns the slot holding t's runtime type descriptor, adding it if it is new.

func (*Dict) SubdictIndex

func (d *Dict) SubdictIndex(use ObjUse) int

SubdictIndex returns the slot holding the dictionary of one instantiation, adding it if it is new.

func (*Dict) TypeParamIndex

func (d *Dict) TypeParamIndex(tp *types2.TypeParam) (int, bool)

TypeParamIndex returns the index a reference to tp is written as.

The enclosing declaration's type parameters come first, then the receiver's, and the declaration's own follow at the position they were declared in. A type parameter that is none of the three cannot be named by this declaration, and the index is then out of range for its dictionary, which is why it is a refusal rather than a fallthrough.

type Expr

type Expr interface {

	// Reshape is the reshape node the format wrote in front of the
	// expression, and is nil where it wrote none.
	Reshape() *TypeUse

	// ExprType is the type of the value the expression produces, and is nil
	// where the stream did not carry one. It is nil for an expression of a
	// tuple type, for a reference to a builtin, and for a use of a local.
	ExprType() types2.Type
	// contains filtered or unexported methods
}

An Expr is one expression of a body.

Every expression that has a type in the checker's record is preceded in the stream by its type, because gc writes a reshape node in front of it. The decoder attaches that type to the expression it wraps, so Expr.ExprType answers for nearly every node without the tree being type checked again.

type ExprKind

type ExprKind int

An ExprKind names one expression encoding.

const (
	ExprConst ExprKind = iota
	ExprLocal
	ExprGlobal
	ExprCompLit
	ExprFuncLit
	ExprFieldVal
	ExprMethodVal
	ExprMethodExpr
	ExprIndex
	ExprSlice
	ExprAssert
	ExprUnaryOp
	ExprBinaryOp
	ExprCall
	ExprConvert
	ExprNew
	ExprMake
	ExprSizeof
	ExprAlignof
	ExprOffsetof
	ExprZero
	ExprFuncInst
	ExprRecv
	ExprReshape
	ExprRuntimeBuiltin
)

The expression encodings, in the format's order.

func (ExprKind) Marker

func (c ExprKind) Marker() pkgbits.SyncMarker

func (ExprKind) String

func (c ExprKind) String() string

func (ExprKind) Value

func (c ExprKind) Value() int

type ExprStmt

type ExprStmt struct{ X Expr }

An ExprStmt is an expression evaluated for its effect.

type ExprType

type ExprType struct {
	Pos Pos

	// Itab is set when the type is being matched against a non-empty
	// interface, and RType is set otherwise.
	Itab    *ConvRTTI
	RType   *RType
	Derived bool
}

An ExprType is a type written where an expression is expected, which is a type assertion's type, a type switch case, and make's and new's first argument.

type FieldValExpr

type FieldValExpr struct {
	X   Expr
	Pos Pos
	Sel Selector
	// contains filtered or unexported fields
}

A FieldValExpr is x.f, where f is a field.

func (*FieldValExpr) ExprType

func (e *FieldValExpr) ExprType() types2.Type

func (*FieldValExpr) Reshape

func (e *FieldValExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type ForStmt

type ForStmt struct {
	Open  Pos
	Range *RangeClause

	Pos  Pos
	Init []Stmt
	Cond Expr
	Post []Stmt

	Body *BlockStmt

	// DistinctVars says the loop declares its variables anew on every
	// iteration, which is the Go 1.22 rule.
	DistinctVars bool
}

A ForStmt is a for statement. Range is set for a range clause and the three-clause fields are set otherwise.

type FuncBody

type FuncBody struct {
	// Path and Name are the declaration, as the export data names it. Name
	// is gc's linker symbol name, so a method is "T.M" or "(*T).M".
	Path string
	Name string

	// Generic is true for a body reached through the declaration's
	// extension data, which is the shape a generic declaration has and the
	// one an importer needs in order to instantiate it
	// (specs/013-generics.md). It is false for a body reached through the
	// private root, which is an inlinable body.
	Generic bool

	// Idx is the SectionBody element, and Body is it decoded.
	Idx  pkgbits.Index
	Body *Body

	// Nested is the number of function literal bodies inside this one,
	// each of which is an element of its own that was decoded with it.
	Nested int
}

A FuncBody is one function body with the declaration it belongs to.

func ReadBodies

func ReadBodies(ctxt *types2.Context, imports map[string]*types2.Package, input pkgbits.PkgDecoder) (*types2.Package, []*FuncBody, error)

ReadBodies reads a package's declarations and then every function body its export data carries.

The package is returned whether or not a body could be read, because the declarations are what an importer needs first and a body that cannot be read is a refusal about one declaration rather than about the package. A refusal is a *BodyError naming the declaration.

type FuncInst

type FuncInst struct {
	// Derived is true when a type argument depends on the enclosing
	// declaration's type parameters, and DictIdx is then the subdictionary
	// slot the call takes its dictionary from.
	Derived bool
	DictIdx int
	Obj     ObjUse
}

A FuncInst is a reference to an instantiated generic function.

type FuncInstExpr

type FuncInstExpr struct {
	Pos  Pos
	Inst FuncInst
	// contains filtered or unexported fields
}

A FuncInstExpr is a reference to an instantiated generic function that is not immediately called.

func (*FuncInstExpr) ExprType

func (e *FuncInstExpr) ExprType() types2.Type

func (*FuncInstExpr) Reshape

func (e *FuncInstExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type FuncLitExpr

type FuncLitExpr struct {
	Pos Pos

	// Params and Results are the literal's signature. A literal has no
	// receiver, so the two together are as long as its body's Params.
	Params   []Param
	Results  []Param
	Variadic bool

	// RangeFuncBody is true for the closure gc builds out of the body of a
	// range over a function.
	RangeFuncBody bool

	// Captured is one entry per variable the literal captures, naming it in
	// the enclosing body's numbering.
	Captured []CapturedVar

	// Body is the index of the SectionBody element holding the literal's
	// body, and Decoded is that body once it has been read.
	Body    pkgbits.Index
	Decoded *Body
	// contains filtered or unexported fields
}

A FuncLitExpr is a function literal.

func (*FuncLitExpr) ExprType

func (e *FuncLitExpr) ExprType() types2.Type

func (*FuncLitExpr) Reshape

func (e *FuncLitExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type GlobalExpr

type GlobalExpr struct {
	Obj ObjUse
	// contains filtered or unexported fields
}

A GlobalExpr is a use of a package-scope declaration, of a builtin, or of an unsafe intrinsic.

func (*GlobalExpr) ExprType

func (e *GlobalExpr) ExprType() types2.Type

func (*GlobalExpr) Reshape

func (e *GlobalExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type IfStmt

type IfStmt struct {
	Open      Pos
	Pos       Pos
	Init      []Stmt
	Cond      Expr
	Static    int
	Then      *BlockStmt
	ThenClose Pos
	Else      []Stmt
}

An IfStmt is an if statement.

Static is the constant value of the condition, if it has one: 1 for a condition that is always true, -1 for one that is always false, and 0 for one that is not constant. gc omits the branch it proved unreachable, so Then is nil when Static is negative and Else is nil when Static is positive.

type Import

type Import struct {
	// Path is the import path the export data was read under, after any
	// importmap rename.
	Path string

	// File is the archive it came from.
	File string

	// Fingerprint identifies the export data. The linker compares it with
	// the one in the imported package's own object and refuses a build
	// whose two copies disagree.
	Fingerprint [8]byte
}

Import is one package this compilation read export data for.

type IncDecStmt

type IncDecStmt struct {
	Op  Op
	X   Expr
	Pos Pos
}

An IncDecStmt is x++ or x--.

type IndexExpr

type IndexExpr struct {
	X     Expr
	Pos   Pos
	Index Expr

	// MapRType is the descriptor of the map being indexed, and is nil when
	// x is not a map.
	MapRType *RType
	// contains filtered or unexported fields
}

An IndexExpr is x[i].

func (*IndexExpr) ExprType

func (e *IndexExpr) ExprType() types2.Type

func (*IndexExpr) Reshape

func (e *IndexExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type InlineFunc

type InlineFunc struct {
	// Obj is the declaration. It is what pairs the body with the extension
	// data that says the declaration has one.
	Obj *types2.Func

	// Name is gc's linker symbol name for the declaration: "F" for a
	// function, "T.M" or "(*T).M" for a method. gc looks a body up in the
	// private root's list by this name and the package path.
	Name string

	// Cost is the inlining budget the body spends, in gc's units. gc reads
	// it and inlines the call when the cost is inside the budget of the
	// function it would inline into.
	Cost int

	// Body is the tree [BodySource.BuildBody] built.
	Body *Body
}

An InlineFunc is one declaration whose body gc can inline.

type ItabSlot

type ItabSlot struct {
	Type  TypeUse
	Iface TypeUse
}

An ItabSlot is the pair of types an interface conversion compares.

type LabelStmt

type LabelStmt struct {
	Pos   Pos
	Label string
}

A LabelStmt is a label. The statement it labels is the next statement of the same list, because gc writes the two flat.

type LitElem

type LitElem struct {
	// Pos is the position of the key, or of the element for a struct
	// literal with no key.
	Pos Pos

	// Key is set for an element of an array, slice or map literal written
	// with a key.
	Key Expr

	// Field is the field index of an element of a struct literal, and
	// Embedded is the path to it through embedded fields when the key names
	// a promoted field.
	Field    int
	Embedded []int

	Value Expr
}

A LitElem is one element of a composite literal.

type Local

type Local struct {
	// DictRType is the runtime type slot of a local whose type is derived
	// from the enclosing declaration's type parameters, and -1 for a local
	// whose type is known without a dictionary.
	DictRType int
}

A Local is one local variable's declaration in a body.

The variable has no name and no object here. gc numbers locals in declaration order and refers to one by its number, so a body carries its own local numbering and nothing outside the body can name a local.

type LocalExpr

type LocalExpr struct {

	// Captured is true when Index names a captured variable rather than a
	// local of this body.
	Captured bool
	Index    int
	// contains filtered or unexported fields
}

A LocalExpr is a use of a local variable or of a variable captured by a function literal.

func (*LocalExpr) ExprType

func (e *LocalExpr) ExprType() types2.Type

func (*LocalExpr) Reshape

func (e *LocalExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type MakeExpr

type MakeExpr struct {
	Pos   Pos
	Type  ExprType
	Args  []Expr
	RType RType
	// contains filtered or unexported fields
}

A MakeExpr is make(T, ...).

func (*MakeExpr) ExprType

func (e *MakeExpr) ExprType() types2.Type

func (*MakeExpr) Reshape

func (e *MakeExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type MethodCall

type MethodCall struct {
	Recv   Expr
	Method MethodRef
}

A MethodCall is the callee of a call through a method selection.

type MethodExprExpr

type MethodExprExpr struct {
	Recv TypeUse

	// Implicits is the path of embedded fields the selection goes through.
	Implicits []int

	// Deref and Addr say whether the receiver needs one before the method
	// is applied.
	Deref bool
	Addr  bool

	Pos    Pos
	Method MethodRef
	// contains filtered or unexported fields
}

A MethodExprExpr is T.m, where the result is a function whose first parameter is the receiver.

func (*MethodExprExpr) ExprType

func (e *MethodExprExpr) ExprType() types2.Type

func (*MethodExprExpr) Reshape

func (e *MethodExprExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type MethodExprSlot

type MethodExprSlot struct {
	// TypeParam is the type parameter's index in the dictionary's own
	// numbering, which [Dict.TypeParamIndex] gives.
	TypeParam int
	Sel       Selector
}

A MethodExprSlot is a method named on a type parameter, which the body reaches through the dictionary because the receiver's method is not known until the type argument is.

type MethodRef

type MethodRef struct {
	Recv TypeUse

	// Generic is true for a method that declares type parameters of its
	// own, and Sig is the method's signature otherwise.
	Generic bool
	Sig     TypeUse

	Pos Pos
	Sel Selector

	// TypeParam is set when the receiver is a type parameter, so that the
	// call goes through the dictionary at DictIdx.
	TypeParam bool
	DictIdx   int

	// Subdict is set when the type arguments are not all known statically,
	// and StaticDict is set when they are and the method needs one.
	Subdict    bool
	SubdictIdx int
	StaticDict bool
	Dict       ObjUse
}

A MethodRef is a reference to the method a selection names.

type MethodValExpr

type MethodValExpr struct {
	Recv   Expr
	Pos    Pos
	Method MethodRef
	// contains filtered or unexported fields
}

A MethodValExpr is x.m, where m is a method and the result is a bound method value.

func (*MethodValExpr) ExprType

func (e *MethodValExpr) ExprType() types2.Type

func (*MethodValExpr) Reshape

func (e *MethodValExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type MultiExpr

type MultiExpr struct {
	// Single is set for the one-expression form. Values are then the
	// results, in order, each with the type it is converted to.
	Single  bool
	Pos     Pos
	Expr    Expr
	Results []MultiResult

	// Exprs is the one-expression-per-value form.
	Exprs []Expr
}

A MultiExpr is a list of values, which is either one expression per value or one multi-valued expression spread over all of them.

type MultiResult

type MultiResult struct {
	Src       TypeUse
	Converted bool
	Dst       TypeUse
	Conv      ConvRTTI
}

A MultiResult is one result of a multi-valued expression.

type NewExpr

type NewExpr struct {
	Pos Pos

	// Value is set for new(x), which Go 1.26 added, and Type is set for
	// new(T).
	Value Expr
	Type  *ExprType
	// contains filtered or unexported fields
}

A NewExpr is new(T) or new(x).

func (*NewExpr) ExprType

func (e *NewExpr) ExprType() types2.Type

func (*NewExpr) Reshape

func (e *NewExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type ObjUse

type ObjUse struct {
	Idx   pkgbits.Index
	Pkg   *types2.Package // nil for the universe
	Name  string
	Obj   types2.Object // nil for a declaration the scope has no object for
	Targs []TypeUse
}

An ObjUse is a reference to a package-scope declaration from inside a body, with the type arguments it is instantiated with.

type OffsetofExpr

type OffsetofExpr struct {
	Pos  Pos
	Type TypeUse

	// Path is the field index at each step of the selection, so a selection
	// through an embedded field has more than one entry.
	Path []int
	// contains filtered or unexported fields
}

An OffsetofExpr is unsafe.Offsetof.

func (*OffsetofExpr) ExprType

func (e *OffsetofExpr) ExprType() types2.Type

func (*OffsetofExpr) Reshape

func (e *OffsetofExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type Op

type Op int

An Op is the operator a body carries on an operation, a branch, or a deferred or concurrent call.

The value is gc's ir.Op ordinal, because that is what reaches the file: noder/writer.go's op writes int(op) and nothing translates it. The ordinals are dense over gc's whole node set, and only the ones below can appear in a body, so an ordinal that is not one of them is a stream this reader refuses rather than a node it guesses at.

const (
	OpAdd      Op = 6   // x + y
	OpSub      Op = 7   // x - y
	OpOr       Op = 8   // x | y
	OpXor      Op = 9   // x ^ y
	OpAddr     Op = 11  // &x
	OpAndAnd   Op = 12  // x && y
	OpEq       Op = 57  // x == y
	OpNe       Op = 58  // x != y
	OpLt       Op = 59  // x < y
	OpLe       Op = 60  // x <= y
	OpGe       Op = 61  // x >= y
	OpGt       Op = 62  // x > y
	OpDeref    Op = 63  // *x
	OpMul      Op = 74  // x * y
	OpDiv      Op = 75  // x / y
	OpMod      Op = 76  // x % y
	OpLsh      Op = 77  // x << y
	OpRsh      Op = 78  // x >> y
	OpAnd      Op = 79  // x & y
	OpAndNot   Op = 80  // x &^ y
	OpNot      Op = 82  // !x
	OpBitNot   Op = 83  // ^x
	OpPlus     Op = 84  // +x
	OpNeg      Op = 85  // -x
	OpOrOr     Op = 86  // x || y
	OpRecv     Op = 100 // <-x
	OpBreak    Op = 116 // break
	OpContinue Op = 118 // continue
	OpDefer    Op = 119 // defer
	OpFall     Op = 120 // fallthrough
	OpGoto     Op = 122 // goto
	OpGo       Op = 125 // go
)

The operators a body can carry. The names are gc's without its O prefix, and the values are gc's ir.Op ordinals on the pinned release.

func (Op) String

func (op Op) String() string

type Param

type Param struct {
	Pos  Pos
	Pkg  *types2.Package
	Name string
	Type TypeUse
}

A Param is one parameter or result of a signature written inside a body.

type Pos

type Pos struct {
	Known bool
	Base  pkgbits.Index
	File  string
	Line  uint
	Col   uint
}

A Pos is a source position, as the format carries it.

nanogo has no coordinate space for a file of another package (specs/010-scanner-and-positions.md), so a position read from an archive is not turned into a syntax.Pos. Known is false for the absent position.

The base is named twice, and the two names have different owners. Base is the SectionPosBase element of the archive the position was read from, and is meaningless in a position built from syntax. File is the file name that element holds, and is the only name a position built from syntax has: a writer allocates the element from it.

type RType

type RType struct {
	Derived bool
	DictIdx int     // the dictionary slot, when Derived
	Type    TypeUse // the type, when not Derived
}

An RType is the runtime type descriptor a body needs at run time.

type RangeClause

type RangeClause struct {
	Pos Pos
	Lhs []Assignee
	X   Expr

	// MapRType is the descriptor of the map being ranged over, and is nil
	// when the operand is not a map.
	MapRType *RType

	// KeyConv and ValueConv convert the key and the value to the type of
	// their destination. Each is nil when the clause has no such
	// destination or when the destination is blank.
	KeyConv   *ConvRTTI
	ValueConv *ConvRTTI
}

A RangeClause is the range form of a for statement.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader reads the export data of the packages one compilation imports.

One Reader serves a whole compilation, because a package reached through two different archives must be the same types2.Package. gc writes the declarations an archive depends on into that archive, so reading "net/http" materialises "io" as a side effect. A second Reader would produce a second "io" and the checker would report the two io.Writer types as unrelated.

The same reasoning gives the Reader one types2.Context: it is what makes two instantiations of one generic type with the same arguments identical.

func NewReader

func NewReader() *Reader

NewReader returns a Reader with no package read yet.

func (*Reader) Imports

func (r *Reader) Imports() []Import

Imports returns what was read, in the order it was read.

A package is read once, so the order is the order the type checker first asked for each import, which is source order. The slice is what the object writer walks, and walking it rather than a map is what keeps the object's Autolib block identical between runs (specs/053-determinism.md).

func (*Reader) Read

func (r *Reader) Read(path, file string) (pkg *types2.Package, err error)

Read returns the package at the import path path, reading it from the archive file.

A package already read is returned only when it is complete. A package that another archive mentioned exists but holds nothing, because ReadPackage marks only the package the archive is for, so an incomplete entry is a package whose own archive has still to be read.

type RecvExpr

type RecvExpr struct {
	X         Expr
	Pos       Pos
	Implicits []int
	Deref     bool
	Addr      bool
	// contains filtered or unexported fields
}

A RecvExpr is the operand of a method selection, with the implicit field selections, dereference or address the selection applies.

func (*RecvExpr) ExprType

func (e *RecvExpr) ExprType() types2.Type

func (*RecvExpr) Reshape

func (e *RecvExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type ReturnStmt

type ReturnStmt struct {
	Pos     Pos
	Results MultiExpr
}

A ReturnStmt is a return.

type RuntimeBuiltinExpr

type RuntimeBuiltinExpr struct {
	Name string
	// contains filtered or unexported fields
}

A RuntimeBuiltinExpr is a reference to a runtime function that gc's own transformations introduced, such as panicrangeexit. It has no source spelling.

func (*RuntimeBuiltinExpr) ExprType

func (e *RuntimeBuiltinExpr) ExprType() types2.Type

func (*RuntimeBuiltinExpr) Reshape

func (e *RuntimeBuiltinExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type SelectStmt

type SelectStmt struct {
	Pos     Pos
	Clauses []CommClause
	Close   Pos
}

A SelectStmt is a select statement.

type Selector

type Selector struct {
	Pkg  *types2.Package
	Name string
}

A Selector names a field or a method.

type SendStmt

type SendStmt struct {
	Pos   Pos
	Chan  Expr
	Value Expr
}

A SendStmt is a channel send.

type SizeExpr

type SizeExpr struct {
	Kind ExprKind // ExprSizeof or ExprAlignof
	Pos  Pos
	Type TypeUse
	// contains filtered or unexported fields
}

A SizeExpr is unsafe.Sizeof or unsafe.Alignof.

func (*SizeExpr) ExprType

func (e *SizeExpr) ExprType() types2.Type

func (*SizeExpr) Reshape

func (e *SizeExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type SliceExpr

type SliceExpr struct {
	X     Expr
	Pos   Pos
	Index [3]Expr
	// contains filtered or unexported fields
}

A SliceExpr is x[a:b] or x[a:b:c]. An absent bound is nil.

func (*SliceExpr) ExprType

func (e *SliceExpr) ExprType() types2.Type

func (*SliceExpr) Reshape

func (e *SliceExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type Source

type Source struct {
	// Fset resolves the position of a declaration and of a position a body
	// carries. Without it every position the file holds is absent.
	Fset *syntax.FileSet

	// Funcs is one entry per declaration whose body reaches the file, in
	// the order the caller decided. The order the file holds them in is the
	// order of the elements they were written to, which is gc's order.
	Funcs []InlineFunc

	// File maps a position's file name to the name the export data records
	// for it. It is nil when the names are recorded as they were parsed.
	//
	// The driver owns the answer, because it is the same answer the object's
	// line table already holds: one compiler must not report two names for
	// one file. See [pkgWriter.posBaseIdx].
	File func(string) string
}

A Source is what a package's own source adds to what the checker recorded.

It is what the driver assembles: the FileSet that resolves a declaration's position, and the bodies BodySource built. The writer allocates the elements each body names and writes nothing it cannot allocate.

type Stmt

type Stmt interface {
	// contains filtered or unexported methods
}

A Stmt is one statement of a body.

type StmtKind

type StmtKind int

A StmtKind names one statement encoding.

const (
	StmtEnd StmtKind = iota
	StmtLabel
	StmtBlock
	StmtExpr
	StmtSend
	StmtAssign
	StmtAssignOp
	StmtIncDec
	StmtBranch
	StmtCall
	StmtReturn
	StmtIf
	StmtFor
	StmtSwitch
	StmtSelect
)

The statement encodings, in the format's order.

func (StmtKind) Marker

func (c StmtKind) Marker() pkgbits.SyncMarker

func (StmtKind) String

func (c StmtKind) String() string

func (StmtKind) Value

func (c StmtKind) Value() int

type SwitchStmt

type SwitchStmt struct {
	Open Pos
	Pos  Pos
	Init []Stmt

	// Guard is set for a type switch and Tag for an expression switch. Tag
	// is nil for a switch with no tag, which is a switch on true.
	Guard *TypeSwitchGuard
	Tag   Expr

	Clauses []CaseClause

	// ClausesClose is the closing brace as it ends the last clause's scope,
	// and Close is the same brace as it ends the switch's own scope. gc
	// writes it twice and the second is written even for a switch with no
	// clause.
	ClausesClose Pos
	Close        Pos
}

A SwitchStmt is an expression switch or a type switch.

type TypeSwitchGuard

type TypeSwitchGuard struct {
	Pos Pos

	// Named is true when the guard declares a variable, which each clause
	// then declares again with the clause's own type.
	Named   bool
	NamePos Pos
	Pkg     *types2.Package
	Name    string

	X Expr
}

A TypeSwitchGuard is the x := y.(type) of a type switch.

type TypeUse

type TypeUse struct {
	Derived bool
	Idx     pkgbits.Index
	Type    types2.Type
}

A TypeUse is a reference to a type from inside a body.

A derived type is one whose identity depends on the enclosing declaration's type parameters. Idx is then a slot in that declaration's dictionary rather than an index into SectionType.

type UnaryExpr

type UnaryExpr struct {
	Op  Op
	Pos Pos
	X   Expr
	// contains filtered or unexported fields
}

A UnaryExpr is a unary operation, an address, a dereference or a receive.

func (*UnaryExpr) ExprType

func (e *UnaryExpr) ExprType() types2.Type

func (*UnaryExpr) Reshape

func (e *UnaryExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

type UnsupportedError

type UnsupportedError struct {
	Package string // the package being written
	Name    string // the declaration, qualified by its own package
	Reason  string // what the writer cannot encode about it
}

UnsupportedError reports a declaration the writer cannot encode.

The declaration is named, because the package that holds it is what a user has to remove from the allowlist or work around.

func (*UnsupportedError) Error

func (e *UnsupportedError) Error() string

type ZeroExpr

type ZeroExpr struct {
	Pos  Pos
	Type TypeUse
	// contains filtered or unexported fields
}

A ZeroExpr is the predeclared nil, typed by its context.

func (*ZeroExpr) ExprType

func (e *ZeroExpr) ExprType() types2.Type

func (*ZeroExpr) Reshape

func (e *ZeroExpr) Reshape() *TypeUse

Reshape returns the type the reshape node in front of the expression named, and nil where the stream carried no such node.

Directories

Path Synopsis
Package pkgbits implements low-level coding abstractions for Unified IR's (UIR) binary export data format.
Package pkgbits implements low-level coding abstractions for Unified IR's (UIR) binary export data format.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL