mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +00:00
[dev.typeparams] go/types: trigger verification while resolving instance
The refactoring of CL 335929 to merge the instance and Named types resulted in type instances only being evaluated once. As a side effect, we only verified constraints once per unique instantiation expression. This can be confusing if type instantations are occurring far apart in the code. Resolve this by lifting up the verification logic into Instantiate and InstantiateLazy. Change-Id: Icd5a482d097d983073955c62931441edfd92f5c2 Reviewed-on: https://go-review.googlesource.com/c/go/+/335978 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
61f69d2559
commit
b7149b781f
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
4
src/go/types/testdata/check/issues.go2
vendored
4
src/go/types/testdata/check/issues.go2
vendored
|
@ -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 _() {
|
||||
|
|
Loading…
Reference in a new issue