diff --git a/src/go/types/instance.go b/src/go/types/instance.go index 205cb47046..9d31b42690 100644 --- a/src/go/types/instance.go +++ b/src/go/types/instance.go @@ -24,7 +24,7 @@ type instance struct { func (n *Named) complete() { if n.instance != nil && len(n.targs) > 0 && n.underlying == nil { check := n.instance.check - inst := check.instantiate(n.instance.pos, n.orig.underlying, n.tparams, n.targs, n.instance.posList, n.instance.verify) + inst := check.instantiate(n.instance.pos, n.orig.underlying, n.tparams, n.targs, n.instance.posList) n.underlying = inst n.fromRHS = inst n.methods = n.orig.methods diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 270652149f..14bbf2b12b 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -54,10 +54,14 @@ func (check *Checker) Instantiate(pos token.Pos, typ Type, targs []Type, posList panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } - return check.instantiate(pos, typ, tparams, targs, posList, verify) + inst := check.instantiate(pos, typ, tparams, targs, posList) + if verify && 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, verify bool) (res Type) { +func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, targs []Type, posList []token.Pos) (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 @@ -67,9 +71,6 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, } panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, len(targs), len(tparams))) } - 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)) @@ -97,22 +98,6 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, tparams []*TypeName, smap := makeSubstMap(tparams, targs) - // check bounds - if verify { - for i, tname := range tparams { - // best position for error reporting - pos := pos - if i < len(posList) { - pos = posList[i] - } - - // stop checking bounds after the first failure - if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { - break - } - } - } - return check.subst(pos, typ, smap) } @@ -124,6 +109,11 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos if base == nil { panic(fmt.Sprintf("%v: cannot instantiate %v", pos, typ)) } + if verify && len(base.tparams) == len(targs) { + check.later(func() { + check.verify(pos, base.tparams, targs, posList) + }) + } h := instantiatedHash(base, targs) if check != nil { if named := check.typMap[h]; named != nil { @@ -146,6 +136,26 @@ func (check *Checker) InstantiateLazy(pos token.Pos, typ Type, targs []Type, pos return named } +func (check *Checker) verify(pos token.Pos, tparams []*TypeName, targs []Type, posList []token.Pos) { + 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 + pos := pos + if i < len(posList) { + pos = posList[i] + } + + // stop checking bounds after the first failure + if !check.satisfies(pos, targs[i], tname.typ.(*TypeParam), smap) { + break + } + } +} + // satisfies reports whether the type argument targ satisfies the constraint of type parameter // parameter tpar (after any of its type parameters have been substituted through smap). // A suitable error is reported if the result is false. diff --git a/src/go/types/testdata/check/issues.go2 b/src/go/types/testdata/check/issues.go2 index ce0d608216..c57f002303 100644 --- a/src/go/types/testdata/check/issues.go2 +++ b/src/go/types/testdata/check/issues.go2 @@ -81,10 +81,8 @@ func (u T2[U]) Add1() U { return u.s + 1 } -// TODO(rfindley): we should probably report an error here as well, not -// just when the type is first instantiated. func NewT2[U any]() T2[U /* ERROR U has no type constraints */ ] { - return T2[U]{} + return T2[U /* ERROR U has no type constraints */ ]{} } func _() {