1
0
mirror of https://github.com/golang/go synced 2024-11-17 13:54:46 -07:00

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>
This commit is contained in:
Dan Scales 2021-09-12 12:21:48 -07:00
parent 59a9a035ff
commit cfa233d76b
5 changed files with 26 additions and 119 deletions

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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

View File

@ -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