-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix #5495: Reject invalid modifiers on enums #5525
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
Conversation
b6c58f1
to
0f49528
Compare
0f49528
to
3a49ed4
Compare
The token `case` is a modifier follower
3a49ed4
to
954d075
Compare
@@ -69,8 +69,8 @@ object DesugarEnums { | |||
|
|||
/** Add implied flags to an enum class or an enum case */ | |||
def addEnumFlags(cdef: TypeDef)(implicit ctx: Context): TypeDef = | |||
if (cdef.mods.isEnumClass) cdef.withMods(cdef.mods.withFlags(cdef.mods.flags | Abstract | Sealed)) | |||
else if (isEnumCase(cdef)) cdef.withMods(cdef.mods.withFlags(cdef.mods.flags | Final)) | |||
if (cdef.mods.isEnumClass) cdef.withMods(cdef.mods.toTypeFlags | Abstract | Sealed) |
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.
Note the toTypeFlags
here. It is to prevent a illegal flagset combination
assertion failure that occurs when combining TermFlags
with TypeFlags
. For example when parsing:
lazy enum Foo {}
Enum is no longer a modifier. This seems to be some vestige of the old enum design
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.
The usual place to check flags is in Checking.checkWellformed
. I believe we should do any checking for enum modifiers there. No changes to Parser should be necessary.
I checked the flags in the parser so that they are sanitised before desugaring happens. Otherwise we report spurious errors: scala> implicit enum Foo {}
1 |implicit enum Foo {}
|^^^^^^^^^^^^^^^^^^^^
|Implicit classes must accept exactly one primary constructor parameter
scala> implicit enum Foo(x: Int) {}
1 |implicit enum Foo(x: Int) {}
| ^
| implicit modifier cannot be used for types or traits Also, if flags are not sanitised before desugaring, this may lead to illegal flag combination: scala> lazy enum Foo{}
Exception in thread "main" java.lang.AssertionError: assertion failed: illegal flagset combination: lazy abstract <enum> and sealed
at dotty.DottyPredef$.assertFail(DottyPredef.scala:38)
at dotty.tools.dotc.core.Flags$FlagSet$.$bar$extension(Flags.scala:26)
at dotty.tools.dotc.ast.DesugarEnums$.addEnumFlags(DesugarEnums.scala:72) |
There are lots of situations where some flag combinations are illegal. That's why we check them in two centralized places: So, whatever we do, let's check all flags in the same way! Maybe we decide it's best to check all flags in parser, or in desugaring, or in Namer, as it is done now. But let's not create exceptions for specific cases. In fact I believe checking flags in desugaring instead of Namer might be a reasonable compromise. |
I am unassigning myself. I will not have time to address the review comments. Feel free to close or take over the PR |
@allanrenucci Understood. Thanks for your work on this, which will be useful for me to take over. |
@odersky That comment applies to #4973 as well apparently, and overrides @smarter's suggestion there, I guess?
Does the choice affect the IDE behavior on erroneous programs? |
Of course that affects whether you get other errors, but these ones should be easy to fix. I asked Olaf, he doesn't have a strong opinion. |
Superseded by #7850 |
Adapted from scala#5525: Check that only access modifiers are legal for enums (both definitions and cases). This is useful as a pre-check, to avoid confusing error messages later.
Fixes #5034