aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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