// it before installing the instantiation, so we are
// checking against non-shape param types in
// typecheckaste.
- transformCall(call)
+ transformCall(call, nil)
// Replace the OFUNCINST with a direct reference to the
// new stenciled function
// Transform the Call now, which changes OCALL
// to OCALLFUNC and does typecheckaste/assignconvfn.
- transformCall(call)
+ transformCall(call, nil)
st := g.getInstantiation(gf, targs, true).fun
dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true)
assert(l == len(g.instInfoMap))
}
-// buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR
+// buildClosure makes a closure to implement x, a OFUNCINST or OMETHEXPR/OMETHVALUE
// of generic type. outer is the containing function (or nil if closure is
// in a global assignment instead of a function).
func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
// transform the call.
call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
transformDot(call.X.(*ir.SelectorExpr), true)
- transformCall(call)
+ transformCall(call, subst.info.dictParam)
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)
+ transformCall(call, subst.info.dictParam)
case ir.ONAME:
name := call.X.Name()
// 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)
+ transformCall(call, subst.info.dictParam)
}
case ir.OCLOSURE:
- transformCall(call)
+ transformCall(call, subst.info.dictParam)
case ir.ODEREF, ir.OINDEX, ir.OINDEXMAP, ir.ORECV:
// Transform a call that was delayed because of the
// use of typeparam inside an expression that required
// a pointer dereference, array indexing, map indexing,
// or channel receive to compute function value.
- transformCall(call)
+ transformCall(call, subst.info.dictParam)
case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
- transformCall(call)
+ transformCall(call, subst.info.dictParam)
case ir.OCONVNOP:
- transformCall(call)
+ transformCall(call, subst.info.dictParam)
case ir.OFUNCINST:
// A call with an OFUNCINST will get transformed
m.(*ir.CallExpr).X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
transformDot(m.(*ir.CallExpr).X.(*ir.SelectorExpr), true)
}
- transformCall(m.(*ir.CallExpr))
+ transformCall(m.(*ir.CallExpr), info.dictParam)
}
case ir.OCONVIFACE:
// transformCall transforms a normal function/method call. Corresponds to last half
// (non-conversion, non-builtin part) of typecheck.tcCall. This code should work even
// in the case of OCALL/OFUNCINST.
-func transformCall(n *ir.CallExpr) {
+// The dict parameter is used for OCALLINTER nodes to ensure that the called method
+// is retained by the linker.
+func transformCall(n *ir.CallExpr, dict *ir.Name) {
// n.Type() can be nil for calls with no return value
assert(n.Typecheck() == 1)
transformArgs(n)
switch l.Op() {
case ir.ODOTINTER:
n.SetOp(ir.OCALLINTER)
+ if n.X.(*ir.SelectorExpr).X.Type().HasShape() {
+ if dict == nil {
+ base.Fatalf("calls on shape interfaces need a dictionary reference")
+ }
+ dict.SetAddrtaken(true)
+ // KeepAlive isn't exactly the right thing here, as we only
+ // need to keep the dictionary live in the linker-deadcode
+ // sense, not the at-runtime sense. But the at-runtime sense
+ // is stronger, so it works. See issue 48047.
+ n.KeepAlive = append(n.KeepAlive, dict)
+ }
case ir.ODOTMETH:
l := l.(*ir.SelectorExpr)