]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] go/types: trigger verification while resolving instance
authorRob Findley <rfindley@google.com>
Tue, 20 Jul 2021 17:07:50 +0000 (13:07 -0400)
committerRobert Findley <rfindley@google.com>
Thu, 22 Jul 2021 14:01:09 +0000 (14:01 +0000)
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>
src/go/types/instance.go
src/go/types/instantiate.go
src/go/types/testdata/check/issues.go2

index 205cb470464dec232e8f3fdb79ca4eb0c3839f7e..9d31b42690a1e22368f1938adb2bed33134d1815 100644 (file)
@@ -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
index 270652149f613ac84e61fe81828bc8a19dd1e02c..14bbf2b12b1e8e8c54138a99af99e3a2c5193559 100644 (file)
@@ -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.
index ce0d608216351b4b72a6959b03078b5cdb676c8c..c57f00230340d30fb8525be409a048ac1f1e9c6a 100644 (file)
@@ -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 _() {