diff options
author | Dan Scales <danscales@google.com> | 2021-09-06 17:46:50 -0700 |
---|---|---|
committer | Dan Scales <danscales@google.com> | 2021-09-20 18:17:05 +0000 |
commit | 6acac8b6856b2531f4ac7ee0eb37048d588d98c7 (patch) | |
tree | 46ef44756afbbe23628c36beda6f0903b7877ee6 | |
parent | 988f18d61d27f75f6a21cef0aa28b8d85982a85d (diff) | |
download | go-6acac8b6856b2531f4ac7ee0eb37048d588d98c7.tar.gz go-6acac8b6856b2531f4ac7ee0eb37048d588d98c7.zip |
cmd/compile: delay all transforms for generic funcs/methods
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>
-rw-r--r-- | src/cmd/compile/internal/ir/mini.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/helpers.go | 60 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/stmt.go | 71 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/transform.go | 2 |
4 files changed, 37 insertions, 98 deletions
diff --git a/src/cmd/compile/internal/ir/mini.go b/src/cmd/compile/internal/ir/mini.go index a7ff4ac9c7..eeb74081fb 100644 --- a/src/cmd/compile/internal/ir/mini.go +++ b/src/cmd/compile/internal/ir/mini.go @@ -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) diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index f06dd8b065..636b5d64cd 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -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() +} diff --git a/src/cmd/compile/internal/noder/stmt.go b/src/cmd/compile/internal/noder/stmt.go index aefd9fcdaa..805a4710c4 100644 --- a/src/cmd/compile/internal/noder/stmt.go +++ b/src/cmd/compile/internal/noder/stmt.go @@ -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) diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 3e5cfacb97..953036eb42 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -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) } |