diff options
-rw-r--r-- | src/cmd/compile/internal/noder/expr.go | 38 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/helpers.go | 11 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/stmt.go | 9 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/transform.go | 84 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/subr.go | 3 |
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 |