-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add "enum" construct #1958
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
Add "enum" construct #1958
Conversation
tests/run/enum-Color.scala
Outdated
case Red | ||
case Green | ||
case Blue | ||
} |
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.
Will
enum Color { case Red, Green, Blue }
expand to the equivalent of the above?
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.
Not yet. I was thinking it would be a nice abbreviation, but not decided yet.
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.
enum Color { case Red, Green, Blue }
is the word "case" needed in the abbreviation?
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.
We definitely should keep case
@felixmulder The build failure comes from my changes to how doc comments are treated in Parser. The changes are in b20c1be. I noted a lot of So, we could back out, which is slightly messy but doable. But maybe it's best to go forward instead. Can you make |
I think that originally I wanted to protect from all cases of misuse. E.g: trait T {
/** Cheeky docstring that shouldn't appear in `C` */
}
class C ce40517 is a bit more permissive and allows this misuse... Another alternative to this fix could be to make docstring its own token and attach it as part of the AST, but I guess that would be added complexity to the parser. Update: failing test is |
But if you associate doc comments to start positions of tokens following them, you can do that. The cheeky doc comment would be associated with Re: stdlib I forgot to push a new one. (the old one uses |
+💯
…--
Cheers,
√
On Feb 13, 2017 9:24 AM, "odersky" ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In tests/run/enum-Color.scala
<#1958>:
> @@ -0,0 +1,13 @@
+enum Color {
+ case Red
+ case Green
+ case Blue
+}
We definitely should keep case
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#1958>, or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAAqd8X7-GsxMsflab2gSzqg8ToqpRc0ks5rcBMsgaJpZM4L6s5a>
.
|
Regarding shorthand for simple enums: Instead of
should it rather be:
? That would align it with pattern syntax. |
We now have the syntax
supported. I propose we defer all other todos to separate issues and skip straight to the decision. Do we want to go ahead with this concept? If everyone is still positive, let's review the code and get this in. |
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.
Otherwise, LGTM
ModuleDef(modName, Template(emptyConstructor, Nil, EmptyValDef, body)) | ||
.withMods(mods) | ||
} | ||
Thicket(clsDef :: modDef :: Nil) |
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'm not sure if it's a good idea to do this inside parser.
When we introduce macros, we do have multiple level desugaring (expansion) in Namer. And as we already have all the facility to support multiple level desugaring, I think we probably should use that. I've done some changes in Namer to support multiple-level desugaring can be seen here. It seems a flatten
method is all that's needed.
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 tried multi-level expansion first, including flattening, but it did not work. Essentially the compiler got confused with symbol attachments and I did not find a good way around it.
val result = flatTree(cdef1 :: companions ::: implicitWrappers) | ||
//if (isEnum) println(i"enum $cdef\n --->\n$result") | ||
//if (isEnumCase) println(i"enum case $cdef\n --->\n$result") | ||
result |
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.
A little cleanup is required here.
// todo: also use anyRef if constructor has a dependent method type (or rule that out)! | ||
else (constrVparamss :\ classTypeRef) ((vparams, restpe) => Function(vparams map (_.tpt), restpe)) | ||
(constrVparamss :\ (if (isEnumCase) applyResultTpt else classTypeRef)) ( | ||
(vparams, restpe) => Function(vparams map (_.tpt), restpe)) |
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 may miss some point here, it seems to me the fold is useless here, because constrVparamss
can only be of size 0?
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.
size 0 or 1
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.
size 0 or 1, actually.
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.
Ah, I see, thanks, obviously I've some problems with basic math :)
val originalTparams = | ||
if (isEnumCase && parents.isEmpty) { | ||
if (constr1.tparams.nonEmpty) | ||
ctx.error(em"case with type parameters needs extends clause", constr1.tparams.head.pos) |
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.
What if the parent takes no type parameters, while the child has type parameters, like the following case:
enum Base {
case Bar[T](x: T)
}
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.
Good point. An example for this are HLists:
enum HList {
case HCons[Hd, Tl](hd: Hd, tl: Tl)
case HNil
}
I think we want to allow this.
Rebased to master |
Insert an empty line before "where" in an explanation.
Modify syntax.md and Tokens/Parser/untpd to support enums.
It's completely redundant, docstring is just the comment found at the `start` offset, which is passed anyway.
`enum' only allowed as a prefix of classes, dropped from traits and objects.
The previous scheme did not work because desugaring cannot deal with repeated expansions. We now sidestep the issue by doing the expansion in the parser. Luckily, positions work out perfectly, so that one can reconstruct the source precisely from the parsed untyped trees.
In case of difference, dump transcript to file for easier comparisons.
Flags like Trait are in fact not always defined when a symbol is created. For symbols loaded from class files, this flag, and some other is defined only once the classfile has been loaded. But this happens in general before the symbol is completed. We model this distinction by separating from the `FromStartFlags` set a new set `AfterLoadFlags` and distinguishing between the two sets in `SymDenotations#is`. Test case is enum-Option.scala. This erroneously complained before that `Enum` was not a trait.
`copy` should always return the type of it's rhs. The discussion of scala#1970 concluded that no special treatment for enums is needed.
In an enum case like case C() extends P1 with ... with Pn ... apply now returns `P1 & ... & Pn`, where before it was just P1. Also, add to Option test.
Based on the discussion in scala#1970, enumeration objects now have three public members: - valueOf: Map[Int, E] - withName: Map[String, E] - values: Iterable[E] Also, the variance of case type parameters is now the same as in the corresponding type parameter of the enum class.
Support cases with type parameters that implicitly extend a non-parameterized base without needing their own extends clause. The proposal has been updated to make clear that this is supported. Also address other reviewers comments.
Previous expansion caused 3 spurious follow-on errors which are now avoided.
This commit can hopefully be reverted once scala#2121 is in.
Infer type arguments for enum paraments from corresponding type parameter bounds. This only works if the type parameter in question is variant and its bound is ground.
- rename utility methods - generate utility methods also for object cases
As far is I'm concerned we are done for this part. We already had a review by @liufengyun but if people want to review either everything or just the later commits please assign to yourself as reviewer. |
One thing missing is exhaustivity check, which can be done in another PR. According to our current algorithm, as long as the parent class symbol carries a list of children symbols (case vals and case classes), the algorithm will be able to handle. My concern here is that in parser, it's clear what the children are, and it's easy to get them. But after desugaring, it seems to require a lot of assumptions about desugaring in order to recover that information. |
This is a prototype implementation to add an "enum" construct to Scala. Scala enums give a more concise notation for
A specification of what's implemented is provided by #1970.
Current status:
If we want to go ahead with this, the following todos should be broken out as separate issues.
what we want from the compiler