pos token.Pos // position of type instantiation; for error reporting only
base *Named // parameterized type to be instantiated
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
}
func (t *instance) expand() Type {
v := t.value
if v == nil {
- v = t.check.Instantiate(t.pos, t.base, t.targs, t.poslist, t.verify)
+ v = t.check.Instantiate(t.pos, t.base, t.targs, t.posList, t.verify)
if v == nil {
v = Typ[Invalid]
}
}
// InstantiateLazy is like Instantiate, but avoids actually
-// instantiating the type until needed.
-func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, verify bool) (res Type) {
+// instantiating the type until needed. typ must be a *Named
+// type.
+func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, posList []token.Pos, verify bool) Type {
base := asNamed(typ)
if base == nil {
panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ))
}
return &instance{
- check: check,
- pos: pos,
- base: base,
- targs: targs,
- verify: verify,
+ check: check,
+ pos: pos,
+ base: base,
+ targs: targs,
+ posList: posList,
+ verify: verify,
}
}
case *ast.IndexExpr, *ast.MultiIndexExpr:
ix := typeparams.UnpackIndexExpr(e)
// TODO(rfindley): type instantiation should require go1.18
- return check.instantiatedType(ix, def)
+ return check.instantiatedType(ix.X, ix.Indices, def)
case *ast.ParenExpr:
// Generic types must be instantiated before they can be used in any form.
return Typ[Invalid]
}
-func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *Named) Type {
- b := check.genericType(ix.X, true) // TODO(gri) what about cycles?
- if b == Typ[Invalid] {
- return b // error already reported
+func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named) Type {
+ base := check.genericType(x, true)
+ if base == Typ[Invalid] {
+ return base // error already reported
}
- base := asNamed(b)
- if base == nil {
- unreachable() // should have been caught by genericType
- }
-
- // create a new type instance rather than instantiate the type
- // TODO(gri) should do argument number check here rather than
- // when instantiating the type?
- // TODO(gri) use InstantiateLazy here (cleanup)
- typ := new(instance)
- def.setUnderlying(typ)
- typ.check = check
- typ.pos = ix.X.Pos()
- typ.base = base
- typ.verify = true
-
- // evaluate arguments (always)
- typ.targs = check.typeList(ix.Indices)
- if typ.targs == nil {
+ // evaluate arguments
+ targs := check.typeList(targsx)
+ if targs == nil {
def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation
return Typ[Invalid]
}
- // determine argument positions (for error reporting)
- typ.poslist = make([]token.Pos, len(ix.Indices))
- for i, arg := range ix.Indices {
- typ.poslist[i] = arg.Pos()
+ // determine argument positions
+ posList := make([]token.Pos, len(targs))
+ for i, arg := range targsx {
+ posList[i] = arg.Pos()
}
+ typ := check.InstantiateLazy(x.Pos(), base, targs, posList, true)
+ def.setUnderlying(typ)
+
// make sure we check instantiation works at least once
// and that the resulting type is valid
check.later(func() {
- t := typ.expand()
+ t := typ.(*instance).expand()
check.validType(t, nil)
})