mirror of
https://github.com/golang/go
synced 2024-09-15 22:20:06 +00:00
[dev.typeparams] go/types: replace types2.Instantiate with Checker.Instantiate
This is a partial port of CL 333569 containing just changes to go/types. Changes to the importer wil be made in a separate CL. Change-Id: I9383e260b76402875ca6eb23c4478a6a3e8c1f0d Reviewed-on: https://go-review.googlesource.com/c/go/+/335071 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
9e147c55b7
commit
41ff0aac13
|
@ -1833,7 +1833,9 @@ func TestInstantiate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// instantiation should succeed (no endless recursion)
|
// instantiation should succeed (no endless recursion)
|
||||||
res := Instantiate(token.NoPos, T, []Type{Typ[Int]})
|
// even with a nil *Checker
|
||||||
|
var check *Checker
|
||||||
|
res := check.Instantiate(token.NoPos, T, []Type{Typ[Int]}, nil, false)
|
||||||
|
|
||||||
// instantiated type should point to itself
|
// instantiated type should point to itself
|
||||||
if res.Underlying().(*Pointer).Elem() != res {
|
if res.Underlying().(*Pointer).Elem() != res {
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// instantiate function signature
|
// instantiate function signature
|
||||||
res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
|
res := check.Instantiate(x.Pos(), sig, targs, poslist, true).(*Signature)
|
||||||
assert(res.tparams == nil) // signature is not generic anymore
|
assert(res.tparams == nil) // signature is not generic anymore
|
||||||
if inferred {
|
if inferred {
|
||||||
check.recordInferred(ix.Orig, targs, res)
|
check.recordInferred(ix.Orig, targs, res)
|
||||||
|
@ -333,7 +333,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute result signature
|
// compute result signature
|
||||||
rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
|
rsig = check.Instantiate(call.Pos(), sig, targs, nil, true).(*Signature)
|
||||||
assert(rsig.tparams == nil) // signature is not generic anymore
|
assert(rsig.tparams == nil) // signature is not generic anymore
|
||||||
check.recordInferred(call, targs, rsig)
|
check.recordInferred(call, targs, rsig)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ type instance struct {
|
||||||
base *Named // parameterized type to be instantiated
|
base *Named // parameterized type to be instantiated
|
||||||
targs []Type // type arguments
|
targs []Type // type arguments
|
||||||
poslist []token.Pos // position of each targ; for error reporting only
|
poslist []token.Pos // position of each targ; for error reporting only
|
||||||
|
verify bool // if set, constraint satisfaction is verified
|
||||||
value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set
|
value Type // base[targs...] after instantiation or Typ[Invalid]; nil if not yet set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ type instance struct {
|
||||||
func (t *instance) expand() Type {
|
func (t *instance) expand() Type {
|
||||||
v := t.value
|
v := t.value
|
||||||
if v == nil {
|
if v == nil {
|
||||||
v = t.check.instantiate(t.pos, t.base, t.targs, t.poslist)
|
v = t.check.Instantiate(t.pos, t.base, t.targs, t.poslist, t.verify)
|
||||||
if v == nil {
|
if v == nil {
|
||||||
v = Typ[Invalid]
|
v = Typ[Invalid]
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,62 +9,9 @@ import (
|
||||||
"go/token"
|
"go/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 token.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstantiateLazy is like Instantiate, but avoids actually
|
// InstantiateLazy is like Instantiate, but avoids actually
|
||||||
// instantiating the type until needed.
|
// instantiating the type until needed.
|
||||||
func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type) (res Type) {
|
func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, verify bool) (res Type) {
|
||||||
base := asNamed(typ)
|
base := asNamed(typ)
|
||||||
if base == nil {
|
if base == nil {
|
||||||
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
||||||
|
@ -75,5 +22,6 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type) (re
|
||||||
pos: pos,
|
pos: pos,
|
||||||
base: base,
|
base: base,
|
||||||
targs: targs,
|
targs: targs,
|
||||||
|
verify: verify,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func TestSizeof(t *testing.T) {
|
||||||
{Chan{}, 12, 24},
|
{Chan{}, 12, 24},
|
||||||
{Named{}, 84, 160},
|
{Named{}, 84, 160},
|
||||||
{TypeParam{}, 28, 48},
|
{TypeParam{}, 28, 48},
|
||||||
{instance{}, 44, 88},
|
{instance{}, 48, 96},
|
||||||
{top{}, 0, 0},
|
{top{}, 0, 0},
|
||||||
|
|
||||||
// Objects
|
// Objects
|
||||||
|
|
|
@ -56,8 +56,24 @@ func (m *substMap) lookup(tpar *TypeParam) Type {
|
||||||
return tpar
|
return tpar
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist []token.Pos) (res Type) {
|
// Instantiate instantiates the type typ with the given type arguments
|
||||||
if trace {
|
// targs. To check type constraint satisfaction, verify must be set.
|
||||||
|
// pos and posList correspond to the instantiation and type argument
|
||||||
|
// positions respectively; posList may be nil or shorter than the number
|
||||||
|
// of type arguments provided.
|
||||||
|
// typ must be a *Named or a *Signature type, and its number of type
|
||||||
|
// parameters must match the number of provided type arguments.
|
||||||
|
// The receiver (check) may be nil if and only if verify is not set.
|
||||||
|
// The result is a new, instantiated (not generic) type of the same kind
|
||||||
|
// (either a *Named or a *Signature).
|
||||||
|
// Any methods attached to a *Named are simply copied; they are not
|
||||||
|
// instantiated.
|
||||||
|
func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) (res Type) {
|
||||||
|
if verify && check == nil {
|
||||||
|
panic("cannot have nil receiver if verify is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if check != nil && trace {
|
||||||
check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
|
check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
|
||||||
check.indent++
|
check.indent++
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -73,7 +89,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(len(poslist) <= len(targs))
|
assert(len(posList) <= len(targs))
|
||||||
|
|
||||||
// TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
|
// TODO(gri) What is better here: work with TypeParams, or work with TypeNames?
|
||||||
var tparams []*TypeName
|
var tparams []*TypeName
|
||||||
|
@ -100,18 +116,20 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
||||||
// anymore; we need to set tparams to nil.
|
// anymore; we need to set tparams to nil.
|
||||||
res.(*Signature).tparams = nil
|
res.(*Signature).tparams = nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
check.dump("%v: cannot instantiate %v", pos, typ)
|
// only types and functions can be generic
|
||||||
unreachable() // only defined types and (defined) functions can be generic
|
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
|
||||||
}
|
}
|
||||||
|
|
||||||
// the number of supplied types must match the number of type parameters
|
// the number of supplied types must match the number of type parameters
|
||||||
if len(targs) != len(tparams) {
|
if len(targs) != len(tparams) {
|
||||||
// TODO(gri) provide better error message
|
// TODO(gri) provide better error message
|
||||||
|
if check != nil {
|
||||||
check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams))
|
check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams))
|
||||||
return Typ[Invalid]
|
return Typ[Invalid]
|
||||||
}
|
}
|
||||||
|
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams)))
|
||||||
|
}
|
||||||
|
|
||||||
if len(tparams) == 0 {
|
if len(tparams) == 0 {
|
||||||
return typ // nothing to do (minor optimization)
|
return typ // nothing to do (minor optimization)
|
||||||
|
@ -120,11 +138,12 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
||||||
smap := makeSubstMap(tparams, targs)
|
smap := makeSubstMap(tparams, targs)
|
||||||
|
|
||||||
// check bounds
|
// check bounds
|
||||||
|
if verify {
|
||||||
for i, tname := range tparams {
|
for i, tname := range tparams {
|
||||||
// best position for error reporting
|
// best position for error reporting
|
||||||
pos := pos
|
pos := pos
|
||||||
if i < len(poslist) {
|
if i < len(posList) {
|
||||||
pos = poslist[i]
|
pos = posList[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop checking bounds after the first failure
|
// stop checking bounds after the first failure
|
||||||
|
@ -132,6 +151,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return check.subst(pos, typ, smap)
|
return check.subst(pos, typ, smap)
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,12 +413,14 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *Named) Typ
|
||||||
// create a new type instance rather than instantiate the type
|
// create a new type instance rather than instantiate the type
|
||||||
// TODO(gri) should do argument number check here rather than
|
// TODO(gri) should do argument number check here rather than
|
||||||
// when instantiating the type?
|
// when instantiating the type?
|
||||||
|
// TODO(gri) use InstantiateLazy here (cleanup)
|
||||||
typ := new(instance)
|
typ := new(instance)
|
||||||
def.setUnderlying(typ)
|
def.setUnderlying(typ)
|
||||||
|
|
||||||
typ.check = check
|
typ.check = check
|
||||||
typ.pos = ix.X.Pos()
|
typ.pos = ix.X.Pos()
|
||||||
typ.base = base
|
typ.base = base
|
||||||
|
typ.verify = true
|
||||||
|
|
||||||
// evaluate arguments (always)
|
// evaluate arguments (always)
|
||||||
typ.targs = check.typeList(ix.Indices)
|
typ.targs = check.typeList(ix.Indices)
|
||||||
|
|
Loading…
Reference in a new issue