]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: check non-generic conversions first
authorRobert Griesemer <gri@golang.org>
Thu, 4 Nov 2021 03:42:44 +0000 (20:42 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 4 Nov 2021 16:36:19 +0000 (16:36 +0000)
This enables the elimination of convertibleToImpl again,
with the code structure close to the original non-generic
version, and closely matching the structure of assignableTo.

We also don't need the hasTerm tests; instead we can rely
directly on the mechanism of TypeParam.is which is feeding
a nil term if there are no specific types.

Change-Id: I0385acca779d75c3c961d06afb464714fe51705d
Reviewed-on: https://go-review.googlesource.com/c/go/+/361269
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/conversions.go

index bd7b82fabffa354b92b0673117977267800a8da4..44e8aad84f065b4730d903489a1b34d4f01254b8 100644 (file)
@@ -122,64 +122,8 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
                return true
        }
 
-       // determine type parameter operands with specific type terms
-       Vp, _ := under(x.typ).(*TypeParam)
-       Tp, _ := under(T).(*TypeParam)
-       if Vp != nil && !Vp.hasTerms() {
-               Vp = nil
-       }
-       if Tp != nil && !Tp.hasTerms() {
-               Tp = nil
-       }
-
-       errorf := func(format string, args ...interface{}) {
-               if check != nil && cause != nil {
-                       msg := check.sprintf(format, args...)
-                       if *cause != "" {
-                               msg += "\n\t" + *cause
-                       }
-                       *cause = msg
-               }
-       }
-
-       // generic cases with specific type terms
-       // (generic operands cannot be constants, so we can ignore x.val)
-       switch {
-       case Vp != nil && Tp != nil:
-               return Vp.is(func(V *term) bool {
-                       return Tp.is(func(T *term) bool {
-                               if !convertibleToImpl(check, V.typ, T.typ, cause) {
-                                       errorf("cannot convert %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
-                                       return false
-                               }
-                               return true
-                       })
-               })
-       case Vp != nil:
-               return Vp.is(func(V *term) bool {
-                       if !convertibleToImpl(check, V.typ, T, cause) {
-                               errorf("cannot convert %s (in %s) to %s", V.typ, Vp, T)
-                               return false
-                       }
-                       return true
-               })
-       case Tp != nil:
-               return Tp.is(func(T *term) bool {
-                       if !convertibleToImpl(check, x.typ, T.typ, cause) {
-                               errorf("cannot convert %s to %s (in %s)", x.typ, T.typ, Tp)
-                               return false
-                       }
-                       return true
-               })
-       }
-
-       // non-generic case
-       return convertibleToImpl(check, x.typ, T, cause)
-}
-
-// convertibleToImpl should only be called by convertibleTo
-func convertibleToImpl(check *Checker, V, T Type, cause *string) bool {
        // "V and T have identical underlying types if tags are ignored"
+       V := x.typ
        Vu := under(V)
        Tu := under(T)
        if IdenticalIgnoreTags(Vu, Tu) {
@@ -250,6 +194,67 @@ func convertibleToImpl(check *Checker, V, T Type, cause *string) bool {
                }
        }
 
+       // optimization: if we don't have type parameters, we're done
+       Vp, _ := Vu.(*TypeParam)
+       Tp, _ := Tu.(*TypeParam)
+       if Vp == nil && Tp == nil {
+               return false
+       }
+
+       errorf := func(format string, args ...interface{}) {
+               if check != nil && cause != nil {
+                       msg := check.sprintf(format, args...)
+                       if *cause != "" {
+                               msg += "\n\t" + *cause
+                       }
+                       *cause = msg
+               }
+       }
+
+       // generic cases with specific type terms
+       // (generic operands cannot be constants, so we can ignore x.val)
+       switch {
+       case Vp != nil && Tp != nil:
+               x := *x // don't clobber outer x
+               return Vp.is(func(V *term) bool {
+                       if V == nil {
+                               return false // no specific types
+                       }
+                       x.typ = V.typ
+                       return Tp.is(func(T *term) bool {
+                               if !x.convertibleTo(check, T.typ, cause) {
+                                       errorf("cannot convert %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
+                                       return false
+                               }
+                               return true
+                       })
+               })
+       case Vp != nil:
+               x := *x // don't clobber outer x
+               return Vp.is(func(V *term) bool {
+                       if V == nil {
+                               return false // no specific types
+                       }
+                       x.typ = V.typ
+                       if !x.convertibleTo(check, T, cause) {
+                               errorf("cannot convert %s (in %s) to %s", V.typ, Vp, T)
+                               return false
+                       }
+                       return true
+               })
+       case Tp != nil:
+               return Tp.is(func(T *term) bool {
+                       if T == nil {
+                               return false // no specific types
+                       }
+                       if !x.convertibleTo(check, T.typ, cause) {
+                               errorf("cannot convert %s to %s (in %s)", x.typ, T.typ, Tp)
+                               return false
+                       }
+                       return true
+               })
+       }
+
        return false
 }