Constructing a CallEmission without a "normal" function call expression?

Hi, I'm trying to construct a call emission from what I suspect is a somewhat unconventional location in SILExpr.cpp. This is going to be a long, and somewhat unfocused set of questions, because I tried several approaches to get this working.

For context, what I'm trying to do is make something like this compile: \MyType.myFunction(arg: someArgument). In other words, I want to generalize KeyPaths to accept function calls, too (and write a pitch for this feature once I have a prototype working). I have the parsing and type-checking done (I think), but I'm having a lot of trouble getting SIL generation to work.

Clearly, inside of RValueEmitter::visitKeyPathExpr, I need to construct a closure that does the equivalent of the subscript version of this function. My understanding is that functions like getOrCreateKeyPathGetter are making a closure that would basically look like this, if it was written in code for a subscript with one argument:

{ callee in
    callee[arg: arg1]

I was originally expecting that a subscript is basically exactly like a function, and that some slight modifications to the subscript version would have this working. But it seems that that is not the case. I ran out of ideas when I got to the point where I needed to have a AbstractStorageDecl; it didn't seem like a good idea to try to fake this, and the code using it didn't seem like it would be easy to modify to not need it.

My next attempt seemed more correct, and is also where CallEmission first shows up. I tried to look at how "real" function call expressions are constructed, and to copy that. So, it seemed like I needed a CallEmission to do this; and here, again, I ran into problems. I'm not sure how to make the self call without some form of Call Expr. To my surprise, a Callee seems to be a function, not an instance of some type (or the type itself for a static/class function), based on the code in CalleeTypeInfo::createCalleeTypeInfo, specifically:

    result.substFnType =
            SGF.SGM.M, Substitutions, SGF.getTypeExpansionContext());

For context: I constructed my callee using Callee::forIndirect, and passed the ManagedValue output from the prior KeyPath segment as my indirectValue.

I have a few ideas for how to proceed from here, but they're all fairly labor intensive; most of them basically involve starting from the top of how a "normal" Swift function call is type checked and has SIL emitted. I figured at this point it was better to ask and see if there's something obvious I'm missing before I go down this road.

So what I'm looking for, is some general advice on whether this is the right approach, how to get it working, and maybe also some context around why Callee is supposed to be a function and why subscripts seem so much easier to construct a call for in SIL than functions?

Thanks for reading!

1 Like

For the benefit of anyone who stumbles on this, indirect isn't the right kind of Callee to use. I had misunderstood what I was reading in the various kinds of callees; actually I needed a combination of forClassMethod, forDirect, and forWitnessMethod. I haven't gotten the latter working yet (it actually has a similar error message to the ones in my original post) but it seems pretty clear that this is the correct approach based on other code like getBaseAccessorFunctionRef.

1 Like