// Enforce ordering by starting a new set of reorderable conditions.
conds = append(conds, []ir.Node{})
}
- p := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym)
- q := ir.NewSelectorExpr(base.Pos, ir.OXDOT, nq, f.Sym)
switch {
case f.Type.IsString():
+ p := typecheck.DotField(base.Pos, typecheck.Expr(np), i)
+ q := typecheck.DotField(base.Pos, typecheck.Expr(nq), i)
eqlen, eqmem := EqString(p, q)
and(eqlen)
and(eqmem)
default:
- and(ir.NewBinaryExpr(base.Pos, ir.OEQ, p, q))
+ and(eqfield(np, nq, i))
}
if typeCanPanic {
// Also enforce ordering after something that can panic.
cost, size, next := eqStructFieldCost(t, i)
if cost <= 4 {
// Cost of 4 or less: use plain field equality.
- s := fields[i:next]
- for _, f := range s {
- and(eqfield(np, nq, ir.OEQ, f.Sym))
+ for j := i; j < next; j++ {
+ and(eqfield(np, nq, j))
}
} else {
// Higher cost: use memequal.
- cc := eqmem(np, nq, f.Sym, size)
+ cc := eqmem(np, nq, i, size)
and(cc)
}
i = next
// eqfield returns the node
//
// p.field == q.field
-func eqfield(p ir.Node, q ir.Node, op ir.Op, field *types.Sym) ir.Node {
- nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)
- ny := ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)
- ne := ir.NewBinaryExpr(base.Pos, op, nx, ny)
- return ne
+func eqfield(p, q ir.Node, field int) ir.Node {
+ nx := typecheck.DotField(base.Pos, typecheck.Expr(p), field)
+ ny := typecheck.DotField(base.Pos, typecheck.Expr(q), field)
+ return typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.OEQ, nx, ny))
}
// eqmem returns the node
//
// memequal(&p.field, &q.field, size)
-func eqmem(p ir.Node, q ir.Node, field *types.Sym, size int64) ir.Node {
- nx := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)))
- ny := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)))
+func eqmem(p, q ir.Node, field int, size int64) ir.Node {
+ nx := typecheck.Expr(typecheck.NodAddr(typecheck.DotField(base.Pos, p, field)))
+ ny := typecheck.Expr(typecheck.NodAddr(typecheck.DotField(base.Pos, q, field)))
fn, needsize := eqmemfunc(size, nx.Type().Elem())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
dt.SetType(typ)
- x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
+ x := typecheck.XDotMethod(sel.Pos(), dt, sel.Sel, true)
switch x.Op() {
case ir.ODOTMETH:
- x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
}
call.X = x
case ir.ODOTINTER:
// Promoted method from embedded interface-typed field (#42279).
- x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
}
assertAsList := ir.NewAssignListStmt(pos, ir.OAS2, []ir.Node{tmpnode, tmpok}, []ir.Node{typecheck.Expr(assert)})
init.Append(typecheck.Stmt(assertAsList))
- concreteCallee := typecheck.Callee(ir.NewSelectorExpr(pos, ir.OXDOT, tmpnode, method))
+ concreteCallee := typecheck.XDotMethod(pos, tmpnode, method, true)
// Copy slice so edits in one location don't affect another.
argvars = append([]ir.Node(nil), argvars...)
concreteCall := typecheck.Call(pos, concreteCallee, argvars, call.IsDDD)
import (
"go/constant"
- "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
"cmd/compile/internal/typecheck"
return n
}
-func DotField(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
- op, typ := ir.ODOT, x.Type()
- if typ.IsPtr() {
- op, typ = ir.ODOTPTR, typ.Elem()
- }
- if !typ.IsStruct() {
- base.FatalfAt(pos, "DotField of non-struct: %L", x)
- }
-
- // TODO(mdempsky): This is the backend's responsibility.
- types.CalcSize(typ)
-
- field := typ.Field(index)
- return dot(pos, field.Type, op, x, field)
-}
-
-func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Field) *ir.SelectorExpr {
- n := ir.NewSelectorExpr(pos, op, x, selection.Sym)
- n.Selection = selection
- typed(typ, n)
- return n
-}
-
// Statements
var one = constant.MakeInt64(1)
pos := r.pos()
_, sym := r.selector()
- return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)).(*ir.SelectorExpr)
+ return typecheck.XDotField(pos, x, sym)
case exprMethodVal:
recv := r.expr()
recv = typecheck.Expr(ir.NewConvExpr(recv.Pos(), ir.OCONVNOP, typ, recv))
}
- n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, recv, wrapperFn.Sel)).(*ir.SelectorExpr)
+ n := typecheck.XDotMethod(pos, recv, wrapperFn.Sel, false)
// As a consistency check here, we make sure "n" selected the
// same method (represented by a types.Field) that wrapperFn
x := r.expr()
pos := r.pos()
for i, n := 0, r.Len(); i < n; i++ {
- x = Implicit(DotField(pos, x, r.Len()))
+ x = Implicit(typecheck.DotField(pos, x, r.Len()))
}
if r.Bool() { // needs deref
x = Implicit(Deref(pos, x.Type().Elem(), x))
// There are also corner cases where semantically it's perhaps
// significant; e.g., fixedbugs/issue15975.go, #38634, #52025.
- fun = typecheck.Callee(ir.NewSelectorExpr(method.Pos(), ir.OXDOT, recv, method.Sel))
+ fun = typecheck.XDotMethod(method.Pos(), recv, method.Sel, true)
} else {
if recv.Type().IsInterface() {
// N.B., this happens currently for typeparam/issue51521.go
{
arg := args[0]
for _, ix := range implicits {
- arg = Implicit(DotField(pos, arg, ix))
+ arg = Implicit(typecheck.DotField(pos, arg, ix))
}
if deref {
arg = Implicit(Deref(pos, arg.Type().Elem(), arg))
fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
- dot := ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym)
+ dot := typecheck.XDotMethod(pos, recv, method.Sym, true)
call := typecheck.Call(pos, dot, args, method.Type.IsVariadic()).(*ir.CallExpr)
if method.Type.NumResults() == 0 {
if !compare.IsRegularMemory(f.Type) {
hashel := hashfor(f.Type)
call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
- nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := typecheck.NodAddr(nx)
+ na := typecheck.NodAddr(typecheck.DotField(base.Pos, np, i))
call.Args.Append(na)
call.Args.Append(nh)
fn.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
// h = hashel(&p.first, size, h)
hashel := hashmem(f.Type)
call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
- nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := typecheck.NodAddr(nx)
+ na := typecheck.NodAddr(typecheck.DotField(base.Pos, np, i))
call.Args.Append(na)
call.Args.Append(nh)
call.Args.Append(ir.NewInt(base.Pos, size))
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
+ "cmd/internal/src"
)
// tcAddr typechecks an OADDR node.
return n
}
+// DotField returns a field selector expression that selects the
+// index'th field of the given expression, which must be of struct or
+// pointer-to-struct type.
+func DotField(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
+ op, typ := ir.ODOT, x.Type()
+ if typ.IsPtr() {
+ op, typ = ir.ODOTPTR, typ.Elem()
+ }
+ if !typ.IsStruct() {
+ base.FatalfAt(pos, "DotField of non-struct: %L", x)
+ }
+
+ // TODO(mdempsky): This is the backend's responsibility.
+ types.CalcSize(typ)
+
+ field := typ.Field(index)
+ return dot(pos, field.Type, op, x, field)
+}
+
+func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Field) *ir.SelectorExpr {
+ n := ir.NewSelectorExpr(pos, op, x, selection.Sym)
+ n.Selection = selection
+ n.SetType(typ)
+ n.SetTypecheck(1)
+ return n
+}
+
+// XDotMethod returns an expression representing the field selection
+// x.sym. If any implicit field selection are necessary, those are
+// inserted too.
+func XDotField(pos src.XPos, x ir.Node, sym *types.Sym) *ir.SelectorExpr {
+ n := Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)).(*ir.SelectorExpr)
+ // TODO(mdempsky): Assert n is ODOT/ODOTPTR.
+ return n
+}
+
+// XDotMethod returns an expression representing the method value
+// x.sym (i.e., x is a value, not a type). If any implicit field
+// selection are necessary, those are inserted too.
+//
+// If callee is true, the result is an ODOTMETH/ODOTINTER, otherwise
+// an OMETHVALUE.
+func XDotMethod(pos src.XPos, x ir.Node, sym *types.Sym, callee bool) *ir.SelectorExpr {
+ n := ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)
+ if callee {
+ n = Callee(n).(*ir.SelectorExpr)
+ // TODO(mdempsky): Assert n is ODOTMETH/ODOTINTER.
+ } else {
+ n = Expr(n).(*ir.SelectorExpr)
+ // TODO(mdempsky): Assert n is OMETHVALUE.
+ }
+ return n
+}
+
// tcDot typechecks an OXDOT or ODOT node.
func tcDot(n *ir.SelectorExpr, top int) ir.Node {
if n.Op() == ir.OXDOT {
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n, nil))
continue
}
- n = typecheck.Expr(ir.NewSelectorExpr(n.Pos(), ir.OXDOT, n, n.Type().Field(0).Sym))
+ n = typecheck.DotField(n.Pos(), n, 0)
case n.Type().IsArray():
n = typecheck.Expr(ir.NewIndexExpr(n.Pos(), n, ir.NewInt(base.Pos, 0)))
default: