]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: check non-generic conversions first
authorRobert Findley <rfindley@google.com>
Tue, 9 Nov 2021 16:14:37 +0000 (11:14 -0500)
committerRobert Findley <rfindley@google.com>
Tue, 9 Nov 2021 19:01:20 +0000 (19:01 +0000)
This is a clean port of CL 361269 to go/types.

Change-Id: I2caaf08eabdf1707ae83ec1e628fd26f21b2b8e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/362616
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/conversions.go

index c171b2c8d6137fb124b8238c4230bef3db089e78..f73e6a0964830326b425058092f2eb78c75c9613 100644 (file)
@@ -120,64 +120,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) {
@@ -241,6 +185,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
 }