]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.unified] cmd/compile: plumb rtype through OSWITCH/OCASE clauses
authorMatthew Dempsky <mdempsky@google.com>
Tue, 21 Jun 2022 09:30:21 +0000 (02:30 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 23 Jun 2022 21:53:09 +0000 (21:53 +0000)
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>

src/cmd/compile/internal/ir/stmt.go
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/reflectdata/helpers.go
src/cmd/compile/internal/walk/switch.go

index 6a82df58f855b9da2119064b26d377a8cf1813e6..10f8b5e3942be3c02cf81f474b3a0a410f8db549 100644 (file)
@@ -170,6 +170,17 @@ type CaseClause struct {
        miniStmt
        Var  *Name // declared variable for this case in type switch
        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
 }
 
index 32276e75537ff288ff8a1a1bf6f189f5043f14f6..aa2cccf86ba0c186bdbb5b1d93ef625319a9f8f4 100644 (file)
@@ -1487,7 +1487,7 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node {
                r.openScope()
 
                pos := r.pos()
-               var cases []ir.Node
+               var cases, rtypes []ir.Node
                if iface != nil {
                        cases = make([]ir.Node, r.Len())
                        if len(cases) == 0 {
@@ -1498,9 +1498,30 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node {
                        }
                } else {
                        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.RTypes = rtypes
 
                if ident != nil {
                        pos := r.pos()
index 66f1864474525f95415ec7f1f5015a3bfeb84627..5edb495a8160d1bc2712fe30ba75a966bcd60df6 100644 (file)
@@ -84,9 +84,7 @@ func AppendElemRType(pos src.XPos, n *ir.CallExpr) ir.Node {
 func CompareRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
        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)
-       // TODO(mdempsky): Need to propagate RType from OSWITCH/OCASE
-       // clauses to emitted OEQ nodes.
-       if haveRType(n, n.RType, "RType", false) {
+       if haveRType(n, n.RType, "RType", true) {
                return n.RType
        }
        typ := n.X.Type()
index 6cac8f29377a1a348327cd2d9ae201bafeed5913..257903c0b3ceff7d0fbc0ff1aa6f3a90bbd0410a 100644 (file)
@@ -85,8 +85,12 @@ func walkSwitchExpr(sw *ir.SwitchStmt) {
                        defaultGoto = jmp
                }
 
-               for _, n1 := range ncase.List {
-                       s.Add(ncase.Pos(), n1, jmp)
+               for i, n1 := range ncase.List {
+                       var rtype ir.Node
+                       if i < len(ncase.RTypes) {
+                               rtype = ncase.RTypes[i]
+                       }
+                       s.Add(ncase.Pos(), n1, rtype, jmp)
                }
 
                // Process body.
@@ -124,11 +128,12 @@ type exprSwitch struct {
 type exprClause struct {
        pos    src.XPos
        lo, hi ir.Node
+       rtype  ir.Node // *runtime._type for OEQ node
        jmp    ir.Node
 }
 
-func (s *exprSwitch) Add(pos src.XPos, expr, jmp ir.Node) {
-       c := exprClause{pos: pos, lo: expr, hi: expr, jmp: jmp}
+func (s *exprSwitch) Add(pos src.XPos, expr, rtype, jmp ir.Node) {
+       c := exprClause{pos: pos, lo: expr, hi: expr, rtype: rtype, jmp: jmp}
        if types.IsOrdered[s.exprname.Type().Kind()] && expr.Op() == ir.OLITERAL {
                s.clauses = append(s.clauses, c)
                return
@@ -233,7 +238,7 @@ func (s *exprSwitch) flush() {
                        // Add length case to outer switch.
                        cas := ir.NewBasicLit(pos, constant.MakeInt64(runLen(run)))
                        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))
                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 {