]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: implement generic .(T) operations
authorKeith Randall <khr@golang.org>
Tue, 27 Jul 2021 00:41:02 +0000 (17:41 -0700)
committerKeith Randall <khr@golang.org>
Thu, 29 Jul 2021 17:15:21 +0000 (17:15 +0000)
Introduce new dynamic dottype operations which take a dynamic
instead of static type to convert to.

Change-Id: I5824a1fea056fe811b1226ce059e1e8da1baa335
Reviewed-on: https://go-review.googlesource.com/c/go/+/337609
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
src/cmd/compile/internal/escape/expr.go
src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/ir/node.go
src/cmd/compile/internal/ir/node_gen.go
src/cmd/compile/internal/ir/op_string.go
src/cmd/compile/internal/noder/stencil.go
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/walk/expr.go
src/cmd/compile/internal/walk/order.go
test/typeparam/dottype.go
test/typeparam/dottype.out

index b7423e114ade7c5aac28baf86b4d24a101b6a9b6..4a6304d47a618528a153614bcd2e95dd3dd9b5c4 100644 (file)
@@ -74,6 +74,10 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
        case ir.ODOTTYPE, ir.ODOTTYPE2:
                n := n.(*ir.TypeAssertExpr)
                e.expr(k.dotType(n.Type(), n, "dot"), n.X)
+       case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
+               n := n.(*ir.DynamicTypeAssertExpr)
+               e.expr(k.dotType(n.Type(), n, "dot"), n.X)
+               // n.T doesn't need to be tracked; it always points to read-only storage.
        case ir.OINDEX:
                n := n.(*ir.IndexExpr)
                if n.X.Type().IsArray() {
index 86323e6b8f86e0d92ce1d21701da39cf44ace939..9c5fbbc9aa8343420e56ca2f0128a017ccfe532a 100644 (file)
@@ -677,6 +677,29 @@ func (n *TypeAssertExpr) SetOp(op Op) {
        }
 }
 
+// A DynamicTypeAssertExpr asserts that X is of dynamic type T.
+type DynamicTypeAssertExpr struct {
+       miniExpr
+       X Node
+       // N = not an interface
+       // E = empty interface
+       // I = nonempty interface
+       // For E->N, T is a *runtime.type for N
+       // For I->N, T is a *runtime.itab for N+I
+       // For E->I, T is a *runtime.type for I
+       // For I->I, ditto
+       // For I->E, T is a *runtime.type for interface{} (unnecessary, but just to fill in the slot)
+       // For E->E, ditto
+       T Node
+}
+
+func NewDynamicTypeAssertExpr(pos src.XPos, op Op, x, t Node) *DynamicTypeAssertExpr {
+       n := &DynamicTypeAssertExpr{X: x, T: t}
+       n.pos = pos
+       n.op = op
+       return n
+}
+
 // A UnaryExpr is a unary expression Op X,
 // or Op(X) for a builtin function that does not end up being a call.
 type UnaryExpr struct {
index 0fbc867c1d93206a830825668b4e477123e331e8..e5f0c38f8617bddbbc8f97c11801482a686caa68 100644 (file)
@@ -319,6 +319,10 @@ const (
        OINLMARK       // start of an inlined body, with file/line of caller. Xoffset is an index into the inline tree.
        OLINKSYMOFFSET // offset within a name
 
+       // opcodes for generics
+       ODYNAMICDOTTYPE
+       ODYNAMICDOTTYPE2
+
        // arch-specific opcodes
        OTAILCALL    // tail call to another function
        OGETG        // runtime.getg() (read g pointer)
index 9a4858d0371f5275dec8bfdc6377698b7ad110c4..56db6bb9cf74a2d5e3439281d630eae0ba500466 100644 (file)
@@ -463,6 +463,34 @@ func (n *Decl) editChildren(edit func(Node) Node) {
        }
 }
 
+func (n *DynamicTypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
+func (n *DynamicTypeAssertExpr) copy() Node {
+       c := *n
+       c.init = copyNodes(c.init)
+       return &c
+}
+func (n *DynamicTypeAssertExpr) doChildren(do func(Node) bool) bool {
+       if doNodes(n.init, do) {
+               return true
+       }
+       if n.X != nil && do(n.X) {
+               return true
+       }
+       if n.T != nil && do(n.T) {
+               return true
+       }
+       return false
+}
+func (n *DynamicTypeAssertExpr) editChildren(edit func(Node) Node) {
+       editNodes(n.init, edit)
+       if n.X != nil {
+               n.X = edit(n.X).(Node)
+       }
+       if n.T != nil {
+               n.T = edit(n.T).(Node)
+       }
+}
+
 func (n *ForStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
 func (n *ForStmt) copy() Node {
        c := *n
index 0235d5eab39a6c870a7bab425ca1eb6b134cb797..7b08ee287a7f01104c55a58f76f400437ff62095 100644 (file)
@@ -162,16 +162,18 @@ func _() {
        _ = x[ORESULT-151]
        _ = x[OINLMARK-152]
        _ = x[OLINKSYMOFFSET-153]
-       _ = x[OTAILCALL-154]
-       _ = x[OGETG-155]
-       _ = x[OGETCALLERPC-156]
-       _ = x[OGETCALLERSP-157]
-       _ = x[OEND-158]
+       _ = x[ODYNAMICDOTTYPE-154]
+       _ = x[ODYNAMICDOTTYPE2-155]
+       _ = x[OTAILCALL-156]
+       _ = x[OGETG-157]
+       _ = x[OGETCALLERPC-158]
+       _ = x[OGETCALLERSP-159]
+       _ = x[OEND-160]
 }
 
-const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETTAILCALLGETGGETCALLERPCGETCALLERSPEND"
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTCHANTMAPTSTRUCTTINTERTFUNCTARRAYTSLICEINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETDYNAMICDOTTYPEDYNAMICDOTTYPE2TAILCALLGETGGETCALLERPCGETCALLERSPEND"
 
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 286, 293, 297, 300, 307, 315, 322, 328, 331, 337, 344, 352, 356, 363, 371, 373, 375, 377, 379, 381, 383, 388, 393, 401, 404, 413, 416, 420, 428, 435, 444, 457, 460, 463, 466, 469, 472, 475, 481, 484, 487, 493, 497, 500, 504, 509, 514, 520, 525, 529, 534, 542, 550, 556, 565, 576, 583, 592, 596, 603, 611, 615, 619, 623, 630, 637, 645, 651, 660, 671, 679, 688, 693, 698, 702, 710, 715, 719, 722, 730, 734, 736, 741, 743, 748, 754, 760, 766, 772, 780, 785, 789, 796, 802, 807, 813, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 877, 883, 890, 903, 911, 915, 926, 937, 940}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 37, 39, 42, 48, 52, 58, 64, 73, 85, 94, 103, 115, 124, 136, 138, 141, 151, 158, 165, 172, 176, 180, 188, 196, 205, 208, 213, 220, 227, 233, 242, 250, 258, 264, 268, 277, 286, 293, 297, 300, 307, 315, 322, 328, 331, 337, 344, 352, 356, 363, 371, 373, 375, 377, 379, 381, 383, 388, 393, 401, 404, 413, 416, 420, 428, 435, 444, 457, 460, 463, 466, 469, 472, 475, 481, 484, 487, 493, 497, 500, 504, 509, 514, 520, 525, 529, 534, 542, 550, 556, 565, 576, 583, 592, 596, 603, 611, 615, 619, 623, 630, 637, 645, 651, 660, 671, 679, 688, 693, 698, 702, 710, 715, 719, 722, 730, 734, 736, 741, 743, 748, 754, 760, 766, 772, 780, 785, 789, 796, 802, 807, 813, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 877, 883, 890, 903, 917, 932, 940, 944, 955, 966, 969}
 
 func (i Op) String() string {
        if i >= Op(len(_Op_index)-1) {
index 02a380e63f95c47d864076ca3bdd1304cac950b3..70a2c7b97fce5bd88f877c48786fc7a80ff75543 100644 (file)
@@ -1039,6 +1039,7 @@ func (subst *subster) checkDictionary(name *ir.Name, targs []*types.Type) (code
        d.SetTypecheck(1)
        d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(len(targs))).PtrTo(), d)
        d.SetTypecheck(1)
+       types.CheckSize(d.Type().Elem())
 
        // Check that each type entry in the dictionary is correct.
        for i, t := range targs {
@@ -1079,6 +1080,7 @@ func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node {
        d.SetTypecheck(1)
        d = ir.NewConvExpr(pos, ir.OCONVNOP, types.NewArray(types.Types[types.TUINTPTR], int64(size)).PtrTo(), d)
        d.SetTypecheck(1)
+       types.CheckSize(d.Type().Elem())
 
        // Load entry i out of the dictionary.
        deref := ir.NewStarExpr(pos, d)
@@ -1367,7 +1369,31 @@ func (subst *subster) node(n ir.Node) ir.Node {
                                m = subst.convertUsingDictionary(m.Pos(), m.(*ir.ConvExpr).X, x, m.Type(), x.X.Type())
                        }
                case ir.ODOTTYPE, ir.ODOTTYPE2:
-                       m.SetType(subst.unshapifyTyp(m.Type()))
+                       dt := m.(*ir.TypeAssertExpr)
+                       var rt ir.Node
+                       if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() {
+                               ix := subst.findDictType(x.Type())
+                               assert(ix >= 0)
+                               rt = subst.getDictionaryType(dt.Pos(), ix)
+                       } else {
+                               // nonempty interface to noninterface. Need an itab.
+                               ix := -1
+                               for i, ic := range subst.info.gfInfo.itabConvs {
+                                       if ic == x {
+                                               ix = subst.info.startItabConv + i
+                                               break
+                                       }
+                               }
+                               assert(ix >= 0)
+                               rt = getDictionaryEntry(dt.Pos(), subst.info.dictParam, ix, subst.info.dictLen)
+                       }
+                       op := ir.ODYNAMICDOTTYPE
+                       if x.Op() == ir.ODOTTYPE2 {
+                               op = ir.ODYNAMICDOTTYPE2
+                       }
+                       m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rt)
+                       m.SetType(dt.Type())
+                       m.SetTypecheck(1)
 
                case ir.OMETHEXPR:
                        se := m.(*ir.SelectorExpr)
@@ -1696,7 +1722,8 @@ func (g *irgen) finalizeSyms() {
                // Emit an entry for each itab
                for _, n := range info.itabConvs {
                        var srctype, dsttype *types.Type
-                       if n.Op() == ir.OXDOT {
+                       switch n.Op() {
+                       case ir.OXDOT:
                                se := n.(*ir.SelectorExpr)
                                srctype = subst.Typ(se.X.Type())
                                dsttype = subst.Typ(se.X.Type().Bound())
@@ -1712,10 +1739,14 @@ func (g *irgen) finalizeSyms() {
                                        }
                                }
                                assert(found)
-                       } else {
-                               assert(n.Op() == ir.OCONVIFACE)
+                       case ir.ODOTTYPE, ir.ODOTTYPE2:
+                               srctype = subst.Typ(n.(*ir.TypeAssertExpr).Type())
+                               dsttype = subst.Typ(n.(*ir.TypeAssertExpr).X.Type())
+                       case ir.OCONVIFACE:
                                srctype = subst.Typ(n.(*ir.ConvExpr).X.Type())
                                dsttype = subst.Typ(n.Type())
+                       default:
+                               base.Fatalf("itab entry with unknown op %s", n.Op())
                        }
                        itabLsym := reflectdata.ITabLsym(srctype, dsttype)
                        d.off = objw.SymPtr(lsym, d.off, itabLsym, 0)
@@ -1859,6 +1890,10 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo {
                        infoPrint("  Itab for interface conv: %v\n", n)
                        info.itabConvs = append(info.itabConvs, n)
                }
+               if (n.Op() == ir.ODOTTYPE || n.Op() == ir.ODOTTYPE2) && !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() {
+                       infoPrint("  Itab for dot type: %v\n", n)
+                       info.itabConvs = append(info.itabConvs, n)
+               }
                if n.Op() == ir.OCLOSURE {
                        // Visit the closure body and add all relevant entries to the
                        // dictionary of the outer function (closure will just use
index d2e0d57b28c3ad898e0a9fe8c8d9a11f14b15651..7e2f6a7471c06fc2a6a8a12564ce662115a15778 100644 (file)
@@ -1423,7 +1423,12 @@ func (s *state) stmt(n ir.Node) {
 
        case ir.OAS2DOTTYPE:
                n := n.(*ir.AssignListStmt)
-               res, resok := s.dottype(n.Rhs[0].(*ir.TypeAssertExpr), true)
+               var res, resok *ssa.Value
+               if n.Rhs[0].Op() == ir.ODOTTYPE2 {
+                       res, resok = s.dottype(n.Rhs[0].(*ir.TypeAssertExpr), true)
+               } else {
+                       res, resok = s.dynamicDottype(n.Rhs[0].(*ir.DynamicTypeAssertExpr), true)
+               }
                deref := false
                if !TypeOK(n.Rhs[0].Type()) {
                        if res.Op != ssa.OpLoad {
@@ -2680,6 +2685,11 @@ func (s *state) expr(n ir.Node) *ssa.Value {
                res, _ := s.dottype(n, false)
                return res
 
+       case ir.ODYNAMICDOTTYPE:
+               n := n.(*ir.DynamicTypeAssertExpr)
+               res, _ := s.dynamicDottype(n, false)
+               return res
+
        // binary ops
        case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT:
                n := n.(*ir.BinaryExpr)
@@ -5147,9 +5157,13 @@ func (s *state) addr(n ir.Node) *ssa.Value {
        case ir.OCALLFUNC, ir.OCALLINTER:
                n := n.(*ir.CallExpr)
                return s.callAddr(n, callNormal)
-       case ir.ODOTTYPE:
-               n := n.(*ir.TypeAssertExpr)
-               v, _ := s.dottype(n, false)
+       case ir.ODOTTYPE, ir.ODYNAMICDOTTYPE:
+               var v *ssa.Value
+               if n.Op() == ir.ODOTTYPE {
+                       v, _ = s.dottype(n.(*ir.TypeAssertExpr), false)
+               } else {
+                       v, _ = s.dynamicDottype(n.(*ir.DynamicTypeAssertExpr), false)
+               }
                if v.Op != ssa.OpLoad {
                        s.Fatalf("dottype of non-load")
                }
@@ -6043,14 +6057,38 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *
 func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
        iface := s.expr(n.X)              // input interface
        target := s.reflectType(n.Type()) // target type
-       byteptr := s.f.Config.Types.BytePtr
+       var targetItab *ssa.Value
+       if n.Itab != nil {
+               targetItab = s.expr(n.Itab)
+       }
+       return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, targetItab, commaok)
+}
 
-       if n.Type().IsInterface() {
-               if n.Type().IsEmptyInterface() {
+func (s *state) dynamicDottype(n *ir.DynamicTypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
+       iface := s.expr(n.X)
+       target := s.expr(n.T)
+       var itab *ssa.Value
+       if !n.X.Type().IsEmptyInterface() && !n.Type().IsInterface() {
+               byteptr := s.f.Config.Types.BytePtr
+               itab = target
+               target = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, int64(types.PtrSize), itab)) // itab.typ
+       }
+       return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, itab, commaok)
+}
+
+// dottype1 implements a x.(T) operation. iface is the argument (x), dst is the type we're asserting to (T)
+// and src is the type we're asserting from.
+// target is the *runtime._type of dst.
+// If src is a nonempty interface and dst is not an interface, targetItab is an itab representing (dst, src). Otherwise it is nil.
+// commaok is true if the caller wants a boolean success value. Otherwise, the generated code panics if the conversion fails.
+func (s *state) dottype1(pos src.XPos, src, dst *types.Type, iface, target, targetItab *ssa.Value, commaok bool) (res, resok *ssa.Value) {
+       byteptr := s.f.Config.Types.BytePtr
+       if dst.IsInterface() {
+               if dst.IsEmptyInterface() {
                        // Converting to an empty interface.
                        // Input could be an empty or nonempty interface.
                        if base.Debug.TypeAssert > 0 {
-                               base.WarnfAt(n.Pos(), "type assertion inlined")
+                               base.WarnfAt(pos, "type assertion inlined")
                        }
 
                        // Get itab/type field from input.
@@ -6058,7 +6096,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
                        // Conversion succeeds iff that field is not nil.
                        cond := s.newValue2(ssa.OpNeqPtr, types.Types[types.TBOOL], itab, s.constNil(byteptr))
 
-                       if n.X.Type().IsEmptyInterface() && commaok {
+                       if src.IsEmptyInterface() && commaok {
                                // Converting empty interface to empty interface with ,ok is just a nil check.
                                return iface, cond
                        }
@@ -6080,7 +6118,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
 
                                // On success, return (perhaps modified) input interface.
                                s.startBlock(bOk)
-                               if n.X.Type().IsEmptyInterface() {
+                               if src.IsEmptyInterface() {
                                        res = iface // Use input interface unchanged.
                                        return
                                }
@@ -6088,7 +6126,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
                                off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(types.PtrSize), itab)
                                typ := s.load(byteptr, off)
                                idata := s.newValue1(ssa.OpIData, byteptr, iface)
-                               res = s.newValue2(ssa.OpIMake, n.Type(), typ, idata)
+                               res = s.newValue2(ssa.OpIMake, dst, typ, idata)
                                return
                        }
 
@@ -6110,62 +6148,62 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
                        bFail.AddEdgeTo(bEnd)
                        s.startBlock(bEnd)
                        idata := s.newValue1(ssa.OpIData, byteptr, iface)
-                       res = s.newValue2(ssa.OpIMake, n.Type(), s.variable(typVar, byteptr), idata)
+                       res = s.newValue2(ssa.OpIMake, dst, s.variable(typVar, byteptr), idata)
                        resok = cond
                        delete(s.vars, typVar)
                        return
                }
                // converting to a nonempty interface needs a runtime call.
                if base.Debug.TypeAssert > 0 {
-                       base.WarnfAt(n.Pos(), "type assertion not inlined")
+                       base.WarnfAt(pos, "type assertion not inlined")
                }
                if !commaok {
                        fn := ir.Syms.AssertI2I
-                       if n.X.Type().IsEmptyInterface() {
+                       if src.IsEmptyInterface() {
                                fn = ir.Syms.AssertE2I
                        }
                        data := s.newValue1(ssa.OpIData, types.Types[types.TUNSAFEPTR], iface)
                        tab := s.newValue1(ssa.OpITab, byteptr, iface)
                        tab = s.rtcall(fn, true, []*types.Type{byteptr}, target, tab)[0]
-                       return s.newValue2(ssa.OpIMake, n.Type(), tab, data), nil
+                       return s.newValue2(ssa.OpIMake, dst, tab, data), nil
                }
                fn := ir.Syms.AssertI2I2
-               if n.X.Type().IsEmptyInterface() {
+               if src.IsEmptyInterface() {
                        fn = ir.Syms.AssertE2I2
                }
-               res = s.rtcall(fn, true, []*types.Type{n.Type()}, target, iface)[0]
-               resok = s.newValue2(ssa.OpNeqInter, types.Types[types.TBOOL], res, s.constInterface(n.Type()))
+               res = s.rtcall(fn, true, []*types.Type{dst}, target, iface)[0]
+               resok = s.newValue2(ssa.OpNeqInter, types.Types[types.TBOOL], res, s.constInterface(dst))
                return
        }
 
        if base.Debug.TypeAssert > 0 {
-               base.WarnfAt(n.Pos(), "type assertion inlined")
+               base.WarnfAt(pos, "type assertion inlined")
        }
 
        // Converting to a concrete type.
-       direct := types.IsDirectIface(n.Type())
+       direct := types.IsDirectIface(dst)
        itab := s.newValue1(ssa.OpITab, byteptr, iface) // type word of interface
        if base.Debug.TypeAssert > 0 {
-               base.WarnfAt(n.Pos(), "type assertion inlined")
+               base.WarnfAt(pos, "type assertion inlined")
        }
-       var targetITab *ssa.Value
-       if n.X.Type().IsEmptyInterface() {
+       var wantedFirstWord *ssa.Value
+       if src.IsEmptyInterface() {
                // Looking for pointer to target type.
-               targetITab = target
+               wantedFirstWord = target
        } else {
                // Looking for pointer to itab for target type and source interface.
-               targetITab = s.expr(n.Itab)
+               wantedFirstWord = targetItab
        }
 
        var tmp ir.Node     // temporary for use with large types
        var addr *ssa.Value // address of tmp
-       if commaok && !TypeOK(n.Type()) {
+       if commaok && !TypeOK(dst) {
                // unSSAable type, use temporary.
                // TODO: get rid of some of these temporaries.
-               tmp, addr = s.temp(n.Pos(), n.Type())
+               tmp, addr = s.temp(pos, dst)
        }
 
-       cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, targetITab)
+       cond := s.newValue2(ssa.OpEqPtr, types.Types[types.TBOOL], itab, wantedFirstWord)
        b := s.endBlock()
        b.Kind = ssa.BlockIf
        b.SetControl(cond)
@@ -6179,8 +6217,8 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
        if !commaok {
                // on failure, panic by calling panicdottype
                s.startBlock(bFail)
-               taddr := s.reflectType(n.X.Type())
-               if n.X.Type().IsEmptyInterface() {
+               taddr := s.reflectType(src)
+               if src.IsEmptyInterface() {
                        s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
                } else {
                        s.rtcall(ir.Syms.PanicdottypeI, false, nil, itab, target, taddr)
@@ -6189,10 +6227,10 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
                // on success, return data from interface
                s.startBlock(bOk)
                if direct {
-                       return s.newValue1(ssa.OpIData, n.Type(), iface), nil
+                       return s.newValue1(ssa.OpIData, dst, iface), nil
                }
-               p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type()), iface)
-               return s.load(n.Type(), p), nil
+               p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
+               return s.load(dst, p), nil
        }
 
        // commaok is the more complicated case because we have
@@ -6206,14 +6244,14 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
        s.startBlock(bOk)
        if tmp == nil {
                if direct {
-                       s.vars[valVar] = s.newValue1(ssa.OpIData, n.Type(), iface)
+                       s.vars[valVar] = s.newValue1(ssa.OpIData, dst, iface)
                } else {
-                       p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type()), iface)
-                       s.vars[valVar] = s.load(n.Type(), p)
+                       p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
+                       s.vars[valVar] = s.load(dst, p)
                }
        } else {
-               p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type()), iface)
-               s.move(n.Type(), addr, p)
+               p := s.newValue1(ssa.OpIData, types.NewPtr(dst), iface)
+               s.move(dst, addr, p)
        }
        s.vars[okVar] = s.constBool(true)
        s.endBlock()
@@ -6222,9 +6260,9 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
        // type assertion failed
        s.startBlock(bFail)
        if tmp == nil {
-               s.vars[valVar] = s.zeroVal(n.Type())
+               s.vars[valVar] = s.zeroVal(dst)
        } else {
-               s.zero(n.Type(), addr)
+               s.zero(dst, addr)
        }
        s.vars[okVar] = s.constBool(false)
        s.endBlock()
@@ -6233,10 +6271,10 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
        // merge point
        s.startBlock(bEnd)
        if tmp == nil {
-               res = s.variable(valVar, n.Type())
+               res = s.variable(valVar, dst)
                delete(s.vars, valVar)
        } else {
-               res = s.load(n.Type(), addr)
+               res = s.load(dst, addr)
                s.vars[memVar] = s.newValue1A(ssa.OpVarKill, types.TypeMem, tmp.(*ir.Name), s.mem())
        }
        resok = s.variable(okVar, types.Types[types.TBOOL])
index f0d37198d37278e677d7bd848d156f9b8fc3da5d..f95b6f4639fa5f6930562cf2f7231b3b61e2178e 100644 (file)
@@ -136,6 +136,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
                n := n.(*ir.TypeAssertExpr)
                return walkDotType(n, init)
 
+       case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
+               n := n.(*ir.DynamicTypeAssertExpr)
+               return walkDynamicDotType(n, init)
+
        case ir.OLEN, ir.OCAP:
                n := n.(*ir.UnaryExpr)
                return walkLenCap(n, init)
@@ -669,6 +673,13 @@ func walkDotType(n *ir.TypeAssertExpr, init *ir.Nodes) ir.Node {
        return n
 }
 
+// walkDynamicdotType walks an ODYNAMICDOTTYPE or ODYNAMICDOTTYPE2 node.
+func walkDynamicDotType(n *ir.DynamicTypeAssertExpr, init *ir.Nodes) ir.Node {
+       n.X = walkExpr(n.X, init)
+       n.T = walkExpr(n.T, init)
+       return n
+}
+
 // walkIndex walks an OINDEX node.
 func walkIndex(n *ir.IndexExpr, init *ir.Nodes) ir.Node {
        n.X = walkExpr(n.X, init)
index fe6ae3fda00982b5b6fec166b87712e0e1ec502e..c5fd0c1e1dad4de1be1112b2087fecdae69f812a 100644 (file)
@@ -686,6 +686,10 @@ func (o *orderState) stmt(n ir.Node) {
                case ir.ODOTTYPE2:
                        r := r.(*ir.TypeAssertExpr)
                        r.X = o.expr(r.X, nil)
+               case ir.ODYNAMICDOTTYPE2:
+                       r := r.(*ir.DynamicTypeAssertExpr)
+                       r.X = o.expr(r.X, nil)
+                       r.T = o.expr(r.T, nil)
                case ir.ORECV:
                        r := r.(*ir.UnaryExpr)
                        r.X = o.expr(r.X, nil)
index 89a9b021119035ff2af8cbc8fa279bac4c38724c..c9c900c0962ecc74ab94d0e6d2b39b05d6f44c74 100644 (file)
@@ -69,6 +69,11 @@ func main() {
        println(h[int](struct{ a, b int }{3, 5}).a)
 
        println(k[int](mybar(3)).bar())
+
+       type large struct {a,b,c,d,e,f int}
+       println(f[large](large{}).a)
+       l2, ok := f2[large](large{})
+       println(l2.a, ok)
 }
 func shouldpanic(x func()) {
        defer func() {
index 058c923a5ce208c7207fa0c8ab31f8f67c7d2e45..8e6a3c25526093a1175bc60dad33b267fa5ad0ee 100644 (file)
@@ -6,3 +6,5 @@
 0 false
 3
 3
+0
+0 true