[dev.typeparams] cmd/compile/internal/types2: use InstantiateLazy to create instance types (cleanup)

This change concentrates the creation is lazily instantiated types
in one place (InstantiateLazy). This should also make it easier to
replace the implementation of lazily instantiated types (e.g. getting
rid of instance types).

Change-Id: I452c463219b466ce79f227c44fb67b79d428842a
Reviewed-on: https://go-review.googlesource.com/c/go/+/333669
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-07-09 15:04:15 -07:00
parent 70f1246a9f
commit d0324eb8fb
4 changed files with 27 additions and 38 deletions

View file

@ -224,7 +224,7 @@ func (r *reader2) doTyp() (res types2.Type) {
obj, targs := r.obj() obj, targs := r.obj()
name := obj.(*types2.TypeName) name := obj.(*types2.TypeName)
if len(targs) != 0 { if len(targs) != 0 {
return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs, false) return r.p.check.InstantiateLazy(syntax.Pos{}, name.Type(), targs, nil, false)
} }
return name.Type() return name.Type()

View file

@ -15,7 +15,7 @@ type instance struct {
pos syntax.Pos // position of type instantiation; for error reporting only pos syntax.Pos // position of type instantiation; for error reporting only
base *Named // parameterized type to be instantiated base *Named // parameterized type to be instantiated
targs []Type // type arguments targs []Type // type arguments
poslist []syntax.Pos // position of each targ; for error reporting only posList []syntax.Pos // position of each targ; for error reporting only
verify bool // if set, constraint satisfaction is verified 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
} }
@ -26,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, t.verify) 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]
} }

View file

@ -112,19 +112,21 @@ func (check *Checker) Instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
} }
// InstantiateLazy is like Instantiate, but avoids actually // InstantiateLazy is like Instantiate, but avoids actually
// instantiating the type until needed. // instantiating the type until needed. typ must be a *Named
func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, verify bool) (res Type) { // type.
func (check *Checker) InstantiateLazy(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos, verify bool) 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))
} }
return &instance{ return &instance{
check: check, check: check,
pos: pos, pos: pos,
base: base, base: base,
targs: targs, targs: targs,
verify: verify, posList: posList,
verify: verify,
} }
} }

View file

@ -410,45 +410,32 @@ func (check *Checker) typOrNil(e syntax.Expr) Type {
return Typ[Invalid] return Typ[Invalid]
} }
func (check *Checker) instantiatedType(x syntax.Expr, targs []syntax.Expr, def *Named) Type { func (check *Checker) instantiatedType(x syntax.Expr, targsx []syntax.Expr, def *Named) Type {
b := check.genericType(x, true) // TODO(gri) what about cycles? base := check.genericType(x, true)
if b == Typ[Invalid] { if base == Typ[Invalid] {
return b // error already reported 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 // evaluate arguments
// TODO(gri) should do argument number check here rather than targs := check.typeList(targsx)
// when instantiating the type? if targs == nil {
// TODO(gri) use InstantiateLazy here (cleanup)
typ := new(instance)
def.setUnderlying(typ)
typ.check = check
typ.pos = x.Pos()
typ.base = base
typ.verify = true
// evaluate arguments (always)
typ.targs = check.typeList(targs)
if typ.targs == nil {
def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation
return Typ[Invalid] return Typ[Invalid]
} }
// determine argument positions (for error reporting) // determine argument positions
typ.poslist = make([]syntax.Pos, len(targs)) posList := make([]syntax.Pos, len(targs))
for i, arg := range targs { for i, arg := range targsx {
typ.poslist[i] = syntax.StartPos(arg) posList[i] = syntax.StartPos(arg)
} }
typ := check.InstantiateLazy(x.Pos(), base, targs, posList, true)
def.setUnderlying(typ)
// make sure we check instantiation works at least once // make sure we check instantiation works at least once
// and that the resulting type is valid // and that the resulting type is valid
check.later(func() { check.later(func() {
t := typ.expand() t := typ.(*instance).expand()
check.validType(t, nil) check.validType(t, nil)
}) })