mirror of
https://github.com/golang/go
synced 2024-11-17 18:54:42 -07: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:
parent
988f18d61d
commit
6acac8b685
@ -62,7 +62,7 @@ const (
|
|||||||
|
|
||||||
func (n *miniNode) Typecheck() uint8 { return n.bits.get2(miniTypecheckShift) }
|
func (n *miniNode) Typecheck() uint8 { return n.bits.get2(miniTypecheckShift) }
|
||||||
func (n *miniNode) SetTypecheck(x uint8) {
|
func (n *miniNode) SetTypecheck(x uint8) {
|
||||||
if x > 3 {
|
if x > 2 {
|
||||||
panic(fmt.Sprintf("cannot SetTypecheck %d", x))
|
panic(fmt.Sprintf("cannot SetTypecheck %d", x))
|
||||||
}
|
}
|
||||||
n.bits.set2(miniTypecheckShift, x)
|
n.bits.set2(miniTypecheckShift, x)
|
||||||
|
@ -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))
|
return typed(x.Type(), ir.NewLogicalExpr(pos, op, x, y))
|
||||||
case ir.OADD:
|
case ir.OADD:
|
||||||
n := ir.NewBinaryExpr(pos, op, x, y)
|
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)
|
typed(typ, n)
|
||||||
return transformAdd(n)
|
r := ir.Node(n)
|
||||||
|
if !delayTransform() {
|
||||||
|
r = transformAdd(n)
|
||||||
|
}
|
||||||
|
return r
|
||||||
default:
|
default:
|
||||||
return typed(x.Type(), ir.NewBinaryExpr(pos, op, x, y))
|
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 {
|
func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) ir.Node {
|
||||||
n := ir.NewBinaryExpr(pos, op, x, y)
|
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)
|
typed(typ, n)
|
||||||
|
if !delayTransform() {
|
||||||
transformCompare(n)
|
transformCompare(n)
|
||||||
|
}
|
||||||
return 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 {
|
func Index(pos src.XPos, typ *types.Type, x, index ir.Node) ir.Node {
|
||||||
n := ir.NewIndexExpr(pos, x, index)
|
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)
|
typed(typ, n)
|
||||||
|
if !delayTransform() {
|
||||||
// transformIndex will modify n.Type() for OINDEXMAP.
|
// transformIndex will modify n.Type() for OINDEXMAP.
|
||||||
transformIndex(n)
|
transformIndex(n)
|
||||||
|
}
|
||||||
return 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
|
op = ir.OSLICE3
|
||||||
}
|
}
|
||||||
n := ir.NewSliceExpr(pos, op, x, low, high, max)
|
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)
|
typed(typ, n)
|
||||||
|
if !delayTransform() {
|
||||||
transformSlice(n)
|
transformSlice(n)
|
||||||
|
}
|
||||||
return 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)
|
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()
|
||||||
|
}
|
||||||
|
@ -40,13 +40,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
|
|||||||
return wrapname(g.pos(stmt.X), g.expr(stmt.X))
|
return wrapname(g.pos(stmt.X), g.expr(stmt.X))
|
||||||
case *syntax.SendStmt:
|
case *syntax.SendStmt:
|
||||||
n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
|
n := ir.NewSendStmt(g.pos(stmt), g.expr(stmt.Chan), g.expr(stmt.Value))
|
||||||
if n.Chan.Type().HasTParam() || n.Value.Type().HasTParam() {
|
if !delayTransform() {
|
||||||
// Delay transforming the send if the channel or value
|
|
||||||
// have a type param.
|
|
||||||
n.SetTypecheck(3)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
transformSend(n)
|
transformSend(n)
|
||||||
|
}
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
return n
|
return n
|
||||||
case *syntax.DeclStmt:
|
case *syntax.DeclStmt:
|
||||||
@ -66,11 +62,9 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
|
|||||||
lhs := g.expr(stmt.Lhs)
|
lhs := g.expr(stmt.Lhs)
|
||||||
n = ir.NewAssignOpStmt(g.pos(stmt), op, lhs, rhs)
|
n = ir.NewAssignOpStmt(g.pos(stmt), op, lhs, rhs)
|
||||||
}
|
}
|
||||||
if n.X.Typecheck() == 3 {
|
if !delayTransform() {
|
||||||
n.SetTypecheck(3)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
transformAsOp(n)
|
transformAsOp(n)
|
||||||
|
}
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
@ -79,46 +73,24 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
|
|||||||
rhs := g.exprList(stmt.Rhs)
|
rhs := g.exprList(stmt.Rhs)
|
||||||
names, lhs := g.assignList(stmt.Lhs, stmt.Op == syntax.Def)
|
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 {
|
if len(lhs) == 1 && len(rhs) == 1 {
|
||||||
n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0])
|
n := ir.NewAssignStmt(g.pos(stmt), lhs[0], rhs[0])
|
||||||
n.Def = initDefn(n, names)
|
n.Def = initDefn(n, names)
|
||||||
|
|
||||||
if delay {
|
if !delayTransform() {
|
||||||
n.SetTypecheck(3)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
|
lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
|
||||||
transformAssign(n, lhs, rhs)
|
transformAssign(n, lhs, rhs)
|
||||||
n.X, n.Y = lhs[0], rhs[0]
|
n.X, n.Y = lhs[0], rhs[0]
|
||||||
|
}
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
|
n := ir.NewAssignListStmt(g.pos(stmt), ir.OAS2, lhs, rhs)
|
||||||
n.Def = initDefn(n, names)
|
n.Def = initDefn(n, names)
|
||||||
if delay {
|
if !delayTransform() {
|
||||||
n.SetTypecheck(3)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
transformAssign(n, n.Lhs, n.Rhs)
|
transformAssign(n, n.Lhs, n.Rhs)
|
||||||
|
}
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
return n
|
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))
|
return ir.NewGoDeferStmt(g.pos(stmt), g.tokOp(int(stmt.Tok), callOps[:]), g.expr(stmt.Call))
|
||||||
case *syntax.ReturnStmt:
|
case *syntax.ReturnStmt:
|
||||||
n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
|
n := ir.NewReturnStmt(g.pos(stmt), g.exprList(stmt.Results))
|
||||||
for _, e := range n.Results {
|
if !delayTransform() {
|
||||||
if e.Type().HasTParam() {
|
|
||||||
// Delay transforming the return statement if any of the
|
|
||||||
// return values have a type param.
|
|
||||||
n.SetTypecheck(3)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transformReturn(n)
|
transformReturn(n)
|
||||||
|
}
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
return n
|
return n
|
||||||
case *syntax.IfStmt:
|
case *syntax.IfStmt:
|
||||||
@ -146,19 +112,10 @@ func (g *irgen) stmt(stmt syntax.Stmt) ir.Node {
|
|||||||
case *syntax.SelectStmt:
|
case *syntax.SelectStmt:
|
||||||
n := g.selectStmt(stmt)
|
n := g.selectStmt(stmt)
|
||||||
|
|
||||||
delay := false
|
if !delayTransform() {
|
||||||
for _, ncase := range n.(*ir.SelectStmt).Cases {
|
|
||||||
if ncase.Comm != nil && ncase.Comm.Typecheck() == 3 {
|
|
||||||
delay = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if delay {
|
|
||||||
n.SetTypecheck(3)
|
|
||||||
} else {
|
|
||||||
transformSelect(n.(*ir.SelectStmt))
|
transformSelect(n.(*ir.SelectStmt))
|
||||||
n.SetTypecheck(1)
|
|
||||||
}
|
}
|
||||||
|
n.SetTypecheck(1)
|
||||||
return n
|
return n
|
||||||
case *syntax.SwitchStmt:
|
case *syntax.SwitchStmt:
|
||||||
return g.switchStmt(stmt)
|
return g.switchStmt(stmt)
|
||||||
|
@ -195,7 +195,7 @@ func transformCompare(n *ir.BinaryExpr) {
|
|||||||
aop, _ := typecheck.Assignop(lt, rt)
|
aop, _ := typecheck.Assignop(lt, rt)
|
||||||
if aop != ir.OXXX {
|
if aop != ir.OXXX {
|
||||||
types.CalcSize(lt)
|
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 = ir.NewConvExpr(base.Pos, aop, rt, l)
|
||||||
l.SetTypecheck(1)
|
l.SetTypecheck(1)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user