For context: I'm currently trying to implement a crude prototype of a MacroExpansionContext.getType(of:)
function that allows a macro expansion to get the type of an expression as a TypeSyntax
(stay tuned for a pitch, I just wanted to try out some designs of the feature first).
During a macro expansion, I want to run TypeChecker::typeCheckExpression
(with macro expansion disabled) on an expression to get its type, so that I can query types from within the macro expansion plugin. This works fine, however, I'm running into the problem that apparently "The constraint system does not support type checking an already-type-checked AST" (as is noted in this PR), which results in the type-checker crashing after the macro expansion when it tries to check the same expression again.
Why is the type-checker designed that way? How hard would it be to support re-type-checking an AST?
Assuming the answer is "very hard", what alternative solutions to this problem can you think of?
For my prototype, I got quite far simply by adding an isAlreadyTypeChecked
field to Expr
and skipping an expression during type-checking when this field is set to true, but that's obviously not a real solution, because the expression actually has to be type-checked again (with macro expansions enabled).
Another idea I had was to literally deep-clone the expression AST and to type-check the cloned expression instead. This could probably work for an initial prototype of this feature (although it would be a big hassle to implement, as the AST currently just doesn't support cloning at all, so one would have to implement a clone function for every single AST node class...), but isn't a real solution either, because it would mean that all the type-checking work has to be done twice for that (possibly arbitrarily large) expression.
As I'm quite new to Swift compiler development, it's possible (very likely actually) that I'm missing some obvious solution, so hopefully one of you more seasoned Swift compiler developers can enlighten me :)
Cheers,
Josef