]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: delay all transforms for generic funcs/methods
authorDan Scales <danscales@google.com>
Tue, 7 Sep 2021 00:46:50 +0000 (17:46 -0700)
committerDan Scales <danscales@google.com>
Mon, 20 Sep 2021 18:17:05 +0000 (18:17 +0000)
This change cleans up the code, by just delaying all transforms on
generic function methods/functions until stenciling time. That way, we
don't have extra code to decide whether to delay, or an extra value for
the typecheck flag. We are already doing all possible transforms at
stencil time anyway, so no changes to the stenciling code.

transform.go includes a change for one case where we check for shape
rather than tparam, now that we only apply transforms to stenciled
functions, not generic functions. This change is to allow CONVIFACE node
to be correctly inserted (needed for dictionaries), even with this
strange code that doesn't add the CONVIFACE node if the concrete type is
NOT huge...

Change-Id: I5f1e71fab11b53385902074915b3ad85f8e753fa
Reviewed-on: https://go-review.googlesource.com/c/go/+/350736
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>

src/cmd/compile/internal/ir/mini.go
src/cmd/compile/internal/noder/helpers.go
src/cmd/compile/internal/noder/stmt.go
src/cmd/compile/internal/noder/transform.go

index a7ff4ac9c77a1a122b8fd558dd69f6b83e4879cb..eeb74081fb8bc51724e761f3579dc660416490bb 100644 (file)
@@ -62,7 +62,7 @@ const (
 
 func (n *miniNode) Typecheck() uint8 { return n.bits.get2(miniTypecheckShift) }
 func (n *miniNode) SetTypecheck(x uint8) {
-       if x > 3 {
+       if x > 2 {
                panic(fmt.Sprintf("cannot SetTypecheck %d", x))
        }
        n.bits.set2(miniTypecheckShift, x)
index f06dd8b0653b56e9693f087b4834c4cd25a4edaa..636b5d64cd7dbdc7f1e588f3963de5973556dfe6 100644 (file)
@@ -95,16 +95,12 @@ func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) ir.Node {
                return typed(x.Type(), ir.NewLogicalExpr(pos, op, x, y))
        case ir.OADD:
                n := ir.NewBinaryExpr(pos, op, x, y)
-               if x.Type().HasTParam() || y.Type().HasTParam() {
-                       // Delay transformAdd() if either arg has a type param,
-                       // since it needs to know the exact types to decide whether
-                       // to transform OADD to OADDSTR.
-                       n.SetType(typ)
-                       n.SetTypecheck(3)
-                       return n
-               }
                typed(typ, n)
-               return transformAdd(n)
+               r := ir.Node(n)
+               if !delayTransform() {
+                       r = transformAdd(n)
+               }
+               return r
        default:
                return typed(x.Type(), ir.NewBinaryExpr(pos, op, x, y))
        }
@@ -201,22 +197,10 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
 
 func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) ir.Node {
        n := ir.NewBinaryExpr(pos, op, x, y)
-       if x.Type().HasTParam() || y.Type().HasTParam() {
-               xIsInt := x.Type().IsInterface()
-               yIsInt := y.Type().IsInterface()
-               if !(xIsInt && !yIsInt || !xIsInt && yIsInt) {
-                       // If either arg is a type param, then we can still do the
-                       // transformCompare() if we know that one arg is an interface
-                       // and the other is not. Otherwise, we delay
-                       // transformCompare(), since it needs to know the exact types
-                       // to decide on any needed conversions.
-                       n.SetType(typ)
-                       n.SetTypecheck(3)
-                       return n
-               }
-       }
        typed(typ, n)
-       transformCompare(n)
+       if !delayTransform() {
+               transformCompare(n)
+       }
        return n
 }
 
@@ -288,15 +272,11 @@ func method(typ *types.Type, index int) *types.Field {
 
 func Index(pos src.XPos, typ *types.Type, x, index ir.Node) ir.Node {
        n := ir.NewIndexExpr(pos, x, index)
-       if x.Type().HasTParam() {
-               // transformIndex needs to know exact type
-               n.SetType(typ)
-               n.SetTypecheck(3)
-               return n
-       }
        typed(typ, n)
-       // transformIndex will modify n.Type() for OINDEXMAP.
-       transformIndex(n)
+       if !delayTransform() {
+               // transformIndex will modify n.Type() for OINDEXMAP.
+               transformIndex(n)
+       }
        return n
 }
 
@@ -306,14 +286,10 @@ func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) ir.Node {
                op = ir.OSLICE3
        }
        n := ir.NewSliceExpr(pos, op, x, low, high, max)
-       if x.Type().HasTParam() {
-               // transformSlice needs to know if x.Type() is a string or an array or a slice.
-               n.SetType(typ)
-               n.SetTypecheck(3)
-               return n
-       }
        typed(typ, n)
-       transformSlice(n)
+       if !delayTransform() {
+               transformSlice(n)
+       }
        return n
 }
 
@@ -355,3 +331,9 @@ func IncDec(pos src.XPos, op ir.Op, x ir.Node) *ir.AssignOpStmt {
        }
        return ir.NewAssignOpStmt(pos, op, x, bl)
 }
+
+// delayTransform returns true if we should delay all transforms, because we are
+// creating the nodes for a generic function/method.
+func delayTransform() bool {
+       return ir.CurFunc != nil && ir.CurFunc.Type().HasTParam()
+}
index aefd9fcdaae9cd68fd3959a1f8dac963694cfd5a..805a4710c42eeeea9369146d2996dc6eeeabbf9f 100644 (file)
@@ -40,13 +40,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                return wrapname(g.pos(stmt.X), g.expr(stmt.X))
        case *syntax.SendStmt:
                n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
-               if n.Chan.Type().HasTParam() || n.Value.Type().HasTParam() {
-                       // Delay transforming the send if the channel or value
-                       // have a type param.
-                       n.SetTypecheck(3)
-                       return n
+               if !delayTransform() {
+                       transformSend(n)
                }
-               transformSend(n)
                n.SetTypecheck(1)
                return n
        case *syntax.DeclStmt:
@@ -66,11 +62,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                                lhs := g.expr(stmt.Lhs)
                                n = ir.NewAssignOpStmt(g.pos(stmt), op, lhs, rhs)
                        }
-                       if n.X.Typecheck() == 3 {
-                               n.SetTypecheck(3)
-                               return n
+                       if !delayTransform() {
+                               transformAsOp(n)
                        }
-                       transformAsOp(n)
                        n.SetTypecheck(1)
                        return n
                }
@@ -79,46 +73,24 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                rhs := g.exprList(stmt.Rhs)
                names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def)
 
-               // We must delay transforming the assign statement if any of the
-               // lhs or rhs nodes are also delayed, since transformAssign needs
-               // to know the types of the left and right sides in various cases.
-               delay := false
-               for _, e := range lhs {
-                       if e.Type().HasTParam() || e.Typecheck() == 3 {
-                               delay = true
-                               break
-                       }
-               }
-               for _, e := range rhs {
-                       if e.Type().HasTParam() || e.Typecheck() == 3 {
-                               delay = true
-                               break
-                       }
-               }
-
                if len(lhs) == 1 && len(rhs) == 1 {
                        n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0])
                        n.Def = initDefn(n, names)
 
-                       if delay {
-                               n.SetTypecheck(3)
-                               return n
+                       if !delayTransform() {
+                               lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
+                               transformAssign(n, lhs, rhs)
+                               n.X, n.Y = lhs[0], rhs[0]
                        }
-
-                       lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
-                       transformAssign(n, lhs, rhs)
-                       n.X, n.Y = lhs[0], rhs[0]
                        n.SetTypecheck(1)
                        return n
                }
 
                n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
                n.Def = initDefn(n, names)
-               if delay {
-                       n.SetTypecheck(3)
-                       return n
+               if !delayTransform() {
+                       transformAssign(n, n.Lhs, n.Rhs)
                }
-               transformAssign(n, n.Lhs, n.Rhs)
                n.SetTypecheck(1)
                return n
 
@@ -128,15 +100,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
                return ir.NewGoDeferStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), callOps[:]), g.expr(stmt.Call))
        case *syntax.ReturnStmt:
                n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
-               for _, e := range n.Results {
-                       if e.Type().HasTParam() {
-                               // Delay transforming the return statement if any of the
-                               // return values have a type param.
-                               n.SetTypecheck(3)
-                               return n
-                       }
+               if !delayTransform() {
+                       transformReturn(n)
                }
-               transformReturn(n)
                n.SetTypecheck(1)
                return n
        case *syntax.IfStmt:
@@ -146,19 +112,10 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
        case *syntax.SelectStmt:
                n := g.selectStmt(stmt)
 
-               delay := false
-               for _, ncase := range n.(*ir.SelectStmt).Cases {
-                       if ncase.Comm != nil && ncase.Comm.Typecheck() == 3 {
-                               delay = true
-                               break
-                       }
-               }
-               if delay {
-                       n.SetTypecheck(3)
-               } else {
+               if !delayTransform() {
                        transformSelect(n.(*ir.SelectStmt))
-                       n.SetTypecheck(1)
                }
+               n.SetTypecheck(1)
                return n
        case *syntax.SwitchStmt:
                return g.switchStmt(stmt)
index 3e5cfacb97725892538b5d50e668009e09e611aa..953036eb4238a244022f748f5785c80dbe9c5c55 100644 (file)
@@ -195,7 +195,7 @@ func transformCompare(n *ir.BinaryExpr) {
                        aop, _ := typecheck.Assignop(lt, rt)
                        if aop != ir.OXXX {
                                types.CalcSize(lt)
-                               if lt.HasTParam() || rt.IsInterface() == lt.IsInterface() || lt.Size() >= 1<<16 {
+                               if lt.HasShape() || rt.IsInterface() == lt.IsInterface() || lt.Size() >= 1<<16 {
                                        l = ir.NewConvExpr(base.Pos, aop, rt, l)
                                        l.SetTypecheck(1)
                                }