Newer
Older
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package noder
import (
"fmt"
"go/constant"
"go/token"
"internal/pkgbits"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types"
"cmd/compile/internal/types2"
)
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// This file implements the Unified IR package writer and defines the
// Unified IR export data format.
//
// Low-level coding details (e.g., byte-encoding of individual
// primitive values, or handling element bitstreams and
// cross-references) are handled by internal/pkgbits, so here we only
// concern ourselves with higher-level worries like mapping Go
// language constructs into elements.
// There are two central types in the writing process: the "writer"
// type handles writing out individual elements, while the "pkgWriter"
// type keeps track of which elements have already been created.
//
// For each sort of "thing" (e.g., position, package, object, type)
// that can be written into the export data, there are generally
// several methods that work together:
//
// - writer.thing handles writing out a *use* of a thing, which often
// means writing a relocation to that thing's encoded index.
//
// - pkgWriter.thingIdx handles reserving an index for a thing, and
// writing out any elements needed for the thing.
//
// - writer.doThing handles writing out the *definition* of a thing,
// which in general is a mix of low-level coding primitives (e.g.,
// ints and strings) or uses of other things.
//
// A design goal of Unified IR is to have a single, canonical writer
// implementation, but multiple reader implementations each tailored
// to their respective needs. For example, within cmd/compile's own
// backend, inlining is implemented largely by just re-running the
// function body reading code.
// TODO(mdempsky): Add an importer for Unified IR to the x/tools repo,
// and better document the file format boundary between public and
// private data.
// A pkgWriter constructs Unified IR export data from the results of
// running the types2 type checker on a Go compilation unit.
type pkgWriter struct {
pkgbits.PkgEncoder
m posMap
curpkg *types2.Package
info *types2.Info
// Indices for previously written syntax and types2 things.
posBasesIdx map[*syntax.PosBase]pkgbits.Index
pkgsIdx map[*types2.Package]pkgbits.Index
typsIdx map[types2.Type]pkgbits.Index
objsIdx map[types2.Object]pkgbits.Index
// Maps from types2.Objects back to their syntax.Decl.
funDecls map[*types2.Func]*syntax.FuncDecl
typDecls map[*types2.TypeName]typeDeclGen
// linknames maps package-scope objects to their linker symbol name,
// if specified by a //go:linkname directive.
linknames map[types2.Object]string
// cgoPragmas accumulates any //go:cgo_* pragmas that need to be
// passed through to cmd/link.
cgoPragmas [][]string
}
// newPkgWriter returns an initialized pkgWriter for the specified
// package.
func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info) *pkgWriter {
return &pkgWriter{
PkgEncoder: pkgbits.NewPkgEncoder(base.Debug.SyncFrames),
m: m,
curpkg: pkg,
info: info,
pkgsIdx: make(map[*types2.Package]pkgbits.Index),
objsIdx: make(map[types2.Object]pkgbits.Index),
typsIdx: make(map[types2.Type]pkgbits.Index),
posBasesIdx: make(map[*syntax.PosBase]pkgbits.Index),
funDecls: make(map[*types2.Func]*syntax.FuncDecl),
typDecls: make(map[*types2.TypeName]typeDeclGen),
linknames: make(map[types2.Object]string),
}
}
// errorf reports a user error about thing p.
func (pw *pkgWriter) errorf(p poser, msg string, args ...interface{}) {
base.ErrorfAt(pw.m.pos(p), 0, msg, args...)
// fatalf reports an internal compiler error about thing p.
func (pw *pkgWriter) fatalf(p poser, msg string, args ...interface{}) {
base.FatalfAt(pw.m.pos(p), msg, args...)
}
// unexpected reports a fatal error about a thing of unexpected
// dynamic type.
func (pw *pkgWriter) unexpected(what string, p poser) {
pw.fatalf(p, "unexpected %s: %v (%T)", what, p, p)
}
func (pw *pkgWriter) typeAndValue(x syntax.Expr) syntax.TypeAndValue {
tv, ok := pw.maybeTypeAndValue(x)
if !ok {
pw.fatalf(x, "missing Types entry: %v", syntax.String(x))
}
return tv
}
func (pw *pkgWriter) maybeTypeAndValue(x syntax.Expr) (syntax.TypeAndValue, bool) {
tv := x.GetTypeInfo()
// If x is a generic function whose type arguments are inferred
// from assignment context, then we need to find its inferred type
// in Info.Instances instead.
if name, ok := x.(*syntax.Name); ok {
if inst, ok := pw.info.Instances[name]; ok {
tv.Type = inst.Type
}
}
return tv, tv.Type != nil
}
// typeOf returns the Type of the given value expression.
func (pw *pkgWriter) typeOf(expr syntax.Expr) types2.Type {
tv := pw.typeAndValue(expr)
if !tv.IsValue() {
pw.fatalf(expr, "expected value: %v", syntax.String(expr))
}
return tv.Type
}
// A writer provides APIs for writing out an individual element.
type writer struct {
p *pkgWriter
pkgbits.Encoder
// sig holds the signature for the current function body, if any.
sig *types2.Signature
// TODO(mdempsky): We should be able to prune localsIdx whenever a
// scope closes, and then maybe we can just use the same map for
// storing the TypeParams too (as their TypeName instead).
// localsIdx tracks any local variables declared within this
// function body. It's unused for writing out non-body things.
localsIdx map[*types2.Var]int
// closureVars tracks any free variables that are referenced by this
// function body. It's unused for writing out non-body things.
closureVars []posVar
closureVarsIdx map[*types2.Var]int // index of previously seen free variables
dict *writerDict
// derived tracks whether the type being written out references any
// type parameters. It's unused for writing non-type things.
derived bool
}
// A writerDict tracks types and objects that are used by a declaration.
type writerDict struct {
implicits []*types2.TypeName
// derived is a slice of type indices for computing derived types
// (i.e., types that depend on the declaration's type parameters).
Matthew Dempsky
committed
derived []derivedInfo
// derivedIdx maps a Type to its corresponding index within the
// derived slice, if present.
derivedIdx map[types2.Type]pkgbits.Index
Loading
Loading full blame...