cmd/compile: create/use noder2 transform functions for more node types

Pull out the transformation part of the typechecking functions for:
 - assignment statements
 - return statements
 - send statements
 - select statements
 - type conversions
 - normal function/method calls
 - index operations

The transform functions are like the original typechecking functions,
but with all code removed related to:
  - Detecting compile-time errors (already done by types2)
  - Setting the actual type of existing nodes (already done based on
    info from types2)
  - Dealing with untyped constants

Moved all the transformation functions to a separate file, transform.go.

Continuing with the same pattern, we delay transforming a node if it has
any type params in its args, marking it with a typecheck flag of 3, and
do the actual transformation during stenciling.

Assignment statements are tricky, since their transformation must be
delayed if any of the left or right-hands-sides are delayed.

Still to do are:
 - selector expressions (OXDOT)
 - composite literal expressions (OCOMPLIT)
 - builtin function calls

Change-Id: Ie608cadbbc69b40db0067a5536cf707dd974aacc
Reviewed-on: https://go-review.googlesource.com/c/go/+/304049
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:
Dan Scales 2021-03-23 10:19:11 -07:00
parent 29ed12d4c7
commit e7e0995cba
7 changed files with 650 additions and 157 deletions

View file

@ -95,10 +95,9 @@ func (g *irgen) stencil() {
copy(withRecv[1:], call.Args)
call.Args = withRecv
}
// Do the typechecking of the Call now, which changes OCALL
// Transform the Call now, which changes OCALL
// to OCALLFUNC and does typecheckaste/assignconvfn.
call.SetTypecheck(0)
typecheck.Call(call)
transformCall(call)
modified = true
})
@ -372,16 +371,36 @@ func (subst *subster) node(n ir.Node) ir.Node {
// their instantiated type was known.
if typecheck.IsCmp(x.Op()) {
transformCompare(m.(*ir.BinaryExpr))
m.SetTypecheck(1)
} else if x.Op() == ir.OSLICE || x.Op() == ir.OSLICE3 {
transformSlice(m.(*ir.SliceExpr))
m.SetTypecheck(1)
} else if x.Op() == ir.OADD {
m = transformAdd(m.(*ir.BinaryExpr))
m.SetTypecheck(1)
} else {
base.Fatalf("Unexpected node with Typecheck() == 3")
switch x.Op() {
case ir.OSLICE:
case ir.OSLICE3:
transformSlice(m.(*ir.SliceExpr))
case ir.OADD:
m = transformAdd(m.(*ir.BinaryExpr))
case ir.OINDEX:
transformIndex(m.(*ir.IndexExpr))
case ir.OAS2:
as2 := m.(*ir.AssignListStmt)
transformAssign(as2, as2.Lhs, as2.Rhs)
case ir.OAS:
as := m.(*ir.AssignStmt)
lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y}
transformAssign(as, lhs, rhs)
case ir.OASOP:
as := m.(*ir.AssignOpStmt)
transformCheckAssign(as, as.X)
default:
base.Fatalf("Unexpected node with Typecheck() == 3")
}
}
m.SetTypecheck(1)
}
switch x.Op() {
@ -415,26 +434,25 @@ func (subst *subster) node(n ir.Node) ir.Node {
case ir.OCALL:
call := m.(*ir.CallExpr)
if call.X.Op() == ir.OTYPE {
// Do typechecking on a conversion, now that we
// know the type argument.
m.SetTypecheck(0)
m = typecheck.Expr(m)
// Transform the conversion, now that we know the
// type argument.
m = transformConvCall(m.(*ir.CallExpr))
m.SetTypecheck(1)
} else if call.X.Op() == ir.OCALLPART {
// Redo the typechecking, now that we know the method
// value is being called.
// Redo the typechecking of OXDOT, now that we
// know the method value is being called. Then
// transform the call.
call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
call.X.SetTypecheck(0)
call.X.SetType(nil)
typecheck.Callee(call.X)
call.SetTypecheck(0)
typecheck.Call(call)
transformCall(call)
} else if call.X.Op() == ir.ODOT || call.X.Op() == ir.ODOTPTR {
// An OXDOT for a generic receiver was resolved to
// an access to a field which has a function
// value. Typecheck the call to that function, now
// value. Transform the call to that function, now
// that the OXDOT was resolved.
call.SetTypecheck(0)
typecheck.Call(call)
transformCall(call)
} else if name := call.X.Name(); name != nil {
switch name.BuiltinOp {
case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND: