-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Implement match type amendment: extractors follow aliases and singletons #20161
Conversation
The existing spec uses as a legal example: ``` class Base { type Y } type YExtractor[t] = Base { type Y = t } ``` And we are allowed to define: ``` type ExtractY[B <: Base] = B match case YExtractor[t] => t ``` However, with the existing spec, extraction does not always work as one might expect: ``` class Sub1 extends Base: type Y = Alias type Alias = Int class Sub2[T] extends Base: type Y = T class Sub3 extends Base: val elem: Sub1 = new Sub1 type Y = elem.Y ExtractY[Base { type Y = Int }] // OK ExtractY[Sub1] // error ExtractY[Sub2[Int]] // error ExtractY[Sub3] // error ``` What's going on here is that when extracting a type `Y` from a non-stable prefix `X`, the spec mandates that we generate a skolem `q` and use that as a prefix to lookup the underlying type of `Y`. Extraction only succeeds if the underlying type does not refer to `q`. For example, for `ExtractY[Sub1]` we have `q.Y` with underlying type `q.Alias` which is rejected since it refers to `q`. We amend the spec to follow aliases and singleton types in the extracted type, so that `q.Alias` can be dealiased to `Int` which is then accepted as a valid extracted type. More motivating examples can be found in the implementation at scala/scala3#20161.
The existing spec uses as a legal example: ``` class Base { type Y } type YExtractor[t] = Base { type Y = t } ``` And we are allowed to define: ``` type ExtractY[B <: Base] = B match case YExtractor[t] => t ``` However, with the existing spec, extraction does not always work as one might expect: ``` class Sub1 extends Base: type Y = Alias type Alias = Int class Sub2[T] extends Base: type Y = T class Sub3 extends Base: val elem: Sub1 = new Sub1 type Y = elem.Y ExtractY[Base { type Y = Int }] // OK ExtractY[Sub1] // error ExtractY[Sub2[Int]] // error ExtractY[Sub3] // error ``` What's going on here is that when extracting a type `Y` from a non-stable prefix `X`, the spec mandates that we generate a skolem `q` and use that as a prefix to lookup the underlying type of `Y`. Extraction only succeeds if the underlying type does not refer to `q`. For example, for `ExtractY[Sub1]` we have `q.Y` with underlying type `q.Alias` which is rejected since it refers to `q`. We amend the spec to follow aliases and singleton types in the extracted type, so that `q.Alias` can be dealiased to `Int` which is then accepted as a valid extracted type. More motivating examples can be found in the implementation at scala/scala3#20161.
I think it'd be useful to get this in 3.5.0-RC1 for testing purposes, we'd then revert it before the release if the sip committee votes against it. |
We will not be merging this before SIP committee decision. |
I'd like to formally appeal that decision. As can be seen in scala/improvement-proposals#84, there is support among the SIP committee members for not unnecessarily delaying this. Delaying makes sense if we believe that it will improve the quality of the final outcome, but we shouldn't stale things for purely procedural reasons. The procedures were put in place to achieve a certain result (build consensus, give enough time for experimentation, ...), so we should always ask ourselves if what we're doing is aligned with the result we want. |
I've now moved the new logic under an experimental language feature so that it can be merged without SIP approval. |
This implements the change proposed in scala/improvement-proposals#84. The added pos test case presents motivating examples, the added neg test cases demonstrate that errors are correctly reported when cycles are present. The potential for cycle is no worse than with the existing extraction logic as demonstrated by the existing test in `tests/neg/mt-deskolemize.scala`.
This way we can merge this PR without waiting for the SIP committee to approve it.
No need to save the value of `refersToSkolem`: if it's true before we enter `NamedType` it will be true after and `dropSkolem` will return `NoType`. The previous logic could still be useful if we want to give more easily actionable error messages in the future by only keeping in the type the skolems we couldn't remove.
This implements the change proposed in
scala/improvement-proposals#84.
The added pos test case presents motivating examples, the added neg test cases demonstrate that errors are correctly reported when cycles are present. The potential for cycle is no worse than with the existing extraction logic as demonstrated by the existing test in
tests/neg/mt-deskolemize.scala
.