Skip to content

Commit 4edefe9

Browse files
committed
cmd/compile: delay all call transforms if in a generic function
We changed to delaying all transforms of generic functions, since there are so many complicated situations where type params can be used. We missed changing so that all Call expressions(not just some) are delayed if in a generic function. This changes to delaying all transforms on calls in generic functions. Had to convert Call() to g.callExpr() (so we can access g.delayTransform()). By always delaying transforms on calls in generic functions, we actually simplify the code a bit both in g.CallExpr() and stencil.go. Fixes #51236 Change-Id: I0342c7995254082c4baf709b0b92a06ec14425e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/386220 Reviewed-by: Keith Randall <[email protected]> Trust: Dan Scales <[email protected]> Run-TryBot: Dan Scales <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 8c5904f commit 4edefe9

File tree

4 files changed

+71
-100
lines changed

4 files changed

+71
-100
lines changed

src/cmd/compile/internal/noder/expr.go

+48-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
114114

115115
case *syntax.CallExpr:
116116
fun := g.expr(expr.Fun)
117-
return Call(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
117+
return g.callExpr(pos, g.typ(typ), fun, g.exprs(expr.ArgList), expr.HasDots)
118118

119119
case *syntax.IndexExpr:
120120
args := unpackListExpr(expr.Index)
@@ -206,6 +206,53 @@ func (g *irgen) substType(typ *types.Type, tparams *types.Type, targs []ir.Node)
206206
return newt
207207
}
208208

209+
// callExpr creates a call expression (which might be a type conversion, built-in
210+
// call, or a regular call) and does standard transforms, unless we are in a generic
211+
// function.
212+
func (g *irgen) callExpr(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
213+
n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
214+
n.IsDDD = dots
215+
typed(typ, n)
216+
217+
if fun.Op() == ir.OTYPE {
218+
// Actually a type conversion, not a function call.
219+
if !g.delayTransform() {
220+
return transformConvCall(n)
221+
}
222+
return n
223+
}
224+
225+
if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
226+
if !g.delayTransform() {
227+
return transformBuiltin(n)
228+
}
229+
return n
230+
}
231+
232+
// Add information, now that we know that fun is actually being called.
233+
switch fun := fun.(type) {
234+
case *ir.SelectorExpr:
235+
if fun.Op() == ir.OMETHVALUE {
236+
op := ir.ODOTMETH
237+
if fun.X.Type().IsInterface() {
238+
op = ir.ODOTINTER
239+
}
240+
fun.SetOp(op)
241+
// Set the type to include the receiver, since that's what
242+
// later parts of the compiler expect
243+
fun.SetType(fun.Selection.Type)
244+
}
245+
}
246+
247+
// A function instantiation (even if fully concrete) shouldn't be
248+
// transformed yet, because we need to add the dictionary during the
249+
// transformation.
250+
if fun.Op() != ir.OFUNCINST && !g.delayTransform() {
251+
transformCall(n)
252+
}
253+
return n
254+
}
255+
209256
// selectorExpr resolves the choice of ODOT, ODOTPTR, OMETHVALUE (eventually
210257
// ODOTMETH & ODOTINTER), and OMETHEXPR and deals with embedded fields here rather
211258
// than in typecheck.go.

src/cmd/compile/internal/noder/helpers.go

-89
Original file line numberDiff line numberDiff line change
@@ -98,95 +98,6 @@ func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExp
9898
}
9999
}
100100

101-
func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
102-
n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
103-
n.IsDDD = dots
104-
105-
if fun.Op() == ir.OTYPE {
106-
// Actually a type conversion, not a function call.
107-
if !fun.Type().IsInterface() &&
108-
(fun.Type().HasTParam() || args[0].Type().HasTParam()) {
109-
// For type params, we can transform if fun.Type() is known
110-
// to be an interface (in which case a CONVIFACE node will be
111-
// inserted). Otherwise, don't typecheck until we actually
112-
// know the type.
113-
return typed(typ, n)
114-
}
115-
typed(typ, n)
116-
return transformConvCall(n)
117-
}
118-
119-
if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
120-
// For most Builtin ops, we delay doing transformBuiltin if any of the
121-
// args have type params, for a variety of reasons:
122-
//
123-
// OMAKE: transformMake can't choose specific ops OMAKESLICE, etc.
124-
// until arg type is known
125-
// OREAL/OIMAG: transformRealImag can't determine type float32/float64
126-
// until arg type known
127-
// OAPPEND: transformAppend requires that the arg is a slice
128-
// ODELETE: transformDelete requires that the arg is a map
129-
// OALIGNOF, OSIZEOF: can be eval'ed to a constant until types known.
130-
switch fun.BuiltinOp {
131-
case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
132-
hasTParam := false
133-
for _, arg := range args {
134-
if fun.BuiltinOp == ir.OOFFSETOF {
135-
// It's the type of left operand of the
136-
// selection that matters, not the type of
137-
// the field itself (which is irrelevant for
138-
// offsetof).
139-
arg = arg.(*ir.SelectorExpr).X
140-
}
141-
if arg.Type().HasTParam() {
142-
hasTParam = true
143-
break
144-
}
145-
}
146-
if hasTParam {
147-
return typed(typ, n)
148-
}
149-
}
150-
151-
typed(typ, n)
152-
return transformBuiltin(n)
153-
}
154-
155-
// Add information, now that we know that fun is actually being called.
156-
switch fun := fun.(type) {
157-
case *ir.SelectorExpr:
158-
if fun.Op() == ir.OMETHVALUE {
159-
op := ir.ODOTMETH
160-
if fun.X.Type().IsInterface() {
161-
op = ir.ODOTINTER
162-
}
163-
fun.SetOp(op)
164-
// Set the type to include the receiver, since that's what
165-
// later parts of the compiler expect
166-
fun.SetType(fun.Selection.Type)
167-
}
168-
}
169-
170-
if fun.Type().HasTParam() || fun.Op() == ir.OXDOT || fun.Op() == ir.OFUNCINST {
171-
// If the fun arg is or has a type param, we can't do all the
172-
// transformations, since we may not have needed properties yet
173-
// (e.g. number of return values, etc). The same applies if a fun
174-
// which is an XDOT could not be transformed yet because of a generic
175-
// type in the X of the selector expression.
176-
//
177-
// A function instantiation (even if fully concrete) shouldn't be
178-
// transformed yet, because we need to add the dictionary during the
179-
// transformation.
180-
return typed(typ, n)
181-
}
182-
183-
// If no type params, do the normal call transformations. This
184-
// will convert OCALL to OCALLFUNC.
185-
typed(typ, n)
186-
transformCall(n)
187-
return n
188-
}
189-
190101
func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
191102
n := ir.NewBinaryExpr(pos, op, x, y)
192103
typed(typ, n)

src/cmd/compile/internal/noder/stencil.go

+1-10
Original file line numberDiff line numberDiff line change
@@ -1055,8 +1055,6 @@ func (subst *subster) node(n ir.Node) ir.Node {
10551055
// Transform the conversion, now that we know the
10561056
// type argument.
10571057
m = transformConvCall(call)
1058-
// CONVIFACE transformation was already done in noder2
1059-
assert(m.Op() != ir.OCONVIFACE)
10601058

10611059
case ir.OMETHVALUE, ir.OMETHEXPR:
10621060
// Redo the transformation of OXDOT, now that we
@@ -1076,14 +1074,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
10761074
case ir.ONAME:
10771075
name := call.X.Name()
10781076
if name.BuiltinOp != ir.OXXX {
1079-
switch name.BuiltinOp {
1080-
case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
1081-
// Transform these builtins now that we
1082-
// know the type of the args.
1083-
m = transformBuiltin(call)
1084-
default:
1085-
base.FatalfAt(call.Pos(), "Unexpected builtin op")
1086-
}
1077+
m = transformBuiltin(call)
10871078
} else {
10881079
// This is the case of a function value that was a
10891080
// type parameter (implied to be a function via a

test/typeparam/issue51236.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// run -gcflags=-G=3
2+
3+
// Copyright 2022 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
type I interface {
10+
[]byte
11+
}
12+
13+
func F[T I]() {
14+
var t T
15+
explodes(t)
16+
}
17+
18+
func explodes(b []byte) {}
19+
20+
func main() {
21+
22+
}

0 commit comments

Comments
 (0)