-
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
Minimal support for dependent case classes #21698
Conversation
I am doing some experiment with dependent pattern match in CC, and this PR is useful for me as well! I modified the desuger so |
83c5e98
to
8d1c7fb
Compare
@noti0na1 Awesome! Let me know how it goes. |
3f3ce18
to
e5327ac
Compare
I think it's probably better to wait after the cutoff with this? |
So 3.6.1 rather than 3.6.0? |
Yes, 3.6.1 should work OK. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICS this only touches the fromProduct method. So it would be good to clarify some more what the limitations are. You mention dependent pattern matching. Ae there other things that don't work as one would expect?
But anyway this change in isolation LGTM
Will we be able to ever fix the remaining things without breaking binary/TASTy compat in the future? Currently we're safe because the definition does not compile. But if we make it compile today with incorrect code for some methods, we might be stuck with those incorrect definitions forever. |
Hi @smarter , is there any plan to merge this? |
Core Meeting says let's go ahead with this as is. @smarter Could you rebase on the latest |
This used to fail with: trait <refinement> in value x extends enum EC, but extending enums is prohibited.
This lets us write: trait A: type B case class CC(a: A, b: a.B) Pattern matching works but isn't dependent yet: x match case CC(a, b) => val a1: A = a // Dependent pattern matching is not currently supported // val b1: a1.B = b val b1 = b // Type is CC#a.B (for my usecase this isn't a problem, I'm working on a type constraint API which lets me write things like `case class CC(a: Int, b: Int GreaterThan[a.type])`) Because case class pattern matching relies on the product selectors `_N`, making it dependent is a bit tricky, currently we generate: case class CC(a: A, b: a.B): def _1: A = a def _2: a.B = b So the type of `_2` is not obviously related to the type of `_1`, we probably need to change what we generate into: case class CC(a: A, b: a.B): @uncheckedStable def _1: a.type = a def _2: _1.B = b But this can be done in a separate PR. Fixes scala#8073.
Looks like there is an bad interaction with @unroll which needs to be investigated. |
Looks like the unroll phase assumes a specific shape for the fromProduct method:
It already crashes if I define fromProduct manually with braces: case class Foo(x: String, @unroll y: Int = 1)
object Foo:
def fromProduct(x: Product): Foo = {
new Foo(
x.productElement(0).asInstanceOf[String],
x.productElement(1).asInstanceOf[Int]
)
} @bishabosha instead of transforming the body of fromProduct, couldn't we directly define the unroll-friendly version of fromProduct in SyntheticMembers ? |
It should work but probably worth checking that these are still generated after we detect unroll annotations on parameters (which updates the compilation unit flag)
so yeah architecture is in PostTyper we scan parameters for unroll, which updates a field in CompilationUnit, you can probably check for that in SyntheticMembers - then remove the special handling in Unroll phase which would simplify that a bunch. |
0b1c9e3
to
f3bd4e2
Compare
* x$0.productElement(2) | ||
* else | ||
* <default getter for the third parameter of C> | ||
* ).asInstanceOf[a$1.Elem] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.asInstanceOf[Seq[String]]
) | ||
).setDefTree | ||
} | ||
|
||
private enum Gen: | ||
case Substitute(origin: Symbol, newDef: DefDef) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be dead code now i think
UnrollDefinitions assumed that the body of `fromProduct` had a specific shape which is no longer the case with the dependent case class support introduced in the previous commit. This caused compiler crashes for tests/run/unroll-multiple.scala and tests/run/unroll-caseclass-integration This commit fixes this by directly generating the correct fromProduct in SyntheticMembers. This should also prevent crashes in situations where code is injected into existing trees like the code coverage support or external compiler plugins.
This accounts for singletons wrapping an ErasedValueType.
oops, I forgot the auto-merge was on, can you double-check the changes related to unroll @bishabosha ? |
@smarter seems good - the test case for illegal unroll on fromProduct is here https://github.com/scala/scala3/blob/main/tests/neg/unroll-duped.scala, so it seems no behavior change |
This lets us write:
Pattern matching works but isn't dependent yet:
(for my usecase this isn't a problem, I'm working on a type constraint API which lets me write things like
case class CC(a: Int, b: Int GreaterThan[a.type])
)Because case class pattern matching relies on the product selectors
_N
, making it dependent is a bit tricky, currently we generate:So the type of
_2
is not obviously related to the type of_1
, we probably need to change what we generate into:But this can be done in a separate PR.
Fixes #8073.