Skip to content

Commit 58a4cc3

Browse files
authored
Merge pull request #2498 from dotty-staging/add-reference-1
Reference sections for some of the new things in Dotty
2 parents 11476d1 + 8013ea4 commit 58a4cc3

20 files changed

+960
-3
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,18 @@ object desugar {
431431
// For all other classes, the parent is AnyRef.
432432
val companions =
433433
if (isCaseClass) {
434+
def extractType(t: Tree): Tree = t match {
435+
case Apply(t1, _) => extractType(t1)
436+
case TypeApply(t1, ts) => AppliedTypeTree(extractType(t1), ts)
437+
case Select(t1, nme.CONSTRUCTOR) => extractType(t1)
438+
case New(t1) => t1
439+
case t1 => t1
440+
}
434441
// The return type of the `apply` method
435442
val applyResultTpt =
436443
if (isEnumCase)
437444
if (parents.isEmpty) enumClassTypeRef
438-
else parents.reduceLeft(AndTypeTree)
445+
else parents.map(extractType).reduceLeft(AndTypeTree)
439446
else TypeTree()
440447

441448
val parent =

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,13 +443,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
443443
tree.tpt match {
444444
case templ: untpd.Template =>
445445
import untpd._
446-
templ.parents foreach {
446+
var templ1 = templ
447+
def isEligible(tp: Type) = tp.exists && !tp.typeSymbol.is(Final)
448+
if (templ1.parents.isEmpty &&
449+
isFullyDefined(pt, ForceDegree.noBottom) &&
450+
isEligible(pt.underlyingClassRef(refinementOK = false)))
451+
templ1 = cpy.Template(templ)(parents = untpd.TypeTree(pt) :: Nil)
452+
templ1.parents foreach {
447453
case parent: RefTree =>
448454
typedAheadImpl(parent, tree => inferTypeParams(typedType(tree), pt))
449455
case _ =>
450456
}
451457
val x = tpnme.ANON_CLASS
452-
val clsDef = TypeDef(x, templ).withFlags(Final)
458+
val clsDef = TypeDef(x, templ1).withFlags(Final)
453459
typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(x), Nil)), pt)
454460
case _ =>
455461
var tpt1 = typedType(tree.tpt)

docs/docs/index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ the code, setup Dotty with your favorite IDE and more!
1414
Contents
1515
-------
1616

17+
* Dotty Language Reference
18+
- [Intersection Types](reference/intersection-types.md)
19+
- [Union Types](reference/union-types.md)
20+
- [Trait Parameters](reference/trait-parameters.md)
21+
- [Enumerations](reference/enums.md)
22+
- [Algebraic Data Types](reference/adts.md)
23+
- [Enum Translation](reference/desugarEnums.md)
24+
- [By-Name Implicits](reference/implicit-by-name-parameters.md)
1725
* Usage
1826
- [Migrating from Scala 2](usage/migrating.md): migration information
1927
- [Dotty projects with cbt](usage/cbt-projects.md): using cbt

docs/docs/reference/adts.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
layout: doc-page
3+
title: "Algebraic Data Types"
4+
---
5+
6+
7+
The `enum` concept is general enough to also support algebraic data
8+
types (ADTs) and their generalized version (GADTs). Here's an example
9+
how an `Option` type can be represented as an ADT:
10+
11+
```scala
12+
enum Option[+T] {
13+
case Some[+T](x: T)
14+
case None
15+
}
16+
```
17+
18+
This example introduces `Option` enum class with a covariant type
19+
parameter `T`, together with two cases, `Some` and `None`. `Some` is
20+
parameterized with a type parameter `T` and a value parameter `x`. It
21+
is a shorthand for writing a case class that extends `Option`. Since
22+
`None` is not parameterized it is treated as a normal enum value.
23+
24+
The `extends` clauses that were omitted in the example above can also
25+
be given explicitly:
26+
27+
```scala
28+
enum Option[+T] {
29+
case Some[+T](x: T) extends Option[T]
30+
case None extends Option[Nothing]
31+
}
32+
```
33+
34+
Note that the parent type of `None` is inferred as
35+
`Option[Nothing]`. Generally, all covariant type parameters of the enum
36+
class are minimized in a compiler-generated extends clause whereas all
37+
contravariant type parameters are maximized. If `Option` was non-variant,
38+
you'd need to give the extends clause of `None` explicitly.
39+
40+
As for normal enum values, the cases of an `enum` are all defined in
41+
the `enum`s companion object. So it's `Option.Some` and `Option.None`
42+
unless the definitions are "pulled out" with an import:
43+
44+
```scala
45+
scala> Option.Some("hello")
46+
val res1: t2.Option[String] = Some(hello)
47+
scala> Option.None
48+
val res2: t2.Option[Nothing] = None
49+
```
50+
51+
Note that the type of the expressions above is always `Option`. That
52+
is, the implementation case classes are not visible in the result
53+
types of their `apply` methods. This is a subtle difference with
54+
respect to normal case classes. The classes making up the cases do
55+
exist, and can be unvealed by constructing them directly with a `new`.
56+
57+
```scala
58+
val res3: t2.Option.Some[Int] = Some(2)
59+
scala> scala> new Option.Some(2)
60+
```
61+
62+
As all other enums, ADTs can have methods on both the enum class and
63+
its companion object. For instance, here is `Option` again, with an
64+
`isDefined` method and an `Option(...)` constructor.
65+
66+
```scala
67+
enum class Option[+T] {
68+
def isDefined: Boolean
69+
}
70+
object Option {
71+
def apply[T >: Null](x: T): Option[T] =
72+
if (x == null) None else Some(x)
73+
74+
case Some[+T](x: T) {
75+
def isDefined = true
76+
}
77+
case None {
78+
def isDefined = false
79+
}
80+
}
81+
```
82+
83+
Enumerations and ADTs have been presented as two different
84+
concepts. But since they share the same syntactic construct, they can
85+
be seen simply as two ends of a spectrum and it is perfectly possible
86+
to conctruct hybrids. For instance, the code below gives an
87+
implementation of `Color` either with three enum values or with a
88+
parameterized case that takes an RGB value.
89+
90+
```scala
91+
enum Color(val rgb: Int) {
92+
case Red extends Color(0xFF0000)
93+
case Green extends Color(0x00FF00)
94+
case Blue extends Color(0x0000FF)
95+
case Mix(mix: Int) extends Color(mix)
96+
}
97+
```
98+
99+
## Syntax of Enums
100+
101+
Changes to the syntax fall in two categories: enum classes and cases inside enums.
102+
The changes are specified below as deltas with respect to the Scala syntax given [here](https://github.com/lampepfl/dotty/blob/master/docs/docs/internals/syntax.md)
103+
104+
1. Enum definitions and enum classes are defined as follows:
105+
106+
TmplDef ::= `enum' `class’ ClassDef
107+
| `enum' EnumDef
108+
EnumDef ::= id ClassConstr [`extends' [ConstrApps]]
109+
[nl] `{’ EnumCaseStat {semi EnumCaseStat} `}’
110+
111+
2. Cases of enums are defined as follows:
112+
113+
EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase
114+
EnumCase ::= `case' (EnumClassDef | ObjectDef | ids)
115+
EnumClassDef ::= id [ClsTpeParamClause | ClsParamClause]
116+
ClsParamClauses TemplateOpt
117+
TemplateStat ::= ... | EnumCaseStat
118+
119+
120+
121+
122+

docs/docs/reference/desugarEnums.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
---
2+
layout: doc-page
3+
title: "Translation of Enums and ADTs"
4+
---
5+
6+
The compiler expands enum classes and cases to code that only uses
7+
Scala's other language features. As such, enums in Scala are
8+
convenient _syntactic sugar_, but they are not essential to understand
9+
Scala's core.
10+
11+
We now explain the expansion of enums is explained in detail. First,
12+
some terminology and notational conventions:
13+
14+
- We use `E` as a name of an enum class, and `C` as a name of an enum case that appears in the companion object of `E`.
15+
- We use `<...>` for syntactic constructs that in some circumstances might be empty. For instance `<body>` represents either the body of a case between `{...}` or nothing at all.
16+
17+
- Enum cases fall into three categories:
18+
19+
- _Class cases_ are those cases that are parameterized, either with a type parameter section `[...]` or with one or more (possibly empty) parameter sections `(...)`.
20+
- _Simple cases_ are cases of a non-generic enum class that have neither parameters nor an extends clause or body. That is, they consist of a name only.
21+
- _Value cases_ are all cases that do not have a parameter section but that do have a (possibly generated) extends clause and/or a body.
22+
23+
Simple cases and value cases are called collectively _singleton cases_.
24+
25+
The desugaring rules imply that class cases are mapped to case classes, and singleton cases are mapped to `val` definitions.
26+
27+
There are eight desugaring rules. Rules (1) and (2) desugar enums and
28+
enum classes. Rules (3) and (4) define extends clauses for cases that
29+
are missing them. Rules (5 - 7) define how such expanded cases map
30+
into case classes, case objects or vals. Finally, rule (8) expands
31+
comma separated simple cases into a sequence of cases.
32+
33+
1. An `enum` definition
34+
35+
enum E ... { <cases> }
36+
37+
expands to an enum class and a companion object
38+
39+
enum class E ...
40+
object E { <cases> }
41+
42+
2. An enum class definition
43+
44+
enum class E ... extends <parents> ...
45+
46+
expands to a `sealed` `abstract` class that extends the `scala.Enum` trait:
47+
48+
sealed abstract class E ... extends <parents> with scala.Enum ...
49+
50+
3. If `E` is an enum class without type parameters, then a case in its companion object without an extends clause
51+
52+
case C <params> <body>
53+
54+
expands to
55+
56+
case C <params> <body> extends E
57+
58+
4. If `E` is an enum class with type parameters `Ts`, then a case in its
59+
companion object without an extends clause
60+
61+
case C <params> <body>
62+
63+
expands according to two alternatives, depending whether `C` has type
64+
parameters or not. If `C` has type parameters, they must have the same
65+
names and appear in the same order as the enum type parameters `Ts`
66+
(variances may be different, however). In this case
67+
68+
case C [Ts] <params> <body>
69+
70+
expands to
71+
72+
case C[Ts] <params> extends E[Ts] <body>
73+
74+
For the case where `C` does not have type parameters, assume `E`'s type
75+
parameters are
76+
77+
V1 T1 > L1 <: U1 , ... , Vn Tn >: Ln <: Un (n > 0)
78+
79+
where each of the variances `Vi` is either `'+'` or `'-'`. Then the case
80+
expands to
81+
82+
case C <params> extends E[B1, ..., Bn] <body>
83+
84+
where `Bi` is `Li` if `Vi = '+'` and `Ui` if `Vi = '-'`. It is an error if
85+
`Bi` refers to some other type parameter `Tj (j = 0,..,n-1)`. It is also
86+
an error if `E` has type parameters that are non-variant.
87+
88+
5. A class case
89+
90+
case C <params> ...
91+
92+
expands analogous to a case class:
93+
94+
final case class C <params> ...
95+
96+
However, unlike for a regular case class, the return type of the associated
97+
`apply` method is a fully parameterized type instance of the enum class `E`
98+
itself instead of `C`. Also the enum case defines an `enumTag` method of
99+
the form
100+
101+
def enumTag = n
102+
103+
where `n` is the ordinal number of the case in the companion object,
104+
starting from 0.
105+
106+
6. A value case
107+
108+
case C extends <parents> <body>
109+
110+
expands to a value definition
111+
112+
val C = new <parents> { <body>; def enumTag = n; $values.register(this) }
113+
114+
where `n` is the ordinal number of the case in the companion object,
115+
starting from 0. The statement `$values.register(this)` registers the value
116+
as one of the `enumValues` of the enumeration (see below). `$values` is a
117+
compiler-defined private value in the companion object.
118+
119+
7. A simple case
120+
121+
case C
122+
123+
of an enum class `E` that does not take type parameters expands to
124+
125+
val C = $new(n, "C")
126+
127+
Here, `$new` is a private method that creates an instance of of `E` (see
128+
below).
129+
130+
8. A simple case consisting of a comma-separated list of enum names
131+
132+
case C_1, ..., C_n
133+
134+
expands to
135+
136+
case C_1; ...; case C_n
137+
138+
Any modifiers or annotations on the original case extend to all expanded
139+
cases.
140+
141+
## Translation of Enumerations
142+
143+
Non-generic enum classes `E` that define one or more singleton cases
144+
are called _enumerations_. Companion objects of enumerations define
145+
the following additional members.
146+
147+
- A method `enumValue` of type `scala.collection.immutable.Map[Int, E]`.
148+
`enumValue(n)` returns the singleton case value with ordinal number `n`.
149+
- A method `enumValueNamed` of type `scala.collection.immutable.Map[String, E]`.
150+
`enumValueNamed(s)` returns the singleton case value whose `toString`
151+
representation is `s`.
152+
- A method `enumValues` which returns an `Iterable[E]` of all singleton case
153+
values in `E`, in the order of their definitions.
154+
155+
Companion objects that contain at least one simple case define in addition:
156+
157+
- A private method `$new` which defines a new simple case value with given
158+
ordinal number and name. This method can be thought as being defined as
159+
follows.
160+
161+
def $new(tag: Int, name: String): ET = new E {
162+
def enumTag = tag
163+
def toString = name
164+
$values.register(this) // register enum value so that `valueOf` and `values` can return it.
165+
}

0 commit comments

Comments
 (0)