1
0
mirror of https://github.com/golang/go synced 2024-11-22 16:14:56 -07:00

cmd/compile/internal/types2: delay recording types of untyped operands when checking against type parameters

Don't eagerly record the target type for an untyped operand if the
target type is just one of possibly many types in the type list of
a type parameter. Instead, record expression type only after we
checked that all types in the type list are ok.

Also, update assertion in Checker.recordTypeAndValue since (currently),
a type parameter is not considered a const type. We may change that,
eventually.

This is a temporary (but working) solution. Eventually we should
copy the approach taken in go/types.

Fixes #45096.

Change-Id: Icf61ee893aca6ead32bfc45ee5831572e672357b
Reviewed-on: https://go-review.googlesource.com/c/go/+/302755
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Robert Griesemer 2021-03-17 16:59:47 -07:00
parent 2583c1b4df
commit 51e4bb236c
3 changed files with 16 additions and 7 deletions

View File

@ -337,6 +337,9 @@ func TestTypesInfo(t *testing.T) {
// instantiated types must be sanitized
{`package g0; type t[P any] int; var x struct{ f t[int] }; var _ = x.f`, `x.f`, `g0.t[int]`},
// issue 45096
{`package issue45096; func _[T interface{ type int8, int16, int32 }](x T) { _ = x < 0 }`, `0`, `T₁`},
}
for _, test := range tests {

View File

@ -335,7 +335,9 @@ func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Ty
}
if mode == constant_ {
assert(val != nil)
assert(typ == Typ[Invalid] || isConstType(typ))
// We check is(typ, IsConstType) here as constant expressions may be
// recorded as type parameters.
assert(typ == Typ[Invalid] || is(typ, IsConstType))
}
if m := check.Types; m != nil {
m[x] = TypeAndValue{mode, typ, val}

View File

@ -628,7 +628,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
for _, t := range unpack(types) {
x := *x // make a copy; convertUntypedInternal modifies x
check.convertUntypedInternal(&x, t)
check.convertUntypedInternal(&x, t, false)
if x.mode == invalid {
goto Error
}
@ -639,7 +639,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
return
}
check.convertUntypedInternal(x, target)
check.convertUntypedInternal(x, target, true)
return
Error:
@ -649,7 +649,7 @@ Error:
}
// convertUntypedInternal should only be called by convertUntyped.
func (check *Checker) convertUntypedInternal(x *operand, target Type) {
func (check *Checker) convertUntypedInternal(x *operand, target Type, update bool) {
assert(isTyped(target))
if x.isNil() {
@ -669,7 +669,9 @@ func (check *Checker) convertUntypedInternal(x *operand, target Type) {
return
}
// expression value may have been rounded - update if needed
check.updateExprVal(x.expr, x.val)
if update {
check.updateExprVal(x.expr, x.val)
}
} else {
// Non-constant untyped values may appear as the
// result of comparisons (untyped bool), intermediate
@ -694,7 +696,7 @@ func (check *Checker) convertUntypedInternal(x *operand, target Type) {
}
case *Sum:
t.is(func(t Type) bool {
check.convertUntypedInternal(x, t)
check.convertUntypedInternal(x, t, false)
return x.mode != invalid
})
case *Interface:
@ -712,7 +714,9 @@ func (check *Checker) convertUntypedInternal(x *operand, target Type) {
OK:
x.typ = target
check.updateExprType(x.expr, target, true)
if update {
check.updateExprType(x.expr, target, true)
}
return
Error: