aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2021-09-12 12:21:48 -0700
committerDan Scales <danscales@google.com>2021-09-15 22:53:42 +0000
commitcfa233d76bcff00f46f5e5acdb17cb819a309d2b (patch)
tree240718d5b535df978ddd13eb95197c1e67d9549b
parent59a9a035ffa34c26a287d124180f6eca7c912311 (diff)
downloadgo-cfa233d76bcff00f46f5e5acdb17cb819a309d2b.tar.gz
go-cfa233d76bcff00f46f5e5acdb17cb819a309d2b.zip
cmd/compile: remove unneeded early transforms, with dictionary change
Now that we are computing the dictionary format on the instantiated functions, we can remove the early transformation code that was needed to create the implicit CONVIFACE nodes in the generic function. Change-Id: I1695484e7d59bccbfb757994f3e40e84288759a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/349614 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Dan Scales <danscales@google.com> Reviewed-by: Keith Randall <khr@golang.org>
-rw-r--r--src/cmd/compile/internal/noder/expr.go38
-rw-r--r--src/cmd/compile/internal/noder/helpers.go11
-rw-r--r--src/cmd/compile/internal/noder/stmt.go9
-rw-r--r--src/cmd/compile/internal/noder/transform.go84
-rw-r--r--src/cmd/compile/internal/typecheck/subr.go3
5 files changed, 26 insertions, 119 deletions
diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go
index 045f028e1a..3e1960f7a4 100644
--- a/src/cmd/compile/internal/noder/expr.go
+++ b/src/cmd/compile/internal/noder/expr.go
@@ -250,44 +250,6 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
// only be fully transformed once it has an instantiated type.
n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value))
typed(g.typ(typ), n)
-
- // Fill in n.Selection for a generic method reference or a bound
- // interface method, even though we won't use it directly, since it
- // is useful for analysis. Specifically do not fill in for fields or
- // other interfaces methods (method call on an interface value), so
- // n.Selection being non-nil means a method reference for a generic
- // type or a method reference due to a bound.
- obj2 := g.info.Selections[expr].Obj()
- sig := types2.AsSignature(obj2.Type())
- if sig == nil || sig.Recv() == nil {
- return n
- }
- index := g.info.Selections[expr].Index()
- last := index[len(index)-1]
- // recvType is the receiver of the method being called. Because of the
- // way methods are imported, g.obj(obj2) doesn't work across
- // packages, so we have to lookup the method via the receiver type.
- recvType := deref2(sig.Recv().Type())
- if types2.AsInterface(recvType.Underlying()) != nil {
- fieldType := n.X.Type()
- for _, ix := range index[:len(index)-1] {
- fieldType = deref(fieldType).Field(ix).Type
- }
- if fieldType.Kind() == types.TTYPEPARAM {
- n.Selection = fieldType.Bound().AllMethods().Index(last)
- //fmt.Printf(">>>>> %v: Bound call %v\n", base.FmtPos(pos), n.Sel)
- } else {
- assert(fieldType.Kind() == types.TINTER)
- //fmt.Printf(">>>>> %v: Interface call %v\n", base.FmtPos(pos), n.Sel)
- }
- return n
- }
-
- recvObj := types2.AsNamed(recvType).Obj()
- recv := g.pkg(recvObj.Pkg()).Lookup(recvObj.Name()).Def
- n.Selection = recv.Type().Methods().Index(last)
- //fmt.Printf(">>>>> %v: Method call %v\n", base.FmtPos(pos), n.Sel)
-
return n
}
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index 9487e76336..f06dd8b065 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -189,17 +189,6 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
// A function instantiation (even if fully concrete) shouldn't be
// transformed yet, because we need to add the dictionary during the
// transformation.
- //
- // However, if we have a function type (even though it is
- // parameterized), then we can add in any needed CONVIFACE nodes via
- // typecheckaste(). We need to call transformArgs() to deal first
- // with the f(g(()) case where g returns multiple return values. We
- // can't do anything if fun is a type param (which is probably
- // described by a structural constraint)
- if fun.Type().Kind() == types.TFUNC {
- transformArgs(n)
- typecheckaste(ir.OCALL, fun, n.IsDDD, fun.Type().Params(), n.Args, true)
- }
return typed(typ, n)
}
diff --git a/src/cmd/compile/internal/noder/stmt.go b/src/cmd/compile/internal/noder/stmt.go
index 146761c23f..1c366296fc 100644
--- a/src/cmd/compile/internal/noder/stmt.go
+++ b/src/cmd/compile/internal/noder/stmt.go
@@ -101,8 +101,6 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
n.Def = initDefn(n, names)
if delay {
- earlyTransformAssign(n, lhs, rhs)
- n.X, n.Y = lhs[0], rhs[0]
n.SetTypecheck(3)
return n
}
@@ -117,7 +115,6 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
n.Def = initDefn(n, names)
if delay {
- earlyTransformAssign(n, lhs, rhs)
n.SetTypecheck(3)
return n
}
@@ -135,12 +132,6 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
if e.Type().HasTParam() {
// Delay transforming the return statement if any of the
// return values have a type param.
- if !ir.HasNamedResults(ir.CurFunc) {
- transformArgs(n)
- // But add CONVIFACE nodes where needed if
- // any of the return values have interface type.
- typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, true)
- }
n.SetTypecheck(3)
return n
}
diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go
index 8173bfc747..91374054b6 100644
--- a/src/cmd/compile/internal/noder/transform.go
+++ b/src/cmd/compile/internal/noder/transform.go
@@ -157,7 +157,7 @@ func transformCall(n *ir.CallExpr) {
n.SetOp(ir.OCALLFUNC)
}
- typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, false)
+ typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args)
if l.Op() == ir.ODOTMETH && len(deref(n.X.Type().Recv().Type).RParams()) == 0 {
typecheck.FixMethodCall(n)
}
@@ -365,59 +365,6 @@ assignOK:
}
}
-// Version of transformAssign that can run on generic code that adds CONVIFACE calls
-// as needed (and rewrites multi-value calls).
-func earlyTransformAssign(stmt ir.Node, lhs, rhs []ir.Node) {
- cr := len(rhs)
- if len(rhs) == 1 {
- if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
- cr = rtyp.NumFields()
- }
- }
-
- // x,y,z = f()
- _, isCallExpr := rhs[0].(*ir.CallExpr)
- if isCallExpr && cr > len(rhs) {
- stmt := stmt.(*ir.AssignListStmt)
- stmt.SetOp(ir.OAS2FUNC)
- r := rhs[0].(*ir.CallExpr)
- rtyp := r.Type()
-
- mismatched := false
- failed := false
- for i := range lhs {
- result := rtyp.Field(i).Type
-
- if lhs[i].Type() == nil || result == nil {
- failed = true
- } else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
- mismatched = true
- }
- }
- if mismatched && !failed {
- typecheck.RewriteMultiValueCall(stmt, r)
- }
- return
- }
-
- // x, ok = y
- if len(lhs) != len(rhs) {
- assert(len(lhs) == 2 && len(rhs) == 1)
- // TODO(danscales): deal with case where x or ok is an interface
- // type. We want to add CONVIFACE now, but that is tricky, because
- // the rhs may be AS2MAPR, AS2RECV, etc. which has two result values,
- // and that is not rewritten until the order phase (o.stmt, as2ok).
- return
- }
-
- // Check for interface conversion on each assignment
- for i, r := range rhs {
- if lhs[i].Type() != nil && lhs[i].Type().IsInterface() {
- rhs[i] = assignconvfn(r, lhs[i].Type())
- }
- }
-}
-
// Corresponds to typecheck.typecheckargs. Really just deals with multi-value calls.
func transformArgs(n ir.InitNode) {
var list []ir.Node
@@ -457,11 +404,11 @@ func assignconvfn(n ir.Node, t *types.Type) ir.Node {
return n
}
- if types.Identical(n.Type(), t) {
+ if types.IdenticalStrict(n.Type(), t) {
return n
}
- op, why := typecheck.Assignop(n.Type(), t)
+ op, why := Assignop(n.Type(), t)
if op == ir.OXXX {
base.Fatalf("found illegal assignment %+v -> %+v; %s", n.Type(), t, why)
}
@@ -472,11 +419,26 @@ func assignconvfn(n ir.Node, t *types.Type) ir.Node {
return r
}
+func Assignop(src, dst *types.Type) (ir.Op, string) {
+ if src == dst {
+ return ir.OCONVNOP, ""
+ }
+ if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
+ return ir.OXXX, ""
+ }
+
+ // 1. src type is identical to dst.
+ if types.IdenticalStrict(src, dst) {
+ return ir.OCONVNOP, ""
+ }
+ return typecheck.Assignop1(src, dst)
+}
+
// Corresponds to typecheck.typecheckaste, but we add an extra flag convifaceOnly
// only. If convifaceOnly is true, we only do interface conversion. We use this to do
// early insertion of CONVIFACE nodes during noder2, when the function or args may
// have typeparams.
-func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes, convifaceOnly bool) {
+func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes) {
var t *types.Type
var i int
@@ -495,7 +457,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i
if isddd {
n = nl[i]
ir.SetPos(n)
- if n.Type() != nil && (!convifaceOnly || t.IsInterface()) {
+ if n.Type() != nil {
nl[i] = assignconvfn(n, t)
}
return
@@ -505,7 +467,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i
for ; i < len(nl); i++ {
n = nl[i]
ir.SetPos(n)
- if n.Type() != nil && (!convifaceOnly || t.IsInterface()) {
+ if n.Type() != nil {
nl[i] = assignconvfn(n, t.Elem())
}
}
@@ -514,7 +476,7 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i
n = nl[i]
ir.SetPos(n)
- if n.Type() != nil && (!convifaceOnly || t.IsInterface()) {
+ if n.Type() != nil {
nl[i] = assignconvfn(n, t)
}
i++
@@ -536,7 +498,7 @@ func transformReturn(rs *ir.ReturnStmt) {
return
}
- typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl, false)
+ typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl)
}
// transformSelect transforms a select node, creating an assignment list as needed
diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go
index 64d30eeb5a..d4af4e172e 100644
--- a/src/cmd/compile/internal/typecheck/subr.go
+++ b/src/cmd/compile/internal/typecheck/subr.go
@@ -352,7 +352,10 @@ func Assignop(src, dst *types.Type) (ir.Op, string) {
if types.Identical(src, dst) {
return ir.OCONVNOP, ""
}
+ return Assignop1(src, dst)
+}
+func Assignop1(src, dst *types.Type) (ir.Op, string) {
// 2. src and dst have identical underlying types and
// a. either src or dst is not a named type, or
// b. both are empty interface types, or