New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
introduces Unquote #112
Merged
Merged
introduces Unquote #112
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I'm about to significantly change @ast codegen, so we need these additional tests to make sure that nothing breaks down the road.
I'm about to introduce impl.Unquote, which has to be a subtype of all tree nodes. However unpleasant the consequences are, we have to deal with them, because we currently don't know of an alternative technology to implement quasiquotes in a principled manner. What we discussed with Denys is that we might be able to get back the guarantees offered by sealedness if we find a way to customize exhaustivity checks in the pattern matcher from a compiler plugin. People are going to use scalahost anyway, so it could also do additional domain-specific exhaustivity checking. This commit also comes with some refactoring of the adt/ast infrastructure. In particular, all checks now return q"()" instead of q"", which has uncovered a terrible bug. If a trait def has the INTERFACE flag set, then essentially any statement in its body (e.g. q"()") is going to crash the compiler. Therefore, I'm manually resetting the INTERFACE flag in @root and @Branch. This, in turn, led to problems with `@branch trait Defn`, because it makes scalac emit `Defn$class`, which comes in conflict with `Defn$Class`. To address that, I had to temporarily disable all checks for Defn.
As explained in the parent's commit message, we had to reset INTERFACE, because our codegen emits statements into templates of the annottees, and GenICode really doesn't like it when a template of an INTERFACE trait has statements in it. Now it's time for a principled solution. All statements are now moved to companions of the annottees, and everyone's happy.
I'm about to introduce scala.meta.internal.ast.Unquote, which has to be a subtype of all tree nodes. For that, we need to make it possible to subclass @ast classes. The solution that I'll be pursuing in this and subsequent commits is splitting `@ast class Foo` into `trait Foo; object Foo { class Impl extends Foo }`. This is a very heavy-handed way of organizing the @ast codegen, but it looks like we don't have much choice. A pleasant side-effect of this change is the ability to proxy trees, so that, for example, we can lazily load bodies of vals/vars/defs. Nothing in that direction is implemented just yet. We will cross that bridge when we get there - now is not the time.
Unfortunately, having an Interface => Api implicit conversion is not enough, because we have things like Member.name in the semantic API, and those come in conflict. Therefore, we'll have to move ast fields to the interface part, and then have Unquote implement ALL those fields with ??? or something similar.
This is a funny class that is a subclass of all ast classes in scala.meta. At the moment it's just `@bottom @ast class Unquote() extends Tree`, but later on we'll decide how it fields should look like.
Now when we accumulate all ast classes in parents of Unquote, we don't need an additional mechanism to track those classes.
It turns out that it can be perfectly represented by meta.Name.Indeterminate.
This takes care of the last place in the tree API, where we represented names with strings, and makes our tree API maximally friendly to Unquote. It's a bit of stretch to use Name.Qualifier here, because along with anonymous and indeterminate names (which fit), Name.Qualifier also covers Term.This (which doesn't fit), but I didn't feel like introducing a new public trait just to have this extra bit of static safety. Maybe in the future we'll have to change this decision. Having this change in place also means that This and Super don't have to be names anymore. This, in turn, means that Name.Qualifier can no longer be a Name and becomes a Ref. This also means that Member.name can no longer be a Name, but that was too much for me, so now it's still a Name, but it does not return This anymore. All in all, this worked pretty well. I'm not sure whether I like the fact that `this` and `super` are no longer names, but I can try to get accustomed to that.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.