From 4d00fcbc4303bca38ecfc1c8a07661089496c1ab Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Mon, 16 Aug 2021 15:59:08 -0400 Subject: [PATCH] go/types: clean up panics in instantiation This is a straightforward port of CL 341862 to go/types. Change-Id: I4214c08d2889e2daf40254385656c6beed79571d Reviewed-on: https://go-review.googlesource.com/c/go/+/342487 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer --- src/go/types/instantiate.go | 43 +++++++++++++++++++++---------------- src/go/types/named.go | 9 ++++---- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 8133067229..37184cb0ab 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -53,15 +53,18 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList // only types and functions can be generic panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + inst := check.instantiate(pos, typ, tparams, targs, nil) - inst := check.instantiate(pos, typ, tparams, targs, posList, nil) - if verify && len(tparams) == len(targs) { - check.verify(pos, tparams, targs, posList) + if verify { + assert(len(posList) <= len(targs)) + if len(tparams) == len(targs) { + check.verify(pos, tparams, targs, posList) + } } return inst } -func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, targs []Type, posList []token.Pos, typMap map[string]*Named) (res Type) { +func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, targs []Type, typMap map[string]*Named) (res Type) { // the number of supplied types must match the number of type parameters if len(targs) != len(tparams) { // TODO(gri) provide better error message @@ -88,8 +91,6 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, }() } - assert(len(posList) <= len(targs)) - // TODO(gri) What is better here: work with TypeParams, or work with TypeNames? if len(tparams) == 0 { @@ -101,14 +102,21 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, // instantiateLazy avoids actually instantiating the type until needed. typ // must be a *Named type. -func (check *Checker) instantiateLazy(pos token.Pos, base *Named, targs []Type, posList []token.Pos, verify bool) Type { - if verify && base.TParams().Len() == len(targs) { - // TODO: lift the nil check in verify to here. - check.later(func() { - check.verify(pos, base.tparams.list(), targs, posList) - }) - } - h := instantiatedHash(base, targs) +func (check *Checker) instantiateLazy(pos token.Pos, orig *Named, targs []Type, posList []token.Pos, verify bool) Type { + if verify { + if check == nil { + // Provide a more useful panic instead of panicking at check.later below. + panic("cannot have nil Checker if verifying constraints") + } + assert(len(posList) <= len(targs)) + if orig.TParams().Len() == len(targs) { + check.later(func() { + check.verify(pos, orig.tparams.list(), targs, posList) + }) + } + } + + h := instantiatedHash(orig, targs) if check != nil { // typ may already have been instantiated with identical type arguments. In // that case, re-use the existing instance. @@ -117,10 +125,10 @@ func (check *Checker) instantiateLazy(pos token.Pos, base *Named, targs []Type, } } - tname := NewTypeName(pos, base.obj.pkg, base.obj.name, nil) - named := check.newNamed(tname, base, nil, nil, nil) // methods and tparams are set when named is loaded. + tname := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil) + named := check.newNamed(tname, orig, nil, nil, nil) // methods and tparams are set when named is loaded named.targs = targs - named.instance = &instance{pos, posList} + named.instance = &instance{pos} if check != nil { check.typMap[h] = named @@ -133,7 +141,6 @@ func (check *Checker) verify(pos token.Pos, tparams []*TypeName, targs []Type, p if check == nil { panic("cannot have nil Checker if verifying constraints") } - smap := makeSubstMap(tparams, targs) for i, tname := range tparams { // best position for error reporting diff --git a/src/go/types/named.go b/src/go/types/named.go index 90abd117e2..d621e5ef21 100644 --- a/src/go/types/named.go +++ b/src/go/types/named.go @@ -248,11 +248,10 @@ func (n *Named) setUnderlying(typ Type) { // instance holds position information for use in lazy instantiation. // -// TODO(rfindley): come up with a better name for this type, now that its usage -// has changed. +// TODO(rfindley): instance is probably unnecessary now. See if it can be +// eliminated. type instance struct { - pos token.Pos // position of type instantiation; for error reporting only - posList []token.Pos // position of each targ; for error reporting only + pos token.Pos // position of type instantiation; for error reporting only } // expand ensures that the underlying type of n is instantiated. @@ -276,7 +275,7 @@ func (n *Named) expand(typMap map[string]*Named) *Named { } } - inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, n.instance.posList, typMap) + inst := n.check.instantiate(n.instance.pos, n.orig.underlying, n.TParams().list(), n.targs, typMap) n.underlying = inst n.fromRHS = inst n.instance = nil -- 2.50.0