mirror of https://github.com/golang/go.git
go/internal/gcimporter: add support for importing parameterized types
Port the necessary logic to go/internal/gcimporter from cmd/compile/internal/importer/iimport.go to support type parameters. This is a partial port of several compiler CLs: at least CL 319930, CL 322609, CL 323029, CL 338192, CL 340251, and CL 340989. Because these ports were not interleaved with the corresponding go/types API changes, it is easier to just take the latest importer logic. Notably, the equivalent of types2.AsTypeParam is not used. It should be unnecessary. Updates #48101 Change-Id: I938bd8debc3f6a68a3ad8d44c61ef9c5038be7e5 Reviewed-on: https://go-review.googlesource.com/c/go/+/347069 Trust: Robert Findley <rfindley@google.com> Trust: Dan Scales <danscales@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dan Scales <danscales@google.com> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
4591f49938
commit
b8420baf46
|
|
@ -138,7 +138,6 @@ func TestVersionHandling(t *testing.T) {
|
||||||
skipSpecialPlatforms(t)
|
skipSpecialPlatforms(t)
|
||||||
|
|
||||||
// This package only handles gc export data.
|
// This package only handles gc export data.
|
||||||
// Disable test until we put in the new export version.
|
|
||||||
if runtime.Compiler != "gc" {
|
if runtime.Compiler != "gc" {
|
||||||
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,11 @@ const (
|
||||||
iexportVersionCurrent = iexportVersionGenerics
|
iexportVersionCurrent = iexportVersionGenerics
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ident struct {
|
||||||
|
pkg string
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
const predeclReserved = 32
|
const predeclReserved = 32
|
||||||
|
|
||||||
type itag uint64
|
type itag uint64
|
||||||
|
|
@ -68,6 +73,7 @@ const (
|
||||||
interfaceType
|
interfaceType
|
||||||
typeParamType
|
typeParamType
|
||||||
instType
|
instType
|
||||||
|
unionType
|
||||||
)
|
)
|
||||||
|
|
||||||
// iImportData imports a package from the serialized package data
|
// iImportData imports a package from the serialized package data
|
||||||
|
|
@ -122,6 +128,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, dataRea
|
||||||
declData: declData,
|
declData: declData,
|
||||||
pkgIndex: make(map[*types.Package]map[string]uint64),
|
pkgIndex: make(map[*types.Package]map[string]uint64),
|
||||||
typCache: make(map[uint64]types.Type),
|
typCache: make(map[uint64]types.Type),
|
||||||
|
// Separate map for typeparams, keyed by their package and unique
|
||||||
|
// name (name with subscript).
|
||||||
|
tparamIndex: make(map[ident]types.Type),
|
||||||
|
|
||||||
fake: fakeFileSet{
|
fake: fakeFileSet{
|
||||||
fset: fset,
|
fset: fset,
|
||||||
|
|
@ -200,6 +209,7 @@ type iimporter struct {
|
||||||
declData []byte
|
declData []byte
|
||||||
pkgIndex map[*types.Package]map[string]uint64
|
pkgIndex map[*types.Package]map[string]uint64
|
||||||
typCache map[uint64]types.Type
|
typCache map[uint64]types.Type
|
||||||
|
tparamIndex map[ident]types.Type
|
||||||
|
|
||||||
fake fakeFileSet
|
fake fakeFileSet
|
||||||
interfaceList []*types.Interface
|
interfaceList []*types.Interface
|
||||||
|
|
@ -289,19 +299,28 @@ func (r *importReader) obj(name string) {
|
||||||
|
|
||||||
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
|
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
|
||||||
|
|
||||||
case 'F':
|
case 'F', 'G':
|
||||||
|
var tparams []*types.TypeParam
|
||||||
|
if tag == 'G' {
|
||||||
|
tparams = r.tparamList()
|
||||||
|
}
|
||||||
sig := r.signature(nil)
|
sig := r.signature(nil)
|
||||||
|
sig.SetTParams(tparams)
|
||||||
r.declare(types.NewFunc(pos, r.currPkg, name, sig))
|
r.declare(types.NewFunc(pos, r.currPkg, name, sig))
|
||||||
|
|
||||||
case 'G':
|
case 'T', 'U':
|
||||||
errorf("unexpected parameterized function/method")
|
var tparams []*types.TypeParam
|
||||||
|
if tag == 'U' {
|
||||||
case 'T':
|
tparams = r.tparamList()
|
||||||
|
}
|
||||||
// Types can be recursive. We need to setup a stub
|
// Types can be recursive. We need to setup a stub
|
||||||
// declaration before recursing.
|
// declaration before recursing.
|
||||||
obj := types.NewTypeName(pos, r.currPkg, name, nil)
|
obj := types.NewTypeName(pos, r.currPkg, name, nil)
|
||||||
named := types.NewNamed(obj, nil, nil)
|
named := types.NewNamed(obj, nil, nil)
|
||||||
|
// TODO(rfindley): guarding on tag == 'U' should not be necessary here.
|
||||||
|
if tag == 'U' {
|
||||||
|
named.SetTParams(tparams)
|
||||||
|
}
|
||||||
r.declare(obj)
|
r.declare(obj)
|
||||||
|
|
||||||
underlying := r.p.typAt(r.uint64(), named).Underlying()
|
underlying := r.p.typAt(r.uint64(), named).Underlying()
|
||||||
|
|
@ -314,12 +333,45 @@ func (r *importReader) obj(name string) {
|
||||||
recv := r.param()
|
recv := r.param()
|
||||||
msig := r.signature(recv)
|
msig := r.signature(recv)
|
||||||
|
|
||||||
|
// If the receiver has any targs, set those as the
|
||||||
|
// rparams of the method (since those are the
|
||||||
|
// typeparams being used in the method sig/body).
|
||||||
|
targs := baseType(msig.Recv().Type()).TArgs()
|
||||||
|
if targs.Len() > 0 {
|
||||||
|
rparams := make([]*types.TypeParam, targs.Len())
|
||||||
|
for i := range rparams {
|
||||||
|
rparams[i], _ = targs.At(i).(*types.TypeParam)
|
||||||
|
}
|
||||||
|
msig.SetRParams(rparams)
|
||||||
|
}
|
||||||
|
|
||||||
named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
|
named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'U':
|
case 'P':
|
||||||
errorf("unexpected parameterized type")
|
// We need to "declare" a typeparam in order to have a name that
|
||||||
|
// can be referenced recursively (if needed) in the type param's
|
||||||
|
// bound.
|
||||||
|
if r.p.exportVersion < iexportVersionGenerics {
|
||||||
|
errorf("unexpected type param type")
|
||||||
|
}
|
||||||
|
name0, sub := parseSubscript(name)
|
||||||
|
tn := types.NewTypeName(pos, r.currPkg, name0, nil)
|
||||||
|
t := (*types.Checker)(nil).NewTypeParam(tn, nil)
|
||||||
|
if sub == 0 {
|
||||||
|
errorf("missing subscript")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(rfindley): can we use a different, stable ID?
|
||||||
|
// t.SetId(sub)
|
||||||
|
|
||||||
|
// To handle recursive references to the typeparam within its
|
||||||
|
// bound, save the partial type in tparamIndex before reading the bounds.
|
||||||
|
id := ident{r.currPkg.Name(), name}
|
||||||
|
r.p.tparamIndex[id] = t
|
||||||
|
|
||||||
|
t.SetConstraint(r.typ())
|
||||||
|
|
||||||
case 'V':
|
case 'V':
|
||||||
typ := r.typ()
|
typ := r.typ()
|
||||||
|
|
@ -575,12 +627,47 @@ func (r *importReader) doType(base *types.Named) types.Type {
|
||||||
return typ
|
return typ
|
||||||
|
|
||||||
case typeParamType:
|
case typeParamType:
|
||||||
errorf("do not handle type param types yet")
|
if r.p.exportVersion < iexportVersionGenerics {
|
||||||
return nil
|
errorf("unexpected type param type")
|
||||||
|
}
|
||||||
|
pkg, name := r.qualifiedIdent()
|
||||||
|
id := ident{pkg.Name(), name}
|
||||||
|
if t, ok := r.p.tparamIndex[id]; ok {
|
||||||
|
// We're already in the process of importing this typeparam.
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
// Otherwise, import the definition of the typeparam now.
|
||||||
|
r.p.doDecl(pkg, name)
|
||||||
|
return r.p.tparamIndex[id]
|
||||||
|
|
||||||
case instType:
|
case instType:
|
||||||
errorf("do not handle instantiated types yet")
|
if r.p.exportVersion < iexportVersionGenerics {
|
||||||
return nil
|
errorf("unexpected instantiation type")
|
||||||
|
}
|
||||||
|
// pos does not matter for instances: they are positioned on the original
|
||||||
|
// type.
|
||||||
|
_ = r.pos()
|
||||||
|
len := r.uint64()
|
||||||
|
targs := make([]types.Type, len)
|
||||||
|
for i := range targs {
|
||||||
|
targs[i] = r.typ()
|
||||||
|
}
|
||||||
|
baseType := r.typ()
|
||||||
|
// The imported instantiated type doesn't include any methods, so
|
||||||
|
// we must always use the methods of the base (orig) type.
|
||||||
|
// TODO provide a non-nil *Checker
|
||||||
|
t, _ := types.Instantiate(nil, baseType, targs, false)
|
||||||
|
return t
|
||||||
|
|
||||||
|
case unionType:
|
||||||
|
if r.p.exportVersion < iexportVersionGenerics {
|
||||||
|
errorf("unexpected instantiation type")
|
||||||
|
}
|
||||||
|
terms := make([]*types.Term, r.uint64())
|
||||||
|
for i := range terms {
|
||||||
|
terms[i] = types.NewTerm(r.bool(), r.typ())
|
||||||
|
}
|
||||||
|
return types.NewUnion(terms)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -595,6 +682,18 @@ func (r *importReader) signature(recv *types.Var) *types.Signature {
|
||||||
return types.NewSignature(recv, params, results, variadic)
|
return types.NewSignature(recv, params, results, variadic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *importReader) tparamList() []*types.TypeParam {
|
||||||
|
n := r.uint64()
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
xs := make([]*types.TypeParam, n)
|
||||||
|
for i := range xs {
|
||||||
|
xs[i], _ = r.typ().(*types.TypeParam)
|
||||||
|
}
|
||||||
|
return xs
|
||||||
|
}
|
||||||
|
|
||||||
func (r *importReader) paramList() *types.Tuple {
|
func (r *importReader) paramList() *types.Tuple {
|
||||||
xs := make([]*types.Var, r.uint64())
|
xs := make([]*types.Var, r.uint64())
|
||||||
for i := range xs {
|
for i := range xs {
|
||||||
|
|
@ -637,3 +736,33 @@ func (r *importReader) byte() byte {
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func baseType(typ types.Type) *types.Named {
|
||||||
|
// pointer receivers are never types.Named types
|
||||||
|
if p, _ := typ.(*types.Pointer); p != nil {
|
||||||
|
typ = p.Elem()
|
||||||
|
}
|
||||||
|
// receiver base types are always (possibly generic) types.Named types
|
||||||
|
n, _ := typ.(*types.Named)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSubscript(name string) (string, uint64) {
|
||||||
|
// Extract the subscript value from the type param name. We export
|
||||||
|
// and import the subscript value, so that all type params have
|
||||||
|
// unique names.
|
||||||
|
sub := uint64(0)
|
||||||
|
startsub := -1
|
||||||
|
for i, r := range name {
|
||||||
|
if '₀' <= r && r < '₀'+10 {
|
||||||
|
if startsub == -1 {
|
||||||
|
startsub = i
|
||||||
|
}
|
||||||
|
sub = sub*10 + uint64(r-'₀')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if startsub >= 0 {
|
||||||
|
name = name[:startsub]
|
||||||
|
}
|
||||||
|
return name, sub
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue