739 lines
18 KiB
Go
739 lines
18 KiB
Go
// 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.
|
|
|
|
// Derived from go/internal/gcimporter/ureader.go
|
|
|
|
//go:build go1.18
|
|
// +build go1.18
|
|
|
|
package gcimporter
|
|
|
|
import (
|
|
"go/token"
|
|
"go/types"
|
|
"strings"
|
|
|
|
"golang.org/x/tools/internal/pkgbits"
|
|
)
|
|
|
|
// A pkgReader holds the shared state for reading a unified IR package
|
|
// description.
|
|
type pkgReader struct {
|
|
pkgbits.PkgDecoder
|
|
|
|
fake fakeFileSet
|
|
|
|
ctxt *types.Context
|
|
imports map[string]*types.Package // previously imported packages, indexed by path
|
|
|
|
// lazily initialized arrays corresponding to the unified IR
|
|
// PosBase, Pkg, and Type sections, respectively.
|
|
posBases []string // position bases (i.e., file names)
|
|
pkgs []*types.Package
|
|
typs []types.Type
|
|
|
|
// laterFns holds functions that need to be invoked at the end of
|
|
// import reading.
|
|
laterFns []func()
|
|
// laterFors is used in case of 'type A B' to ensure that B is processed before A.
|
|
laterFors map[types.Type]int
|
|
|
|
// ifaces holds a list of constructed Interfaces, which need to have
|
|
// Complete called after importing is done.
|
|
ifaces []*types.Interface
|
|
}
|
|
|
|
// later adds a function to be invoked at the end of import reading.
|
|
func (pr *pkgReader) later(fn func()) {
|
|
pr.laterFns = append(pr.laterFns, fn)
|
|
}
|
|
|
|
// See cmd/compile/internal/noder.derivedInfo.
|
|
type derivedInfo struct {
|
|
idx pkgbits.Index
|
|
needed bool
|
|
}
|
|
|
|
// See cmd/compile/internal/noder.typeInfo.
|
|
type typeInfo struct {
|
|
idx pkgbits.Index
|
|
derived bool
|
|
}
|
|
|
|
func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
|
|
s := string(data)
|
|
s = s[:strings.LastIndex(s, "\n$$\n")]
|
|
input := pkgbits.NewPkgDecoder(path, s)
|
|
pkg = readUnifiedPackage(fset, nil, imports, input)
|
|
return
|
|
}
|
|
|
|
// laterFor adds a function to be invoked at the end of import reading, and records the type that function is finishing.
|
|
func (pr *pkgReader) laterFor(t types.Type, fn func()) {
|
|
if pr.laterFors == nil {
|
|
pr.laterFors = make(map[types.Type]int)
|
|
}
|
|
pr.laterFors[t] = len(pr.laterFns)
|
|
pr.laterFns = append(pr.laterFns, fn)
|
|
}
|
|
|
|
// readUnifiedPackage reads a package description from the given
|
|
// unified IR export data decoder.
|
|
func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package {
|
|
pr := pkgReader{
|
|
PkgDecoder: input,
|
|
|
|
fake: fakeFileSet{
|
|
fset: fset,
|
|
files: make(map[string]*fileInfo),
|
|
},
|
|
|
|
ctxt: ctxt,
|
|
imports: imports,
|
|
|
|
posBases: make([]string, input.NumElems(pkgbits.RelocPosBase)),
|
|
pkgs: make([]*types.Package, input.NumElems(pkgbits.RelocPkg)),
|
|
typs: make([]types.Type, input.NumElems(pkgbits.RelocType)),
|
|
}
|
|
defer pr.fake.setLines()
|
|
|
|
r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
|
|
pkg := r.pkg()
|
|
r.Bool() // has init
|
|
|
|
for i, n := 0, r.Len(); i < n; i++ {
|
|
// As if r.obj(), but avoiding the Scope.Lookup call,
|
|
// to avoid eager loading of imports.
|
|
r.Sync(pkgbits.SyncObject)
|
|
assert(!r.Bool())
|
|
r.p.objIdx(r.Reloc(pkgbits.RelocObj))
|
|
assert(r.Len() == 0)
|
|
}
|
|
|
|
r.Sync(pkgbits.SyncEOF)
|
|
|
|
for _, fn := range pr.laterFns {
|
|
fn()
|
|
}
|
|
|
|
for _, iface := range pr.ifaces {
|
|
iface.Complete()
|
|
}
|
|
|
|
pkg.MarkComplete()
|
|
return pkg
|
|
}
|
|
|
|
// A reader holds the state for reading a single unified IR element
|
|
// within a package.
|
|
type reader struct {
|
|
pkgbits.Decoder
|
|
|
|
p *pkgReader
|
|
|
|
dict *readerDict
|
|
}
|
|
|
|
// A readerDict holds the state for type parameters that parameterize
|
|
// the current unified IR element.
|
|
type readerDict struct {
|
|
// bounds is a slice of typeInfos corresponding to the underlying
|
|
// bounds of the element's type parameters.
|
|
bounds []typeInfo
|
|
|
|
// tparams is a slice of the constructed TypeParams for the element.
|
|
tparams []*types.TypeParam
|
|
|
|
// devived is a slice of types derived from tparams, which may be
|
|
// instantiated while reading the current element.
|
|
derived []derivedInfo
|
|
derivedTypes []types.Type // lazily instantiated from derived
|
|
}
|
|
|
|
func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
|
|
return &reader{
|
|
Decoder: pr.NewDecoder(k, idx, marker),
|
|
p: pr,
|
|
}
|
|
}
|
|
|
|
func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
|
|
return &reader{
|
|
Decoder: pr.TempDecoder(k, idx, marker),
|
|
p: pr,
|
|
}
|
|
}
|
|
|
|
func (pr *pkgReader) retireReader(r *reader) {
|
|
pr.RetireDecoder(&r.Decoder)
|
|
}
|
|
|
|
// @@@ Positions
|
|
|
|
func (r *reader) pos() token.Pos {
|
|
r.Sync(pkgbits.SyncPos)
|
|
if !r.Bool() {
|
|
return token.NoPos
|
|
}
|
|
|
|
// TODO(mdempsky): Delta encoding.
|
|
posBase := r.posBase()
|
|
line := r.Uint()
|
|
col := r.Uint()
|
|
return r.p.fake.pos(posBase, int(line), int(col))
|
|
}
|
|
|
|
func (r *reader) posBase() string {
|
|
return r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase))
|
|
}
|
|
|
|
func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string {
|
|
if b := pr.posBases[idx]; b != "" {
|
|
return b
|
|
}
|
|
|
|
var filename string
|
|
{
|
|
r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
|
|
|
|
// Within types2, position bases have a lot more details (e.g.,
|
|
// keeping track of where //line directives appeared exactly).
|
|
//
|
|
// For go/types, we just track the file name.
|
|
|
|
filename = r.String()
|
|
|
|
if r.Bool() { // file base
|
|
// Was: "b = token.NewTrimmedFileBase(filename, true)"
|
|
} else { // line base
|
|
pos := r.pos()
|
|
line := r.Uint()
|
|
col := r.Uint()
|
|
|
|
// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
|
|
_, _, _ = pos, line, col
|
|
}
|
|
pr.retireReader(r)
|
|
}
|
|
b := filename
|
|
pr.posBases[idx] = b
|
|
return b
|
|
}
|
|
|
|
// @@@ Packages
|
|
|
|
func (r *reader) pkg() *types.Package {
|
|
r.Sync(pkgbits.SyncPkg)
|
|
return r.p.pkgIdx(r.Reloc(pkgbits.RelocPkg))
|
|
}
|
|
|
|
func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Package {
|
|
// TODO(mdempsky): Consider using some non-nil pointer to indicate
|
|
// the universe scope, so we don't need to keep re-reading it.
|
|
if pkg := pr.pkgs[idx]; pkg != nil {
|
|
return pkg
|
|
}
|
|
|
|
pkg := pr.newReader(pkgbits.RelocPkg, idx, pkgbits.SyncPkgDef).doPkg()
|
|
pr.pkgs[idx] = pkg
|
|
return pkg
|
|
}
|
|
|
|
func (r *reader) doPkg() *types.Package {
|
|
path := r.String()
|
|
switch path {
|
|
case "":
|
|
path = r.p.PkgPath()
|
|
case "builtin":
|
|
return nil // universe
|
|
case "unsafe":
|
|
return types.Unsafe
|
|
}
|
|
|
|
if pkg := r.p.imports[path]; pkg != nil {
|
|
return pkg
|
|
}
|
|
|
|
name := r.String()
|
|
|
|
pkg := types.NewPackage(path, name)
|
|
r.p.imports[path] = pkg
|
|
|
|
imports := make([]*types.Package, r.Len())
|
|
for i := range imports {
|
|
imports[i] = r.pkg()
|
|
}
|
|
pkg.SetImports(flattenImports(imports))
|
|
|
|
return pkg
|
|
}
|
|
|
|
// flattenImports returns the transitive closure of all imported
|
|
// packages rooted from pkgs.
|
|
func flattenImports(pkgs []*types.Package) []*types.Package {
|
|
var res []*types.Package
|
|
seen := make(map[*types.Package]struct{})
|
|
for _, pkg := range pkgs {
|
|
if _, ok := seen[pkg]; ok {
|
|
continue
|
|
}
|
|
seen[pkg] = struct{}{}
|
|
res = append(res, pkg)
|
|
|
|
// pkg.Imports() is already flattened.
|
|
for _, pkg := range pkg.Imports() {
|
|
if _, ok := seen[pkg]; ok {
|
|
continue
|
|
}
|
|
seen[pkg] = struct{}{}
|
|
res = append(res, pkg)
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// @@@ Types
|
|
|
|
func (r *reader) typ() types.Type {
|
|
return r.p.typIdx(r.typInfo(), r.dict)
|
|
}
|
|
|
|
func (r *reader) typInfo() typeInfo {
|
|
r.Sync(pkgbits.SyncType)
|
|
if r.Bool() {
|
|
return typeInfo{idx: pkgbits.Index(r.Len()), derived: true}
|
|
}
|
|
return typeInfo{idx: r.Reloc(pkgbits.RelocType), derived: false}
|
|
}
|
|
|
|
func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type {
|
|
idx := info.idx
|
|
var where *types.Type
|
|
if info.derived {
|
|
where = &dict.derivedTypes[idx]
|
|
idx = dict.derived[idx].idx
|
|
} else {
|
|
where = &pr.typs[idx]
|
|
}
|
|
|
|
if typ := *where; typ != nil {
|
|
return typ
|
|
}
|
|
|
|
var typ types.Type
|
|
{
|
|
r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
|
|
r.dict = dict
|
|
|
|
typ = r.doTyp()
|
|
assert(typ != nil)
|
|
pr.retireReader(r)
|
|
}
|
|
// See comment in pkgReader.typIdx explaining how this happens.
|
|
if prev := *where; prev != nil {
|
|
return prev
|
|
}
|
|
|
|
*where = typ
|
|
return typ
|
|
}
|
|
|
|
func (r *reader) doTyp() (res types.Type) {
|
|
switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag {
|
|
default:
|
|
errorf("unhandled type tag: %v", tag)
|
|
panic("unreachable")
|
|
|
|
case pkgbits.TypeBasic:
|
|
return types.Typ[r.Len()]
|
|
|
|
case pkgbits.TypeNamed:
|
|
obj, targs := r.obj()
|
|
name := obj.(*types.TypeName)
|
|
if len(targs) != 0 {
|
|
t, _ := types.Instantiate(r.p.ctxt, name.Type(), targs, false)
|
|
return t
|
|
}
|
|
return name.Type()
|
|
|
|
case pkgbits.TypeTypeParam:
|
|
return r.dict.tparams[r.Len()]
|
|
|
|
case pkgbits.TypeArray:
|
|
len := int64(r.Uint64())
|
|
return types.NewArray(r.typ(), len)
|
|
case pkgbits.TypeChan:
|
|
dir := types.ChanDir(r.Len())
|
|
return types.NewChan(dir, r.typ())
|
|
case pkgbits.TypeMap:
|
|
return types.NewMap(r.typ(), r.typ())
|
|
case pkgbits.TypePointer:
|
|
return types.NewPointer(r.typ())
|
|
case pkgbits.TypeSignature:
|
|
return r.signature(nil, nil, nil)
|
|
case pkgbits.TypeSlice:
|
|
return types.NewSlice(r.typ())
|
|
case pkgbits.TypeStruct:
|
|
return r.structType()
|
|
case pkgbits.TypeInterface:
|
|
return r.interfaceType()
|
|
case pkgbits.TypeUnion:
|
|
return r.unionType()
|
|
}
|
|
}
|
|
|
|
func (r *reader) structType() *types.Struct {
|
|
fields := make([]*types.Var, r.Len())
|
|
var tags []string
|
|
for i := range fields {
|
|
pos := r.pos()
|
|
pkg, name := r.selector()
|
|
ftyp := r.typ()
|
|
tag := r.String()
|
|
embedded := r.Bool()
|
|
|
|
fields[i] = types.NewField(pos, pkg, name, ftyp, embedded)
|
|
if tag != "" {
|
|
for len(tags) < i {
|
|
tags = append(tags, "")
|
|
}
|
|
tags = append(tags, tag)
|
|
}
|
|
}
|
|
return types.NewStruct(fields, tags)
|
|
}
|
|
|
|
func (r *reader) unionType() *types.Union {
|
|
terms := make([]*types.Term, r.Len())
|
|
for i := range terms {
|
|
terms[i] = types.NewTerm(r.Bool(), r.typ())
|
|
}
|
|
return types.NewUnion(terms)
|
|
}
|
|
|
|
func (r *reader) interfaceType() *types.Interface {
|
|
methods := make([]*types.Func, r.Len())
|
|
embeddeds := make([]types.Type, r.Len())
|
|
implicit := len(methods) == 0 && len(embeddeds) == 1 && r.Bool()
|
|
|
|
for i := range methods {
|
|
pos := r.pos()
|
|
pkg, name := r.selector()
|
|
mtyp := r.signature(nil, nil, nil)
|
|
methods[i] = types.NewFunc(pos, pkg, name, mtyp)
|
|
}
|
|
|
|
for i := range embeddeds {
|
|
embeddeds[i] = r.typ()
|
|
}
|
|
|
|
iface := types.NewInterfaceType(methods, embeddeds)
|
|
if implicit {
|
|
iface.MarkImplicit()
|
|
}
|
|
|
|
// We need to call iface.Complete(), but if there are any embedded
|
|
// defined types, then we may not have set their underlying
|
|
// interface type yet. So we need to defer calling Complete until
|
|
// after we've called SetUnderlying everywhere.
|
|
//
|
|
// TODO(mdempsky): After CL 424876 lands, it should be safe to call
|
|
// iface.Complete() immediately.
|
|
r.p.ifaces = append(r.p.ifaces, iface)
|
|
|
|
return iface
|
|
}
|
|
|
|
func (r *reader) signature(recv *types.Var, rtparams, tparams []*types.TypeParam) *types.Signature {
|
|
r.Sync(pkgbits.SyncSignature)
|
|
|
|
params := r.params()
|
|
results := r.params()
|
|
variadic := r.Bool()
|
|
|
|
return types.NewSignatureType(recv, rtparams, tparams, params, results, variadic)
|
|
}
|
|
|
|
func (r *reader) params() *types.Tuple {
|
|
r.Sync(pkgbits.SyncParams)
|
|
|
|
params := make([]*types.Var, r.Len())
|
|
for i := range params {
|
|
params[i] = r.param()
|
|
}
|
|
|
|
return types.NewTuple(params...)
|
|
}
|
|
|
|
func (r *reader) param() *types.Var {
|
|
r.Sync(pkgbits.SyncParam)
|
|
|
|
pos := r.pos()
|
|
pkg, name := r.localIdent()
|
|
typ := r.typ()
|
|
|
|
return types.NewParam(pos, pkg, name, typ)
|
|
}
|
|
|
|
// @@@ Objects
|
|
|
|
func (r *reader) obj() (types.Object, []types.Type) {
|
|
r.Sync(pkgbits.SyncObject)
|
|
|
|
assert(!r.Bool())
|
|
|
|
pkg, name := r.p.objIdx(r.Reloc(pkgbits.RelocObj))
|
|
obj := pkgScope(pkg).Lookup(name)
|
|
|
|
targs := make([]types.Type, r.Len())
|
|
for i := range targs {
|
|
targs[i] = r.typ()
|
|
}
|
|
|
|
return obj, targs
|
|
}
|
|
|
|
func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|
|
|
var objPkg *types.Package
|
|
var objName string
|
|
var tag pkgbits.CodeObj
|
|
{
|
|
rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
|
|
|
|
objPkg, objName = rname.qualifiedIdent()
|
|
assert(objName != "")
|
|
|
|
tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
|
|
pr.retireReader(rname)
|
|
}
|
|
|
|
if tag == pkgbits.ObjStub {
|
|
assert(objPkg == nil || objPkg == types.Unsafe)
|
|
return objPkg, objName
|
|
}
|
|
|
|
// Ignore local types promoted to global scope (#55110).
|
|
if _, suffix := splitVargenSuffix(objName); suffix != "" {
|
|
return objPkg, objName
|
|
}
|
|
|
|
if objPkg.Scope().Lookup(objName) == nil {
|
|
dict := pr.objDictIdx(idx)
|
|
|
|
r := pr.newReader(pkgbits.RelocObj, idx, pkgbits.SyncObject1)
|
|
r.dict = dict
|
|
|
|
declare := func(obj types.Object) {
|
|
objPkg.Scope().Insert(obj)
|
|
}
|
|
|
|
switch tag {
|
|
default:
|
|
panic("weird")
|
|
|
|
case pkgbits.ObjAlias:
|
|
pos := r.pos()
|
|
typ := r.typ()
|
|
declare(types.NewTypeName(pos, objPkg, objName, typ))
|
|
|
|
case pkgbits.ObjConst:
|
|
pos := r.pos()
|
|
typ := r.typ()
|
|
val := r.Value()
|
|
declare(types.NewConst(pos, objPkg, objName, typ, val))
|
|
|
|
case pkgbits.ObjFunc:
|
|
pos := r.pos()
|
|
tparams := r.typeParamNames()
|
|
sig := r.signature(nil, nil, tparams)
|
|
declare(types.NewFunc(pos, objPkg, objName, sig))
|
|
|
|
case pkgbits.ObjType:
|
|
pos := r.pos()
|
|
|
|
obj := types.NewTypeName(pos, objPkg, objName, nil)
|
|
named := types.NewNamed(obj, nil, nil)
|
|
declare(obj)
|
|
|
|
named.SetTypeParams(r.typeParamNames())
|
|
|
|
setUnderlying := func(underlying types.Type) {
|
|
// If the underlying type is an interface, we need to
|
|
// duplicate its methods so we can replace the receiver
|
|
// parameter's type (#49906).
|
|
if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
|
|
methods := make([]*types.Func, iface.NumExplicitMethods())
|
|
for i := range methods {
|
|
fn := iface.ExplicitMethod(i)
|
|
sig := fn.Type().(*types.Signature)
|
|
|
|
recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named)
|
|
methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic()))
|
|
}
|
|
|
|
embeds := make([]types.Type, iface.NumEmbeddeds())
|
|
for i := range embeds {
|
|
embeds[i] = iface.EmbeddedType(i)
|
|
}
|
|
|
|
newIface := types.NewInterfaceType(methods, embeds)
|
|
r.p.ifaces = append(r.p.ifaces, newIface)
|
|
underlying = newIface
|
|
}
|
|
|
|
named.SetUnderlying(underlying)
|
|
}
|
|
|
|
// Since go.dev/cl/455279, we can assume rhs.Underlying() will
|
|
// always be non-nil. However, to temporarily support users of
|
|
// older snapshot releases, we continue to fallback to the old
|
|
// behavior for now.
|
|
//
|
|
// TODO(mdempsky): Remove fallback code and simplify after
|
|
// allowing time for snapshot users to upgrade.
|
|
rhs := r.typ()
|
|
if underlying := rhs.Underlying(); underlying != nil {
|
|
setUnderlying(underlying)
|
|
} else {
|
|
pk := r.p
|
|
pk.laterFor(named, func() {
|
|
// First be sure that the rhs is initialized, if it needs to be initialized.
|
|
delete(pk.laterFors, named) // prevent cycles
|
|
if i, ok := pk.laterFors[rhs]; ok {
|
|
f := pk.laterFns[i]
|
|
pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
|
|
f() // initialize RHS
|
|
}
|
|
setUnderlying(rhs.Underlying())
|
|
})
|
|
}
|
|
|
|
for i, n := 0, r.Len(); i < n; i++ {
|
|
named.AddMethod(r.method())
|
|
}
|
|
|
|
case pkgbits.ObjVar:
|
|
pos := r.pos()
|
|
typ := r.typ()
|
|
declare(types.NewVar(pos, objPkg, objName, typ))
|
|
}
|
|
}
|
|
|
|
return objPkg, objName
|
|
}
|
|
|
|
func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
|
|
|
|
var dict readerDict
|
|
|
|
{
|
|
r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
|
|
if implicits := r.Len(); implicits != 0 {
|
|
errorf("unexpected object with %v implicit type parameter(s)", implicits)
|
|
}
|
|
|
|
dict.bounds = make([]typeInfo, r.Len())
|
|
for i := range dict.bounds {
|
|
dict.bounds[i] = r.typInfo()
|
|
}
|
|
|
|
dict.derived = make([]derivedInfo, r.Len())
|
|
dict.derivedTypes = make([]types.Type, len(dict.derived))
|
|
for i := range dict.derived {
|
|
dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()}
|
|
}
|
|
|
|
pr.retireReader(r)
|
|
}
|
|
// function references follow, but reader doesn't need those
|
|
|
|
return &dict
|
|
}
|
|
|
|
func (r *reader) typeParamNames() []*types.TypeParam {
|
|
r.Sync(pkgbits.SyncTypeParamNames)
|
|
|
|
// Note: This code assumes it only processes objects without
|
|
// implement type parameters. This is currently fine, because
|
|
// reader is only used to read in exported declarations, which are
|
|
// always package scoped.
|
|
|
|
if len(r.dict.bounds) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Careful: Type parameter lists may have cycles. To allow for this,
|
|
// we construct the type parameter list in two passes: first we
|
|
// create all the TypeNames and TypeParams, then we construct and
|
|
// set the bound type.
|
|
|
|
r.dict.tparams = make([]*types.TypeParam, len(r.dict.bounds))
|
|
for i := range r.dict.bounds {
|
|
pos := r.pos()
|
|
pkg, name := r.localIdent()
|
|
|
|
tname := types.NewTypeName(pos, pkg, name, nil)
|
|
r.dict.tparams[i] = types.NewTypeParam(tname, nil)
|
|
}
|
|
|
|
typs := make([]types.Type, len(r.dict.bounds))
|
|
for i, bound := range r.dict.bounds {
|
|
typs[i] = r.p.typIdx(bound, r.dict)
|
|
}
|
|
|
|
// TODO(mdempsky): This is subtle, elaborate further.
|
|
//
|
|
// We have to save tparams outside of the closure, because
|
|
// typeParamNames() can be called multiple times with the same
|
|
// dictionary instance.
|
|
//
|
|
// Also, this needs to happen later to make sure SetUnderlying has
|
|
// been called.
|
|
//
|
|
// TODO(mdempsky): Is it safe to have a single "later" slice or do
|
|
// we need to have multiple passes? See comments on CL 386002 and
|
|
// go.dev/issue/52104.
|
|
tparams := r.dict.tparams
|
|
r.p.later(func() {
|
|
for i, typ := range typs {
|
|
tparams[i].SetConstraint(typ)
|
|
}
|
|
})
|
|
|
|
return r.dict.tparams
|
|
}
|
|
|
|
func (r *reader) method() *types.Func {
|
|
r.Sync(pkgbits.SyncMethod)
|
|
pos := r.pos()
|
|
pkg, name := r.selector()
|
|
|
|
rparams := r.typeParamNames()
|
|
sig := r.signature(r.param(), rparams, nil)
|
|
|
|
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
|
|
return types.NewFunc(pos, pkg, name, sig)
|
|
}
|
|
|
|
func (r *reader) qualifiedIdent() (*types.Package, string) { return r.ident(pkgbits.SyncSym) }
|
|
func (r *reader) localIdent() (*types.Package, string) { return r.ident(pkgbits.SyncLocalIdent) }
|
|
func (r *reader) selector() (*types.Package, string) { return r.ident(pkgbits.SyncSelector) }
|
|
|
|
func (r *reader) ident(marker pkgbits.SyncMarker) (*types.Package, string) {
|
|
r.Sync(marker)
|
|
return r.pkg(), r.String()
|
|
}
|
|
|
|
// pkgScope returns pkg.Scope().
|
|
// If pkg is nil, it returns types.Universe instead.
|
|
//
|
|
// TODO(mdempsky): Remove after x/tools can depend on Go 1.19.
|
|
func pkgScope(pkg *types.Package) *types.Scope {
|
|
if pkg != nil {
|
|
return pkg.Scope()
|
|
}
|
|
return types.Universe
|
|
}
|