Rename DynamicType's "X" field to "RType".
Split DynamicTypeAssertExpr's "T" field into "RType" and "ITab", the
same as DynamicType, updating all uses accordingly.
Change-Id: I8cec8171349c93234a10ac50708f800dee6fb1d2
Reviewed-on: https://go-review.googlesource.com/c/go/+/405334
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
// Runtime type information provided by walkDotType for
// assertions from non-empty interface to concrete type.
- Itab *AddrExpr `mknode:"-"` // *runtime.itab for Type implementing X's type
+ ITab *AddrExpr `mknode:"-"` // *runtime.itab for Type implementing X's type
}
func NewTypeAssertExpr(pos src.XPos, x Node, typ *types.Type) *TypeAssertExpr {
}
}
-// A DynamicTypeAssertExpr asserts that X is of dynamic type T.
+// A DynamicTypeAssertExpr asserts that X is of dynamic type RType.
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}
+
+ // RType is an expression that yields a *runtime._type value
+ // representing the asserted type.
+ //
+ // BUG(mdempsky): If ITab is non-nil, RType may be nil.
+ RType Node
+
+ // ITab is an expression that yields a *runtime.itab value
+ // representing the asserted type within the assertee expression's
+ // original interface type.
+ //
+ // ITab is only used for assertions from non-empty interface type to
+ // a concrete (i.e., non-interface) type. For all other assertions,
+ // ITab is nil.
+ ITab Node
+}
+
+func NewDynamicTypeAssertExpr(pos src.XPos, op Op, x, rtype Node) *DynamicTypeAssertExpr {
+ n := &DynamicTypeAssertExpr{X: x, RType: rtype}
n.pos = pos
n.op = op
return n
if doNodes(n.init, do) {
return true
}
- if n.X != nil && do(n.X) {
+ if n.RType != nil && do(n.RType) {
return true
}
if n.ITab != nil && do(n.ITab) {
}
func (n *DynamicType) editChildren(edit func(Node) Node) {
editNodes(n.init, edit)
- if n.X != nil {
- n.X = edit(n.X).(Node)
+ if n.RType != nil {
+ n.RType = edit(n.RType).(Node)
}
if n.ITab != nil {
n.ITab = edit(n.ITab).(Node)
if n.X != nil && do(n.X) {
return true
}
- if n.T != nil && do(n.T) {
+ if n.RType != nil && do(n.RType) {
+ return true
+ }
+ if n.ITab != nil && do(n.ITab) {
return true
}
return false
if n.X != nil {
n.X = edit(n.X).(Node)
}
- if n.T != nil {
- n.T = edit(n.T).(Node)
+ if n.RType != nil {
+ n.RType = edit(n.RType).(Node)
+ }
+ if n.ITab != nil {
+ n.ITab = edit(n.ITab).(Node)
}
}
return newTypeNode(t)
}
-// A DynamicType represents the target type in a type switch.
+// A DynamicType represents a type expression whose exact type must be
+// computed dynamically.
type DynamicType struct {
miniExpr
- X Node // a *runtime._type for the targeted type
- ITab Node // for type switches from nonempty interfaces to non-interfaces, this is the itab for that pair.
+
+ // RType is an expression that yields a *runtime._type value
+ // representing the asserted type.
+ //
+ // BUG(mdempsky): If ITab is non-nil, RType may be nil.
+ RType Node
+
+ // ITab is an expression that yields a *runtime.itab value
+ // representing the asserted type within the assertee expression's
+ // original interface type.
+ //
+ // ITab is only used for assertions (including type switches) from
+ // non-empty interface type to a concrete (i.e., non-interface)
+ // type. For all other assertions, ITab is nil.
+ ITab Node
}
-func NewDynamicType(pos src.XPos, x Node) *DynamicType {
- n := &DynamicType{X: x}
+func NewDynamicType(pos src.XPos, rtype Node) *DynamicType {
+ n := &DynamicType{RType: rtype}
n.pos = pos
n.op = ODYNAMICTYPE
return n
typ := r.exprType(false)
if typ, ok := typ.(*ir.DynamicType); ok && typ.Op() == ir.ODYNAMICTYPE {
- return typed(typ.Type(), ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, x, typ.X))
+ assert := ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, x, typ.RType)
+ assert.ITab = typ.ITab
+ return typed(typ.Type(), assert)
}
return typecheck.Expr(ir.NewTypeAssertExpr(pos, x, typ.Type()))
pos := r.pos()
+ lsymPtr := func(lsym *obj.LSym) ir.Node {
+ return typecheck.Expr(typecheck.NodAddr(ir.NewLinksymExpr(pos, lsym, types.Types[types.TUINT8])))
+ }
+
var typ *types.Type
- var lsym *obj.LSym
+ var rtype, itab ir.Node
if r.Bool() {
- itab := r.dict.itabs[r.Len()]
- typ, lsym = itab.typ, itab.lsym
+ info := r.dict.itabs[r.Len()]
+ typ = info.typ
+
+ // TODO(mdempsky): Populate rtype unconditionally?
+ if typ.IsInterface() {
+ rtype = lsymPtr(info.lsym)
+ } else {
+ itab = lsymPtr(info.lsym)
+ }
} else {
info := r.typInfo()
typ = r.p.typIdx(info, r.dict, true)
return n
}
- lsym = reflectdata.TypeLinksym(typ)
+ rtype = lsymPtr(reflectdata.TypeLinksym(typ))
}
- ptr := typecheck.Expr(typecheck.NodAddr(ir.NewLinksymExpr(pos, lsym, types.Types[types.TUINT8])))
- return typed(typ, ir.NewDynamicType(pos, ptr))
+ dt := ir.NewDynamicType(pos, rtype)
+ dt.ITab = itab
+ return typed(typ, dt)
}
func (r *reader) op() ir.Op {
break
}
dt := m.(*ir.TypeAssertExpr)
- var rt ir.Node
+ var rtype, itab ir.Node
if dt.Type().IsInterface() || dt.X.Type().IsEmptyInterface() {
+ // TODO(mdempsky): Investigate executing this block unconditionally.
ix := findDictType(info, m.Type())
assert(ix >= 0)
- rt = getDictionaryType(info, info.dictParam, dt.Pos(), ix)
+ rtype = getDictionaryType(info, info.dictParam, dt.Pos(), ix)
} else {
// nonempty interface to noninterface. Need an itab.
ix := -1
}
}
assert(ix >= 0)
- rt = getDictionaryEntry(dt.Pos(), info.dictParam, ix, info.dictInfo.dictLen)
+ itab = getDictionaryEntry(dt.Pos(), info.dictParam, ix, info.dictInfo.dictLen)
}
op := ir.ODYNAMICDOTTYPE
if m.Op() == ir.ODOTTYPE2 {
op = ir.ODYNAMICDOTTYPE2
}
- m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rt)
+ m = ir.NewDynamicTypeAssertExpr(dt.Pos(), op, dt.X, rtype)
+ m.(*ir.DynamicTypeAssertExpr).ITab = itab
m.SetType(dt.Type())
m.SetTypecheck(1)
case ir.OCASE:
iface := s.expr(n.X) // input interface
target := s.reflectType(n.Type()) // target type
var targetItab *ssa.Value
- if n.Itab != nil {
- targetItab = s.expr(n.Itab)
+ if n.ITab != nil {
+ targetItab = s.expr(n.ITab)
}
return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, targetItab, commaok)
}
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
+ var target, targetItab *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
+ targetItab = s.expr(n.ITab)
+ // TODO(mdempsky): Investigate whether compiling n.RType could be
+ // better than loading itab.typ.
+ target = s.load(byteptr, s.newValue1I(ssa.OpOffPtr, byteptr, int64(types.PtrSize), targetItab)) // itab.typ
+ } else {
+ target = s.expr(n.RType)
}
- return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, itab, commaok)
+ return s.dottype1(n.Pos(), n.X.Type(), n.Type(), iface, target, targetItab, commaok)
}
// dottype1 implements a x.(T) operation. iface is the argument (x), dst is the type we're asserting to (T)
n := n.(*ir.DynamicType)
w.op(ir.ODYNAMICTYPE)
w.pos(n.Pos())
- w.expr(n.X)
- if n.ITab != nil {
- w.bool(true)
+ w.expr(n.RType)
+ if w.bool(n.ITab != nil) {
w.expr(n.ITab)
- } else {
- w.bool(false)
}
w.typ(n.Type())
w.op(n.Op())
w.pos(n.Pos())
w.expr(n.X)
- w.expr(n.T)
+ w.expr(n.RType)
+ if w.bool(n.ITab != nil) {
+ w.expr(n.ITab)
+ }
w.typ(n.Type())
case ir.OINDEX, ir.OINDEXMAP:
case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
n := ir.NewDynamicTypeAssertExpr(r.pos(), op, r.expr(), r.expr())
+ if r.bool() {
+ n.ITab = r.expr()
+ }
n.SetType(r.typ())
return n
n.X = walkExpr(n.X, init)
// Set up interface type addresses for back end.
if !n.Type().IsInterface() && !n.X.Type().IsEmptyInterface() {
- n.Itab = reflectdata.ITabAddr(n.Type(), n.X.Type())
+ n.ITab = reflectdata.ITabAddr(n.Type(), n.X.Type())
}
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)
+ n.RType = walkExpr(n.RType, init)
+ n.ITab = walkExpr(n.ITab, init)
return n
}
case ir.ODYNAMICDOTTYPE2:
r := r.(*ir.DynamicTypeAssertExpr)
r.X = o.expr(r.X, nil)
- r.T = o.expr(r.T, nil)
+ r.RType = o.expr(r.RType, nil)
+ r.ITab = o.expr(r.ITab, nil)
case ir.ORECV:
r := r.(*ir.UnaryExpr)
r.X = o.expr(r.X, nil)
}
if len(ncase.List) == 1 && ncase.List[0].Op() == ir.ODYNAMICTYPE {
dt := ncase.List[0].(*ir.DynamicType)
- x := ir.NewDynamicTypeAssertExpr(ncase.Pos(), ir.ODYNAMICDOTTYPE, val, dt.X)
- if dt.ITab != nil {
- // TODO: make ITab a separate field in DynamicTypeAssertExpr?
- x.T = dt.ITab
- }
+ x := ir.NewDynamicTypeAssertExpr(ncase.Pos(), ir.ODYNAMICDOTTYPE, val, dt.RType)
+ x.ITab = dt.ITab
x.SetType(caseVar.Type())
x.SetTypecheck(1)
val = x
case ir.ODYNAMICTYPE:
// Dynamic type assertion (generic)
dt := n1.(*ir.DynamicType)
- dot := ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, s.facename, dt.X)
- if dt.ITab != nil {
- dot.T = dt.ITab
- }
+ dot := ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, s.facename, dt.RType)
+ dot.ITab = dt.ITab
dot.SetType(typ)
dot.SetTypecheck(1)
as.Rhs = []ir.Node{dot}