diff options
| author | Dan Scales <danscales@google.com> | 2021-03-29 08:28:01 -0700 |
|---|---|---|
| committer | Dan Scales <danscales@google.com> | 2021-03-30 03:05:45 +0000 |
| commit | eeadfa2d3810c252f86a88ddd282b48be5abc6df (patch) | |
| tree | cbc38592e0a2dbad05d343271124278d028bcf95 /src/cmd/compile/internal/noder/stencil.go | |
| parent | a95454b6f31a982f064d262987199fba19f085e9 (diff) | |
| download | go-eeadfa2d3810c252f86a88ddd282b48be5abc6df.tar.xz | |
cmd/compile: fix various small bugs related to type lists
Fix various small bugs related to delaying transformations due to type
params. Most of these relate to the need to delay a transformation when
an argument of an expression or statement has a type parameter that has
a structural constraint. The structural constraint implies the operation
should work, but the transformation can't happen until the actual value
of the type parameter is known.
- delay transformations for send statements and return statements if
any args/values have type params.
- similarly, delay transformation of a call where the function arg has
type parameters. This is mainly important for the case where the
function arg is a pure type parameter, but has a structural
constraint that requires it to be a function. Move the setting of
n.Use to transformCall(), since we may not know how many return
values there are until then, if the function arg is a type parameter.
- set the type of unary expressions from the type2 type (as we do with
most other expressions), since that works better with expressions
with type params.
- deal with these delayed transformations in subster.node() and convert
the CALL checks to a switch statement.
- make sure ir.CurFunc is set properly during stenciling, including
closures (needed for transforming return statements during
stenciling).
New test file typelist.go with tests for these cases.
Change-Id: I1b82f949d8cec47d906429209e846f4ebc8ec85e
Reviewed-on: https://go-review.googlesource.com/c/go/+/305729
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/noder/stencil.go')
| -rw-r--r-- | src/cmd/compile/internal/noder/stencil.go | 67 |
1 files changed, 50 insertions, 17 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 45864763d4..8dcc9d811e 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -270,6 +270,7 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.No newf.Nname.Func = newf newf.Nname.Defn = newf newsym.Def = newf.Nname + ir.CurFunc = newf assert(len(tparams) == len(targs)) @@ -286,7 +287,6 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.No for i, n := range gf.Dcl { newf.Dcl[i] = subst.node(n).(*ir.Name) } - newf.Body = subst.list(gf.Body) // Ugly: we have to insert the Name nodes of the parameters/results into // the function type. The current function type has no Nname fields set, @@ -305,6 +305,11 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.No newf.Nname.SetTypecheck(1) // TODO(danscales) - remove later, but avoid confusion for now. newf.Pragma = ir.Noinline + + // Make sure name/type of newf is set before substituting the body. + newf.Body = subst.list(gf.Body) + ir.CurFunc = nil + return newf } @@ -396,6 +401,12 @@ func (subst *subster) node(n ir.Node) ir.Node { as := m.(*ir.AssignOpStmt) transformCheckAssign(as, as.X) + case ir.ORETURN: + transformReturn(m.(*ir.ReturnStmt)) + + case ir.OSEND: + transformSend(m.(*ir.SendStmt)) + default: base.Fatalf("Unexpected node with Typecheck() == 3") } @@ -435,38 +446,55 @@ func (subst *subster) node(n ir.Node) ir.Node { case ir.OCALL: call := m.(*ir.CallExpr) - if call.X.Op() == ir.OTYPE { + switch call.X.Op() { + case ir.OTYPE: // Transform the conversion, now that we know the // type argument. m = transformConvCall(m.(*ir.CallExpr)) - } else if call.X.Op() == ir.OCALLPART { + + case ir.OCALLPART: // Redo the transformation of OXDOT, now that we // know the method value is being called. Then // transform the call. call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT) transformDot(call.X.(*ir.SelectorExpr), true) transformCall(call) - } else if call.X.Op() == ir.ODOT || call.X.Op() == ir.ODOTPTR { + + case ir.ODOT, ir.ODOTPTR: // An OXDOT for a generic receiver was resolved to // an access to a field which has a function // value. Transform the call to that function, now // that the OXDOT was resolved. 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: - // Transform these builtins now that we - // know the type of the args. - m = transformBuiltin(call) - default: - base.FatalfAt(call.Pos(), "Unexpected builtin op") + + case ir.ONAME: + name := call.X.Name() + if name.BuiltinOp != ir.OXXX { + switch name.BuiltinOp { + case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND: + // Transform these builtins now that we + // know the type of the args. + m = transformBuiltin(call) + default: + base.FatalfAt(call.Pos(), "Unexpected builtin op") + } + } else { + // This is the case of a function value that was a + // type parameter (implied to be a function via a + // structural constraint) which is now resolved. + transformCall(call) } - } else if call.X.Op() != ir.OFUNCINST { - // A call with an OFUNCINST will get typechecked + case ir.OCLOSURE: + transformCall(call) + + case ir.OFUNCINST: + // A call with an OFUNCINST will get transformed // in stencil() once we have created & attached the // instantiation to be called. - base.FatalfAt(call.Pos(), "Expecting OCALLPART or OTYPE or OFUNCINST or builtin with CALL") + + default: + base.FatalfAt(call.Pos(), fmt.Sprintf("Unexpected op with CALL during stenciling: %v", call.X.Op())) } case ir.OCLOSURE: @@ -491,17 +519,22 @@ func (subst *subster) node(n ir.Node) ir.Node { newfn.OClosure = m.(*ir.ClosureExpr) saveNewf := subst.newf + ir.CurFunc = newfn subst.newf = newfn newfn.Dcl = subst.namelist(oldfn.Dcl) newfn.ClosureVars = subst.namelist(oldfn.ClosureVars) - newfn.Body = subst.list(oldfn.Body) - subst.newf = saveNewf // Set Ntype for now to be compatible with later parts of compiler newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype) typed(subst.typ(oldfn.Nname.Type()), newfn.Nname) typed(newfn.Nname.Type(), m) newfn.SetTypecheck(1) + + // Make sure type of closure function is set before doing body. + newfn.Body = subst.list(oldfn.Body) + subst.newf = saveNewf + ir.CurFunc = saveNewf + subst.g.target.Decls = append(subst.g.target.Decls, newfn) } return m |
