mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.unified] cmd/compile: plumb rtype through OSWITCH/OCASE clauses
For (value) switch statements, we may generate OEQ comparisons between values of interface and concrete type, which in turn may require access to the concrete type's RType. To plumb this through, this CL adds CaseClause.RTypes to hold the rtype values, updates the GOEXPERIMENT=unified frontend to set it, and updates walk to plumb rtypes through into generated OEQ nodes. Change-Id: I6f1de2a1167ce54f5770147498a0a591efb3f012 Reviewed-on: https://go-review.googlesource.com/c/go/+/413361 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: David Chase <drchase@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
3d432b6c4b
commit
61ae2b734c
4 changed files with 47 additions and 10 deletions
|
|
@ -170,6 +170,17 @@ type CaseClause struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
Var *Name // declared variable for this case in type switch
|
Var *Name // declared variable for this case in type switch
|
||||||
List Nodes // list of expressions for switch, early select
|
List Nodes // list of expressions for switch, early select
|
||||||
|
|
||||||
|
// RTypes is a list of RType expressions, which are copied to the
|
||||||
|
// corresponding OEQ nodes that are emitted when switch statements
|
||||||
|
// are desugared. RTypes[i] must be non-nil if the emitted
|
||||||
|
// comparison for List[i] will be a mixed interface/concrete
|
||||||
|
// comparison; see reflectdata.CompareRType for details.
|
||||||
|
//
|
||||||
|
// Because mixed interface/concrete switch cases are rare, we allow
|
||||||
|
// len(RTypes) < len(List). Missing entries are implicitly nil.
|
||||||
|
RTypes Nodes
|
||||||
|
|
||||||
Body Nodes
|
Body Nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1487,7 +1487,7 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node {
|
||||||
r.openScope()
|
r.openScope()
|
||||||
|
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
var cases []ir.Node
|
var cases, rtypes []ir.Node
|
||||||
if iface != nil {
|
if iface != nil {
|
||||||
cases = make([]ir.Node, r.Len())
|
cases = make([]ir.Node, r.Len())
|
||||||
if len(cases) == 0 {
|
if len(cases) == 0 {
|
||||||
|
|
@ -1498,9 +1498,30 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cases = r.exprList()
|
cases = r.exprList()
|
||||||
|
|
||||||
|
tagType := types.Types[types.TBOOL]
|
||||||
|
if tag != nil {
|
||||||
|
tagType = tag.Type()
|
||||||
|
}
|
||||||
|
for i, cas := range cases {
|
||||||
|
if cas.Op() == ir.ONIL {
|
||||||
|
continue // never needs rtype
|
||||||
|
}
|
||||||
|
if tagType.IsInterface() != cas.Type().IsInterface() {
|
||||||
|
typ := tagType
|
||||||
|
if typ.IsInterface() {
|
||||||
|
typ = cas.Type()
|
||||||
|
}
|
||||||
|
for len(rtypes) < i {
|
||||||
|
rtypes = append(rtypes, nil)
|
||||||
|
}
|
||||||
|
rtypes = append(rtypes, reflectdata.TypePtr(typ))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clause := ir.NewCaseStmt(pos, cases, nil)
|
clause := ir.NewCaseStmt(pos, cases, nil)
|
||||||
|
clause.RTypes = rtypes
|
||||||
|
|
||||||
if ident != nil {
|
if ident != nil {
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,7 @@ func AppendElemRType(pos src.XPos, n *ir.CallExpr) ir.Node {
|
||||||
func CompareRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
|
func CompareRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
|
||||||
assertOp2(n, ir.OEQ, ir.ONE)
|
assertOp2(n, ir.OEQ, ir.ONE)
|
||||||
base.AssertfAt(n.X.Type().IsInterface() != n.Y.Type().IsInterface(), n.Pos(), "expect mixed interface and non-interface, have %L and %L", n.X, n.Y)
|
base.AssertfAt(n.X.Type().IsInterface() != n.Y.Type().IsInterface(), n.Pos(), "expect mixed interface and non-interface, have %L and %L", n.X, n.Y)
|
||||||
// TODO(mdempsky): Need to propagate RType from OSWITCH/OCASE
|
if haveRType(n, n.RType, "RType", true) {
|
||||||
// clauses to emitted OEQ nodes.
|
|
||||||
if haveRType(n, n.RType, "RType", false) {
|
|
||||||
return n.RType
|
return n.RType
|
||||||
}
|
}
|
||||||
typ := n.X.Type()
|
typ := n.X.Type()
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,12 @@ func walkSwitchExpr(sw *ir.SwitchStmt) {
|
||||||
defaultGoto = jmp
|
defaultGoto = jmp
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, n1 := range ncase.List {
|
for i, n1 := range ncase.List {
|
||||||
s.Add(ncase.Pos(), n1, jmp)
|
var rtype ir.Node
|
||||||
|
if i < len(ncase.RTypes) {
|
||||||
|
rtype = ncase.RTypes[i]
|
||||||
|
}
|
||||||
|
s.Add(ncase.Pos(), n1, rtype, jmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process body.
|
// Process body.
|
||||||
|
|
@ -124,11 +128,12 @@ type exprSwitch struct {
|
||||||
type exprClause struct {
|
type exprClause struct {
|
||||||
pos src.XPos
|
pos src.XPos
|
||||||
lo, hi ir.Node
|
lo, hi ir.Node
|
||||||
|
rtype ir.Node // *runtime._type for OEQ node
|
||||||
jmp ir.Node
|
jmp ir.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *exprSwitch) Add(pos src.XPos, expr, jmp ir.Node) {
|
func (s *exprSwitch) Add(pos src.XPos, expr, rtype, jmp ir.Node) {
|
||||||
c := exprClause{pos: pos, lo: expr, hi: expr, jmp: jmp}
|
c := exprClause{pos: pos, lo: expr, hi: expr, rtype: rtype, jmp: jmp}
|
||||||
if types.IsOrdered[s.exprname.Type().Kind()] && expr.Op() == ir.OLITERAL {
|
if types.IsOrdered[s.exprname.Type().Kind()] && expr.Op() == ir.OLITERAL {
|
||||||
s.clauses = append(s.clauses, c)
|
s.clauses = append(s.clauses, c)
|
||||||
return
|
return
|
||||||
|
|
@ -233,7 +238,7 @@ func (s *exprSwitch) flush() {
|
||||||
// Add length case to outer switch.
|
// Add length case to outer switch.
|
||||||
cas := ir.NewBasicLit(pos, constant.MakeInt64(runLen(run)))
|
cas := ir.NewBasicLit(pos, constant.MakeInt64(runLen(run)))
|
||||||
jmp := ir.NewBranchStmt(pos, ir.OGOTO, label)
|
jmp := ir.NewBranchStmt(pos, ir.OGOTO, label)
|
||||||
outer.Add(pos, cas, jmp)
|
outer.Add(pos, cas, nil, jmp)
|
||||||
}
|
}
|
||||||
s.done.Append(ir.NewLabelStmt(s.pos, outerLabel))
|
s.done.Append(ir.NewLabelStmt(s.pos, outerLabel))
|
||||||
outer.Emit(&s.done)
|
outer.Emit(&s.done)
|
||||||
|
|
@ -342,7 +347,9 @@ func (c *exprClause) test(exprname ir.Node) ir.Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ir.NewBinaryExpr(c.pos, ir.OEQ, exprname, c.lo)
|
n := ir.NewBinaryExpr(c.pos, ir.OEQ, exprname, c.lo)
|
||||||
|
n.RType = c.rtype
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func allCaseExprsAreSideEffectFree(sw *ir.SwitchStmt) bool {
|
func allCaseExprsAreSideEffectFree(sw *ir.SwitchStmt) bool {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue