Skip to content

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

Closed
wants to merge 3 commits into from

Conversation

allanrenucci
Copy link
Contributor

Fixes #5034

The token `case` is a modifier follower
@@ -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)
Copy link
Contributor Author

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
Copy link
Contributor

@odersky odersky left a 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.

@odersky odersky assigned allanrenucci and unassigned odersky Dec 4, 2018
@allanrenucci
Copy link
Contributor Author

allanrenucci commented Dec 5, 2018

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)

@odersky
Copy link
Contributor

odersky commented Dec 13, 2018

There are lots of situations where some flag combinations are illegal. That's why we check them in two centralized places: checkFlags and checkWellformed. The former just checks that we don't mix type flags and term flags and the latter does all the other checks. I believe it's unsystematic to now also check some flag combinations in parser.

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.

@allanrenucci
Copy link
Contributor Author

I am unassigning myself. I will not have time to address the review comments. Feel free to close or take over the PR

@allanrenucci allanrenucci removed their assignment Jan 12, 2019
@odersky
Copy link
Contributor

odersky commented Jan 12, 2019

@allanrenucci Understood. Thanks for your work on this, which will be useful for me to take over.

@Blaisorblade
Copy link
Contributor

@odersky That comment applies to #4973 as well apparently, and overrides @smarter's suggestion there, I guess?

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.

Does the choice affect the IDE behavior on erroneous programs?

@Blaisorblade
Copy link
Contributor

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.

@odersky
Copy link
Contributor

odersky commented Dec 25, 2019

Superseded by #7850

@odersky odersky closed this Dec 25, 2019
odersky added a commit to dotty-staging/dotty that referenced this pull request Dec 26, 2019
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Lazy enums.
4 participants