1
0
mirror of https://github.com/golang/go synced 2024-09-29 20:34:36 -06:00

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>
This commit is contained in:
Dan Scales 2021-09-06 17:46:50 -07:00
parent 988f18d61d
commit 6acac8b685
4 changed files with 37 additions and 98 deletions

View 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)

View 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()
}

View 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)

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