mirror of
https://github.com/golang/go
synced 2024-11-26 17:07:09 -07:00
cmd/compile/internal/types2: implement types2.Instantiate
Instantiation support for imports. This is experimental but it also doesn't affect Go 1.17 as this code is not executed unless we enable generics (in the parser). Change-Id: If2da09ac3a557ec6a180707a53f75f3ce354f3e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/314773 Trust: Robert Griesemer <gri@golang.org> Trust: Dan Scales <danscales@google.com> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dan Scales <danscales@google.com>
This commit is contained in:
parent
caf4c9434b
commit
9e0facd26e
63
src/cmd/compile/internal/types2/instantiate.go
Normal file
63
src/cmd/compile/internal/types2/instantiate.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// 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 types2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/compile/internal/syntax"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Instantiate instantiates the type typ with the given type arguments.
|
||||||
|
// typ must be a *Named or a *Signature type, it must be generic, and
|
||||||
|
// its number of type parameters must match the number of provided type
|
||||||
|
// arguments. The result is a new, instantiated (not generic) type of
|
||||||
|
// the same kind (either a *Named or a *Signature). The type arguments
|
||||||
|
// are not checked against the constraints of the type parameters.
|
||||||
|
// Any methods attached to a *Named are simply copied; they are not
|
||||||
|
// instantiated.
|
||||||
|
func Instantiate(pos syntax.Pos, typ Type, targs []Type) (res Type) {
|
||||||
|
// TODO(gri) This code is basically identical to the prolog
|
||||||
|
// in Checker.instantiate. Factor.
|
||||||
|
var tparams []*TypeName
|
||||||
|
switch t := typ.(type) {
|
||||||
|
case *Named:
|
||||||
|
tparams = t.tparams
|
||||||
|
case *Signature:
|
||||||
|
tparams = t.tparams
|
||||||
|
defer func() {
|
||||||
|
// If we had an unexpected failure somewhere don't panic below when
|
||||||
|
// asserting res.(*Signature). Check for *Signature in case Typ[Invalid]
|
||||||
|
// is returned.
|
||||||
|
if _, ok := res.(*Signature); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// If the signature doesn't use its type parameters, subst
|
||||||
|
// will not make a copy. In that case, make a copy now (so
|
||||||
|
// we can set tparams to nil w/o causing side-effects).
|
||||||
|
if t == res {
|
||||||
|
copy := *t
|
||||||
|
res = ©
|
||||||
|
}
|
||||||
|
// After instantiating a generic signature, it is not generic
|
||||||
|
// anymore; we need to set tparams to nil.
|
||||||
|
res.(*Signature).tparams = nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
||||||
|
}
|
||||||
|
|
||||||
|
// the number of supplied types must match the number of type parameters
|
||||||
|
if len(targs) != len(tparams) {
|
||||||
|
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tparams) == 0 {
|
||||||
|
return typ // nothing to do (minor optimization)
|
||||||
|
}
|
||||||
|
|
||||||
|
smap := makeSubstMap(tparams, targs)
|
||||||
|
return (*Checker)(nil).subst(pos, typ, smap)
|
||||||
|
}
|
@ -308,6 +308,9 @@ func (subst *subster) typ(typ Type) Type {
|
|||||||
embeddeds, ecopied := subst.typeList(t.embeddeds)
|
embeddeds, ecopied := subst.typeList(t.embeddeds)
|
||||||
if mcopied || types != t.types || ecopied {
|
if mcopied || types != t.types || ecopied {
|
||||||
iface := &Interface{methods: methods, types: types, embeddeds: embeddeds}
|
iface := &Interface{methods: methods, types: types, embeddeds: embeddeds}
|
||||||
|
if subst.check == nil {
|
||||||
|
panic("internal error: cannot instantiate interfaces yet")
|
||||||
|
}
|
||||||
subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement
|
subst.check.posMap[iface] = subst.check.posMap[t] // satisfy completeInterface requirement
|
||||||
subst.check.completeInterface(nopos, iface)
|
subst.check.completeInterface(nopos, iface)
|
||||||
return iface
|
return iface
|
||||||
@ -327,12 +330,14 @@ func (subst *subster) typ(typ Type) Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *Named:
|
case *Named:
|
||||||
subst.check.indent++
|
// dump is for debugging
|
||||||
defer func() {
|
dump := func(string, ...interface{}) {}
|
||||||
subst.check.indent--
|
if subst.check != nil && subst.check.conf.Trace {
|
||||||
}()
|
subst.check.indent++
|
||||||
dump := func(format string, args ...interface{}) {
|
defer func() {
|
||||||
if subst.check.conf.Trace {
|
subst.check.indent--
|
||||||
|
}()
|
||||||
|
dump = func(format string, args ...interface{}) {
|
||||||
subst.check.trace(subst.pos, format, args...)
|
subst.check.trace(subst.pos, format, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,17 +382,21 @@ func (subst *subster) typ(typ Type) Type {
|
|||||||
// before creating a new named type, check if we have this one already
|
// before creating a new named type, check if we have this one already
|
||||||
h := instantiatedHash(t, new_targs)
|
h := instantiatedHash(t, new_targs)
|
||||||
dump(">>> new type hash: %s", h)
|
dump(">>> new type hash: %s", h)
|
||||||
if named, found := subst.check.typMap[h]; found {
|
if subst.check != nil {
|
||||||
dump(">>> found %s", named)
|
if named, found := subst.check.typMap[h]; found {
|
||||||
subst.cache[t] = named
|
dump(">>> found %s", named)
|
||||||
return named
|
subst.cache[t] = named
|
||||||
|
return named
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new named type and populate caches to avoid endless recursion
|
// create a new named type and populate caches to avoid endless recursion
|
||||||
tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
|
tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
|
||||||
named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily
|
named := subst.check.newNamed(tname, t, t.underlying, t.tparams, t.methods) // method signatures are updated lazily
|
||||||
named.targs = new_targs
|
named.targs = new_targs
|
||||||
subst.check.typMap[h] = named
|
if subst.check != nil {
|
||||||
|
subst.check.typMap[h] = named
|
||||||
|
}
|
||||||
subst.cache[t] = named
|
subst.cache[t] = named
|
||||||
|
|
||||||
// do the substitution
|
// do the substitution
|
||||||
|
Loading…
Reference in New Issue
Block a user