Skip to content

Commit

Permalink
cmd/compile/internal/ir: more idiomatic DynamicType{,AssertExpr}
Browse files Browse the repository at this point in the history
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 <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Keith Randall <[email protected]>
Reviewed-by: Dmitri Shuralyov <[email protected]>
Run-TryBot: Matthew Dempsky <[email protected]>
  • Loading branch information
mdempsky authored and gopherbot committed May 16, 2022
1 parent 3caf67d commit 2a6e138
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 63 deletions.
37 changes: 21 additions & 16 deletions src/cmd/compile/internal/ir/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ type TypeAssertExpr struct {

// 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 {
Expand All @@ -645,24 +645,29 @@ func (n *TypeAssertExpr) SetOp(op Op) {
}
}

// 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
Expand Down
18 changes: 12 additions & 6 deletions src/cmd/compile/internal/ir/node_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 19 additions & 5 deletions src/cmd/compile/internal/ir/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,29 @@ func TypeNode(t *types.Type) Ntype {
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
Expand Down
28 changes: 21 additions & 7 deletions src/cmd/compile/internal/noder/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -1636,7 +1636,9 @@ func (r *reader) expr() (res ir.Node) {
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()))

Expand Down Expand Up @@ -1806,12 +1808,23 @@ func (r *reader) exprType(nilOK bool) ir.Node {

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)
Expand All @@ -1823,11 +1836,12 @@ func (r *reader) exprType(nilOK bool) ir.Node {
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 {
Expand Down
10 changes: 6 additions & 4 deletions src/cmd/compile/internal/noder/stencil.go
Original file line number Diff line number Diff line change
Expand Up @@ -1333,11 +1333,12 @@ func (g *genInst) dictPass(info *instInfo) {
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
Expand All @@ -1348,13 +1349,14 @@ func (g *genInst) dictPass(info *instInfo) {
}
}
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:
Expand Down
17 changes: 10 additions & 7 deletions src/cmd/compile/internal/ssagen/ssa.go
Original file line number Diff line number Diff line change
Expand Up @@ -6222,22 +6222,25 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
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)
Expand Down
12 changes: 6 additions & 6 deletions src/cmd/compile/internal/typecheck/iexport.go
Original file line number Diff line number Diff line change
Expand Up @@ -1811,12 +1811,9 @@ func (w *exportWriter) expr(n ir.Node) {
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())

Expand Down Expand Up @@ -1931,7 +1928,10 @@ func (w *exportWriter) expr(n ir.Node) {
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:
Expand Down
3 changes: 3 additions & 0 deletions src/cmd/compile/internal/typecheck/iimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,9 @@ func (r *importReader) node() ir.Node {

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

Expand Down
5 changes: 3 additions & 2 deletions src/cmd/compile/internal/walk/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,15 +666,16 @@ func walkDotType(n *ir.TypeAssertExpr, init *ir.Nodes) ir.Node {
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
}

Expand Down
3 changes: 2 additions & 1 deletion src/cmd/compile/internal/walk/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,8 @@ func (o *orderState) stmt(n ir.Node) {
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)
Expand Down
13 changes: 4 additions & 9 deletions src/cmd/compile/internal/walk/switch.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,11 +469,8 @@ func walkSwitchType(sw *ir.SwitchStmt) {
}
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
Expand Down Expand Up @@ -572,10 +569,8 @@ func (s *typeSwitch) Add(pos src.XPos, n1 ir.Node, caseVar *ir.Name, jmp ir.Node
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}
Expand Down

0 comments on commit 2a6e138

Please sign in to comment.