mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: replace calls to typecheck with transform functions
For additions, compares, and slices, create transform functions that do just the transformations for those nodes by the typecheck package (given that the code has been fully typechecked by types2). For nodes that have no args with typeparams, we call these transform functions directly in noder2. But for nodes that have args with typeparams, we have to delay and call the tranform functions during stenciling, since we don't know the specific types involved. We indicate that a node still needs transformation by setting Typecheck to a new value 3. This value means the current type of the node has been set (via types2), but the node may still need transformation. Had to export typcheck.IsCmp and typecheck.Assignop from the typecheck package. Added new tests list2.go (required delaying compare typecheck/transform because of != compare in checkList) and adder.go (requires delaying add typecheck/transform, since it can do addition for numbers or strings). There are several more transformation functions needed for expressions (indexing, calls, etc.) and several more complicated ones needed for statements (mainly various kinds of assignments). Change-Id: I7d89d13a4108308ea0304a4b815ab60b40c59b0a Reviewed-on: https://go-review.googlesource.com/c/go/+/303091 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Dan Scales <danscales@google.com> Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
b8371d495b
commit
0265b6475f
10 changed files with 785 additions and 24 deletions
|
|
@ -67,16 +67,47 @@ func Assert(pos src.XPos, x ir.Node, typ *types.Type) ir.Node {
|
|||
return typed(typ, ir.NewTypeAssertExpr(pos, x, nil))
|
||||
}
|
||||
|
||||
func Binary(pos src.XPos, op ir.Op, x, y ir.Node) ir.Node {
|
||||
// transformAdd transforms an addition operation (currently just addition of
|
||||
// strings). Equivalent to the "binary operators" case in typecheck.typecheck1.
|
||||
func transformAdd(n *ir.BinaryExpr) ir.Node {
|
||||
l := n.X
|
||||
if l.Type().IsString() {
|
||||
var add *ir.AddStringExpr
|
||||
if l.Op() == ir.OADDSTR {
|
||||
add = l.(*ir.AddStringExpr)
|
||||
add.SetPos(n.Pos())
|
||||
} else {
|
||||
add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
|
||||
}
|
||||
r := n.Y
|
||||
if r.Op() == ir.OADDSTR {
|
||||
r := r.(*ir.AddStringExpr)
|
||||
add.List.Append(r.List.Take()...)
|
||||
} else {
|
||||
add.List.Append(r)
|
||||
}
|
||||
add.SetType(l.Type())
|
||||
return add
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) ir.Node {
|
||||
switch op {
|
||||
case ir.OANDAND, ir.OOROR:
|
||||
return typed(x.Type(), ir.NewLogicalExpr(pos, op, x, y))
|
||||
case ir.OADD:
|
||||
if x.Type().IsString() {
|
||||
// TODO(mdempsky): Construct OADDSTR directly.
|
||||
return typecheck.Expr(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
|
||||
}
|
||||
fallthrough
|
||||
n1 := transformAdd(n)
|
||||
return typed(typ, n1)
|
||||
default:
|
||||
return typed(x.Type(), ir.NewBinaryExpr(pos, op, x, y))
|
||||
}
|
||||
|
|
@ -178,12 +209,56 @@ func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool)
|
|||
return n
|
||||
}
|
||||
|
||||
// transformCompare transforms a compare operation (currently just equals/not
|
||||
// equals). Equivalent to the "comparison operators" case in
|
||||
// typecheck.typecheck1, including tcArith.
|
||||
func transformCompare(n *ir.BinaryExpr) {
|
||||
if (n.Op() == ir.OEQ || n.Op() == ir.ONE) && !types.Identical(n.X.Type(), n.Y.Type()) {
|
||||
// Comparison is okay as long as one side is assignable to the
|
||||
// other. The only allowed case where the conversion is not CONVNOP is
|
||||
// "concrete == interface". In that case, check comparability of
|
||||
// the concrete type. The conversion allocates, so only do it if
|
||||
// the concrete type is huge.
|
||||
l, r := n.X, n.Y
|
||||
lt, rt := l.Type(), r.Type()
|
||||
converted := false
|
||||
if rt.Kind() != types.TBLANK {
|
||||
aop, _ := typecheck.Assignop(lt, rt)
|
||||
if aop != ir.OXXX {
|
||||
types.CalcSize(lt)
|
||||
if rt.IsInterface() == lt.IsInterface() || lt.Width >= 1<<16 {
|
||||
l = ir.NewConvExpr(base.Pos, aop, rt, l)
|
||||
l.SetTypecheck(1)
|
||||
}
|
||||
|
||||
converted = true
|
||||
}
|
||||
}
|
||||
|
||||
if !converted && lt.Kind() != types.TBLANK {
|
||||
aop, _ := typecheck.Assignop(rt, lt)
|
||||
if aop != ir.OXXX {
|
||||
types.CalcSize(rt)
|
||||
if rt.IsInterface() == lt.IsInterface() || rt.Width >= 1<<16 {
|
||||
r = ir.NewConvExpr(base.Pos, aop, lt, r)
|
||||
r.SetTypecheck(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
n.X, n.Y = l, r
|
||||
}
|
||||
}
|
||||
|
||||
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 !types.Identical(x.Type(), y.Type()) {
|
||||
// TODO(mdempsky): Handle subtleties of constructing mixed-typed comparisons.
|
||||
n = typecheck.Expr(n).(*ir.BinaryExpr)
|
||||
if x.Type().HasTParam() || y.Type().HasTParam() {
|
||||
// Delay transformCompare() if either arg has a type param, since
|
||||
// it needs to know the exact types to decide on any needed conversions.
|
||||
n.SetType(typ)
|
||||
n.SetTypecheck(3)
|
||||
return n
|
||||
}
|
||||
transformCompare(n)
|
||||
return typed(typ, n)
|
||||
}
|
||||
|
||||
|
|
@ -267,13 +342,42 @@ func Index(pos src.XPos, typ *types.Type, x, index ir.Node) ir.Node {
|
|||
return typecheck.Expr(n)
|
||||
}
|
||||
|
||||
func Slice(pos src.XPos, x, low, high, max ir.Node) ir.Node {
|
||||
// transformSlice transforms a slice operation. Equivalent to typecheck.tcSlice.
|
||||
func transformSlice(n *ir.SliceExpr) {
|
||||
l := n.X
|
||||
if l.Type().IsArray() {
|
||||
addr := typecheck.NodAddr(n.X)
|
||||
addr.SetImplicit(true)
|
||||
typed(types.NewPtr(n.X.Type()), addr)
|
||||
n.X = addr
|
||||
l = addr
|
||||
}
|
||||
t := l.Type()
|
||||
if t.IsString() {
|
||||
n.SetOp(ir.OSLICESTR)
|
||||
} else if t.IsPtr() && t.Elem().IsArray() {
|
||||
if n.Op().IsSlice3() {
|
||||
n.SetOp(ir.OSLICE3ARR)
|
||||
} else {
|
||||
n.SetOp(ir.OSLICEARR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) ir.Node {
|
||||
op := ir.OSLICE
|
||||
if max != nil {
|
||||
op = ir.OSLICE3
|
||||
}
|
||||
// TODO(mdempsky): Avoid typecheck.Expr.
|
||||
return typecheck.Expr(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
|
||||
}
|
||||
transformSlice(n)
|
||||
return typed(typ, n)
|
||||
}
|
||||
|
||||
func Unary(pos src.XPos, op ir.Op, x ir.Node) ir.Node {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue