aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/expr.go
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2021-01-19 13:54:33 -0800
committerDan Scales <danscales@google.com>2021-01-22 17:16:22 +0000
commit12cd9cf7e080806f86595d71078a30e654458ebe (patch)
treee07920049ee8de09c6796fdad9654b9e9b9e57ee /src/cmd/compile/internal/noder/expr.go
parentf8654579cdd637167bb38d38f0de76abc812d34c (diff)
downloadgo-12cd9cf7e080806f86595d71078a30e654458ebe.tar.xz
[dev.typeparams] cmd/compile: disambiguate OXDOT in noder using types2 Selection info
By using the types2 Selection information, we can create ODOT, ODOTPTR, OCALLPART, ODOTMETH, ODOTINTER, and OMETHEXPR nodes directly in noder, so we don't have to do that functionality in typecheck.go. Intermediate nodes are created as needed for embedded fields. Don't have to typecheck the results of g.selectorExpr(), because we set the types of all the needed nodes. There is one bug remaining in 'go test reflect' that will be fixed when dev.regabi is merged. Change-Id: I4599d43197783e318610deb2f208137f9344ab63 Reviewed-on: https://go-review.googlesource.com/c/go/+/285373 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Dan Scales <danscales@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/cmd/compile/internal/noder/expr.go')
-rw-r--r--src/cmd/compile/internal/noder/expr.go92
1 files changed, 89 insertions, 3 deletions
diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go
index 76db774229..b38e9cfb4e 100644
--- a/src/cmd/compile/internal/noder/expr.go
+++ b/src/cmd/compile/internal/noder/expr.go
@@ -11,6 +11,7 @@ import (
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/compile/internal/types2"
+ "cmd/internal/src"
)
func (g *irgen) expr(expr syntax.Expr) ir.Node {
@@ -106,9 +107,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
}
}
- // TODO(mdempsky/danscales): Use g.info.Selections[expr]
- // to resolve field/method selection. See CL 280633.
- return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, g.expr(expr.X), g.name(expr.Sel)))
+ return g.selectorExpr(pos, typ, expr)
case *syntax.SliceExpr:
return Slice(pos, g.expr(expr.X), g.expr(expr.Index[0]), g.expr(expr.Index[1]), g.expr(expr.Index[2]))
@@ -129,6 +128,93 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
}
}
+// selectorExpr resolves the choice of ODOT, ODOTPTR, OCALLPART (eventually
+// ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
+// than in typecheck.go.
+func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.SelectorExpr) ir.Node {
+ x := g.expr(expr.X)
+ selinfo := g.info.Selections[expr]
+ nindex := len(selinfo.Index())
+
+ // Iterate through the selections from types2. If nindex > 1, then we will
+ // create extra nodes to deal with embedded fields.
+ for i := 0; i < nindex; i++ {
+ var f *types.Field
+ var n *ir.SelectorExpr
+
+ op := ir.ODOT
+ index := selinfo.Index()[i]
+ xt := x.Type()
+ origxt := xt
+ if xt.IsPtr() && !xt.Elem().IsInterface() {
+ // Get to the base type, but remember that we skipped the ptr
+ xt = xt.Elem()
+ op = ir.ODOTPTR
+ }
+ types.CalcSize(xt)
+ // Everything up to the last selection is an embedded field
+ // access, and the last selection is determined by selinfo.Kind().
+ if i < nindex-1 || selinfo.Kind() == types2.FieldVal {
+ f = xt.Field(index)
+ sym := f.Sym
+ n = ir.NewSelectorExpr(pos, op, x, sym)
+ if i < nindex-1 {
+ n.SetImplicit(true)
+ typed(f.Type, n)
+ }
+ } else if selinfo.Kind() == types2.MethodExpr {
+ var ms *types.Fields
+ if xt.IsInterface() {
+ // TODO(danscales,mdempsky): interface method sets
+ // are not sorted the same between types and
+ // types2. In particular, this will likely fail if
+ // an interface contains unexported methods from
+ // two different packages (due to cross-package
+ // interface embedding).
+ ms = xt.Fields()
+ } else {
+ mt := types.ReceiverBaseType(xt)
+ ms = mt.Methods()
+ }
+ f = ms.Slice()[index]
+ n = ir.NewSelectorExpr(pos, ir.OMETHEXPR, x, f.Sym)
+ } else { // types.MethodVal
+ if xt.IsInterface() {
+ f = xt.Field(index)
+ } else {
+ f = xt.Methods().Slice()[index]
+ rcvr := f.Type.Recv().Type
+ if rcvr.IsPtr() && types.Identical(rcvr.Elem(), origxt) {
+ addr := typecheck.NodAddrAt(pos, x)
+ addr.SetImplicit(true)
+ typed(xt.PtrTo(), addr)
+ x = addr
+ } else if op == ir.ODOTPTR && !rcvr.IsPtr() {
+ star := ir.NewStarExpr(pos, x)
+ star.SetImplicit(true)
+ typed(xt, star)
+ x = star
+ }
+ }
+ // We will change OCALLPART to ODOTMETH or ODOTINTER in
+ // Call() if n is actually called.
+ n = ir.NewSelectorExpr(pos, ir.OCALLPART, x, f.Sym)
+ }
+ n.Selection = f
+ x = n
+ }
+
+ // We don't set type on x for the last index (i == nindex - 1), since that
+ // is the actual selection (ignoring embedded fields) and may be an
+ // OMETHEXPR or OCALLPART operation. In those cases, the type to set on the
+ // node will be different from the type derived from the field/method
+ // selection. Instead for the last index, we always set the type (at the
+ // end of the function) from g.typ(typ).
+ typed(g.typ(typ), x)
+ types.CalcSize(x.Type())
+ return x
+}
+
func (g *irgen) exprList(expr syntax.Expr) []ir.Node {
switch expr := expr.(type) {
case nil: