mirror of https://github.com/golang/go.git
cmd/compile/internal/types2: check non-generic conversions first
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>
This commit is contained in:
parent
6ba68a0581
commit
f934b8326f
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue