From: Robert Griesemer Date: Wed, 17 Mar 2021 23:59:47 +0000 (-0700) Subject: cmd/compile/internal/types2: delay recording types of untyped operands when checking... X-Git-Tag: go1.17beta1~1075 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=51e4bb236cb8feb8118ed6dd768ddac834dad2ef;p=gostls13.git 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 Run-TryBot: Robert Griesemer Reviewed-by: Robert Findley TryBot-Result: Go Bot --- diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 9d23b5b2a6..a06a073f97 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -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 { diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 7c1d4eae56..c65666e802 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -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} diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index b89eb199eb..4cdec84604 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -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: