-
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
Don't generate Mirror.Sum for simple enum cases #14525
Conversation
@andrzejressel is that causing the problems with enums in shapeless and kittens? |
@joroKr21 Hi, I've just verified this and yes, this commit fixes typelevel/shapeless-3#51 and typelevel/kittens#449 |
@@ -273,7 +273,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): | |||
val cls = mirroredType.classSymbol | |||
val useCompanion = cls.useCompanionAsSumMirror | |||
|
|||
if cls.isGenericSum(if useCompanion then cls.linkedClass else ctx.owner) then | |||
if (!mirroredType.termSymbol.isEnumCase && (cls.isGenericSum(if useCompanion then cls.linkedClass else ctx.owner))) then |
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.
isGenericSum
is used in one more place and I wonder if it should be modified as well.
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.
In SyntheticMembers::addMirrorSupport
? It's not an issue, because this method will never be called: as far as I understand branch else if (impl.removeAttachment(ExtendsSingletonMirror).isDefined)
will be invoked.
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.
it's fine to keep isGenericSum
implementation unchanged, it should only be called on a class symbol, perhaps it could be more informative to rename to isGenericSumClass
, along with isGenericProduct
to isGenericProductClass
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.
Hey, thank you for noticing this and opening the PR!
I think this could go further, for example, it's still possible to summon a sum mirror for the union of two value cases (that is generated like the mirror for Foo
):
enum Foo { case A, B, C }
summon[scala.deriving.Mirror.SumOf[Foo.A.type | Foo.B.type]]
/*
val res6:
(
deriving.Mirror.Sum{
MirroredType = (Foo.A.type | Foo.B.type);
MirroredMonoType = (Foo.A.type | Foo.B.type)
; MirroredElemTypes <: Tuple
}
&
scala.deriving.Mirror.Sum{
MirroredMonoType = (Foo.A.type | Foo.B.type);
MirroredType = (Foo.A.type | Foo.B.type)
; MirroredLabel = "Foo"
}
){
MirroredElemTypes = (Foo.A.type, Foo.B.type, Foo.C.type);
MirroredElemLabels = ("A", "B", "C")
} = anon$1@7b205eaa
*/
my guess for a workable heuristic would be any top level part of the type being a term ref is not allowed.
Maybe the right approach is to use |
|
This doesn't make much sense to me - if we want union types to work properly their "children" should be only the elements of the union type. What happens right now is that it finds the LUB class and takes its children? scala> {
| sealed trait Foo extends Product, Serializable
| case object A extends Foo
| case object B extends Foo
| case object C extends Foo
| }
// defined trait Foo
// defined case object A
// defined case object B
// defined case object C
scala> summon[scala.deriving.Mirror.SumOf[A.type | B.type]]
val res4:
(
deriving.Mirror.Sum{
MirroredType = (A.type | B.type); MirroredMonoType = (A.type | B.type);
MirroredElemTypes <: Tuple
}
&
scala.deriving.Mirror.Sum{
MirroredMonoType = (A.type | B.type); MirroredType = (A.type | B.type);
MirroredLabel = "Foo"
}
){
MirroredElemTypes = (A.type, B.type, C.type);
MirroredElemLabels = ("A", "B", "C")
} = anon$1@2b749404 Note that scala> {
| sealed trait Foo extends Product, Serializable
| case class A() extends Foo
| case class B() extends Foo
| case class C() extends Foo
| }
// defined trait Foo
// defined case class A
// defined case class B
// defined case class C
scala> summon[scala.deriving.Mirror.SumOf[A | B]]
-- Error: ----------------------------------------------------------------------
1 |summon[scala.deriving.Mirror.SumOf[A | B]]
| ^
|this case is unreachable since type MirroredMonoType and class C are unrelated
1 error found |
A union type can only be allowed where all of its branches are type applications of a covariant class, i.e. there can still be a mirror for Elaborating: |
I think it's fine disallowing |
@andrzejressel hey, I'm just wondering if are you blocked, or do not have time to work on this, or if we can help in any way? |
To be honest I was wondering where your discussion would lead. I guess my current task is disallowing mirror of union of singletons: #14525 (comment) |
I think we should also want to block enum Bar:
case A(i: Int)
case B(b: Boolean)
case C(s: String) so the algorithm for this would be that we extract the leaves of union types, and then check that either no branch is some singleton value, or that no two branches refer to different class types |
Hi, I don't know If I understood you correctly, but I found method |
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.
Nicely done
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.
I still think it would have been simpler to use typeSymbol
instead of classSymbol
but I'm fairly happy with this and I'm looking forward to this fix a lot 😄
I simplified a bit so it is more resistant to change |
From my understanding simple enum cases are not real classes, but instances of enum object class. Because of that they inherit their Mirror.Sum which may confuse tools like Shapeless (and also I feel it's not valid, because class cannot have both Product and Sum at the same time).