How to best maximally reabstract returned function type in SILGen

Hi SIL experts,

I wonder how to reabstract values from type A to type B during SILGen?

A: $(Float) -> (Float, @owned @callee_guaranteed (Float) -> Float)
B: $(Float) -> (Float, @owned @callee_guaranteed (@in_guaranteed Float) -> @out Float)

The main difficulty: SILGen reabstraction utilities involve AST types and abstraction patterns, not SIL types. There is a corresponding AST type and abstraction pattern for B, but they are simply (Float) -> (Float, (Float) -> Float).

I want to force the returned function type to be maximally indirect (@in_guaranteed Float) -> @out Float. What is the best way to do this?


My ideas:

  • Opaque abstraction pattern is not appropriate because that causes the entire function type to be maximally indirect, not just the returned function type: $(@in_guaranteed Float) -> @out (Float, @callee_guaranteed (@in_guaranteed Float) -> @out Float).
    • We could adapt the rest of our infrastructure to work with entirely maximally indirect function types, but I wonder if we can avoid this if possible for efficiency/simplicity.
    • Invariants are that arguments of B can have same abstraction as arguments of B, and returned tuple type of B can always be direct.
  • We could manually construct a generic function type <T>(Float) -> (Float, (T) -> T) and use that as an abstraction pattern for type B, but this feels quite hacky.

Context: I'm working on the differentiable programming project.

  • Derivative functions return a "linear approximation function".
  • We want to standardize all "returned linear approximation function types" to be maximally indirect in SIL to fix a sleuth of abstraction mismatch bugs - see issue description here for more details.

Any help would be appreciated!

cc @Joe_Groff @Slava_Pestov @John_McCall

("slew", not "sleuth")

I'm sorry, but that sounds like a cop-out to me. It sounds like you're having trouble applying abstraction patterns correctly, so you decided to try to define them away, and now, unsurprisingly, you're having trouble with even the first-order consequences of that decision.

Abstraction patterns can be structurally opaque; it's not all or nothing. You could construct an abstraction pattern by looking through function types in the original type and filling in the arguments and returns that aren't themselves function types with opaque patterns in those positions. Alternatively, maybe you want to introduce a new kind of abstraction pattern that has the abstraction behavior you want, similar to what we do with abstraction patterns for C/ObjC method signatures.

1 Like
Terms of Service

Privacy Policy

Cookie Policy