Automatic tracking of CallsFed constraints#3083
Conversation
pcapriotti
left a comment
There was a problem hiding this comment.
This looks great! I'm looking forward to having this applied everywhere and to error constraints as well.
I don't quite understand the meaning of the Location parameter of HasAnnotation. Could the Location thing and Symbols be replaced by an arbitrary kind, like
class HasAnnotation a (x :: a)? That would make the plugin more general, and allow us to use it for errors too.
The constraint-discharging mechanism using the empty dictionary trick could be moved to the plugin itself and ported to HasAnnotation constraints, right?
Somewhat relatedly, could this be improved by adding an extra type variable to the constraint? Then we could solve it directly by writing an empty instance of the HasAnnotation class for a new type. This could have been slightly annoying before, because the variable had to be specified on every function, but now it would be fine.
|
The location parameter is for my followup step of tracking non-federated calls across the codebase. I am open to better naming for the constructors here :) I explored making the annotation generic, but it's a no-go unfortunately. The compiler doesn't have enough information at compile-time to easily reify everything we need. Eg, we need a
I haven't explored this idea. It's plausible, depending on GHC's plugin architecture. However, I'd prefer to get a smaller plugin merged and battle-hardened before putting in more surface for things to go wrong.
I don't quite understand the suggestion here, but am all ears! |
If foo :: CallsFed Brig "blah" x => ...Then we could avoid the unsafeCoerce to make an instance, because we could make a new type and give it an instance in the normal way data X
instance CallsFed c api XThen say This would be annoying right now because this Actually, I think we could have taken this approach even without the plugin, by using the |
bdeabae to
9a5f888
Compare
pcapriotti
left a comment
There was a problem hiding this comment.
LGTM. Thanks for this!
This PR uses a new GHC plugin to automatically track
CallsFedconstraints across the codebase without manual programmer intervention. At a high level, it introduces a couple of new constructs:Adding Annotations
Adding an
AddAnnotation loc api methodconstraint to a function will instruct GHC to track this function call across the call-graph. Any other function which transitively calls this function will also acquire anAddAnnotation loc api methodconstraint. This is completely analogous to the oldCallsFedconstraint, except that the plugin prevents us from needing to move the constraints around ourselves.The
xparameter is an implementation detail, and should always be filled with an ambiguous, unspecified type variable.Exposing Annotations
The
exposeAnnotations ffunction lets us reintroduceAddAnnotation loc api method xconstraints attached tof, rewriting them asHasAnnotation loc api methodconstraints. By calling this function at the edge of each servant handler, the constraints GHC sees are exactly the same as if we had manually pushed theCallsFedconstraints all the way to servant. These constraints get immediately handled viacallsFedas before, ensuring we get an unsolved instance error if a codepath makes a federated call that isn't documented in the servant API.Misc
The plugin itself is currently a little messy. I'd like to clean it up before merging this PR, but would like confirmation that this is an approach we'd like to take before I invest that time into it.
Unfortunately, this PR requires reverting #3030, since we are now running at too low-level to use type information to help drive the analysis.
Checklist
changelog.d