mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
cmd/compile: add early a CONVIFACE normally created in the order phase
Most CONVIFACEs are created in the transform phase (or old typechecker, in -G=0 mode). But if the main result of a multi-value assignment (map, channel, or dot-type) must be converted to an interface during the assignment, that CONVIFACE is not created until (*orderState).as2ok in the order phase (because the AS2* ops and their sub-ops are so tightly intertwined). But we need to create the CONVIFACE during the stenciling/transform phase to enable dictionary lookups. So, in transformAssign(), if we are doing a special multi-value assignment involving a type-param-derived type, assign the results first to temps, so that we can manifest the CONVIFACE during the transform in assigning the first temp to lhs[0]. Added a test for both AS2RECV (channel receives) and AS2MAPR (maps). I don't think we can have a type assertion on a type-param-derived type. Fixes #50642 Change-Id: I4d079fc46c93d8494d7db4ea8234d91522edb02a Reviewed-on: https://go-review.googlesource.com/c/go/+/379054 Reviewed-by: Matthew Dempsky <mdempsky@google.com> Trust: Dan Scales <danscales@google.com> Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
1efc5815dd
commit
c1296af151
|
@ -356,6 +356,37 @@ assignOK:
|
|||
}
|
||||
checkLHS(0, r.Type())
|
||||
checkLHS(1, types.UntypedBool)
|
||||
t := lhs[0].Type()
|
||||
if t != nil && rhs[0].Type().HasShape() && t.IsInterface() && !types.IdenticalStrict(t, rhs[0].Type()) {
|
||||
// This is a multi-value assignment (map, channel, or dot-type)
|
||||
// where the main result is converted to an interface during the
|
||||
// assignment. Normally, the needed CONVIFACE is not created
|
||||
// until (*orderState).as2ok(), because the AS2* ops and their
|
||||
// sub-ops are so tightly intertwined. But we need to create the
|
||||
// CONVIFACE now to enable dictionary lookups. So, assign the
|
||||
// results first to temps, so that we can manifest the CONVIFACE
|
||||
// in assigning the first temp to lhs[0]. If we added the
|
||||
// CONVIFACE into rhs[0] directly, we would break a lot of later
|
||||
// code that depends on the tight coupling between the AS2* ops
|
||||
// and their sub-ops. (Issue #50642).
|
||||
v := typecheck.Temp(rhs[0].Type())
|
||||
ok := typecheck.Temp(types.Types[types.TBOOL])
|
||||
as := ir.NewAssignListStmt(base.Pos, stmt.Op(), []ir.Node{v, ok}, []ir.Node{r})
|
||||
as.Def = true
|
||||
as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, v))
|
||||
as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, ok))
|
||||
as.SetTypecheck(1)
|
||||
// Change stmt to be a normal assignment of the temps to the final
|
||||
// left-hand-sides. We re-create the original multi-value assignment
|
||||
// so that it assigns to the temps and add it as an init of stmt.
|
||||
//
|
||||
// TODO: fix the order of evaluation, so that the lval of lhs[0]
|
||||
// is evaluated before rhs[0] (similar to problem in #50672).
|
||||
stmt.SetOp(ir.OAS2)
|
||||
stmt.PtrInit().Append(as)
|
||||
// assignconvfn inserts the CONVIFACE.
|
||||
stmt.Rhs = []ir.Node{assignconvfn(v, t), ok}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
63
test/typeparam/issue50642.go
Normal file
63
test/typeparam/issue50642.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
// run -gcflags=-G=3
|
||||
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Temp[T any] struct {
|
||||
}
|
||||
|
||||
var temp, temp1 any
|
||||
var ch any
|
||||
|
||||
func (it Temp[T]) HasNext() bool {
|
||||
var ok bool
|
||||
temp1 = <-ch.(chan T)
|
||||
// test conversion of T to interface{} during an OAS2RECV
|
||||
temp, ok = <-ch.(chan T)
|
||||
return ok
|
||||
}
|
||||
|
||||
type MyInt int
|
||||
|
||||
func (i MyInt) String() string {
|
||||
return "a"
|
||||
}
|
||||
|
||||
type Stringer interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
type Temp2[T Stringer] struct {
|
||||
}
|
||||
|
||||
var temp2 Stringer
|
||||
|
||||
func (it Temp2[T]) HasNext() string {
|
||||
var x map[int]T
|
||||
|
||||
var ok bool
|
||||
// test conversion of T to Stringer during an OAS2MAPR
|
||||
temp2, ok = x[43]
|
||||
_ = ok
|
||||
return temp2.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
ch1 := make(chan int, 2)
|
||||
ch1 <- 5
|
||||
ch1 <- 6
|
||||
ch = ch1
|
||||
iter := Temp[int]{}
|
||||
iter.HasNext()
|
||||
|
||||
iter2 := Temp2[MyInt]{}
|
||||
if got, want := iter2.HasNext(), "a"; got != want {
|
||||
panic(fmt.Sprintf("got %v, want %v", got, want))
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue