diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index cb137d46476a..b7de824d2952 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -431,11 +431,18 @@ object desugar {
// For all other classes, the parent is AnyRef.
val companions =
if (isCaseClass) {
+ def extractType(t: Tree): Tree = t match {
+ case Apply(t1, _) => extractType(t1)
+ case TypeApply(t1, ts) => AppliedTypeTree(extractType(t1), ts)
+ case Select(t1, nme.CONSTRUCTOR) => extractType(t1)
+ case New(t1) => t1
+ case t1 => t1
+ }
// The return type of the `apply` method
val applyResultTpt =
if (isEnumCase)
if (parents.isEmpty) enumClassTypeRef
- else parents.reduceLeft(AndTypeTree)
+ else parents.map(extractType).reduceLeft(AndTypeTree)
else TypeTree()
val parent =
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 644bcd7cbe0a..7df0f0dc4437 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -443,13 +443,19 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
tree.tpt match {
case templ: untpd.Template =>
import untpd._
- templ.parents foreach {
+ var templ1 = templ
+ def isEligible(tp: Type) = tp.exists && !tp.typeSymbol.is(Final)
+ if (templ1.parents.isEmpty &&
+ isFullyDefined(pt, ForceDegree.noBottom) &&
+ isEligible(pt.underlyingClassRef(refinementOK = false)))
+ templ1 = cpy.Template(templ)(parents = untpd.TypeTree(pt) :: Nil)
+ templ1.parents foreach {
case parent: RefTree =>
typedAheadImpl(parent, tree => inferTypeParams(typedType(tree), pt))
case _ =>
}
val x = tpnme.ANON_CLASS
- val clsDef = TypeDef(x, templ).withFlags(Final)
+ val clsDef = TypeDef(x, templ1).withFlags(Final)
typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(x), Nil)), pt)
case _ =>
var tpt1 = typedType(tree.tpt)
diff --git a/docs/docs/index.md b/docs/docs/index.md
index d4661a497503..b2c1f1b5dfc0 100644
--- a/docs/docs/index.md
+++ b/docs/docs/index.md
@@ -14,6 +14,14 @@ the code, setup Dotty with your favorite IDE and more!
Contents
-------
+* Dotty Language Reference
+ - [Intersection Types](reference/intersection-types.md)
+ - [Union Types](reference/union-types.md)
+ - [Trait Parameters](reference/trait-parameters.md)
+ - [Enumerations](reference/enums.md)
+ - [Algebraic Data Types](reference/adts.md)
+ - [Enum Translation](reference/desugarEnums.md)
+ - [By-Name Implicits](reference/implicit-by-name-parameters.md)
* Usage
- [Migrating from Scala 2](usage/migrating.md): migration information
- [Dotty projects with cbt](usage/cbt-projects.md): using cbt
diff --git a/docs/docs/reference/adts.md b/docs/docs/reference/adts.md
new file mode 100644
index 000000000000..9c4f83a6db93
--- /dev/null
+++ b/docs/docs/reference/adts.md
@@ -0,0 +1,122 @@
+---
+layout: doc-page
+title: "Algebraic Data Types"
+---
+
+
+The `enum` concept is general enough to also support algebraic data
+types (ADTs) and their generalized version (GADTs). Here's an example
+how an `Option` type can be represented as an ADT:
+
+```scala
+enum Option[+T] {
+ case Some[+T](x: T)
+ case None
+}
+```
+
+This example introduces `Option` enum class with a covariant type
+parameter `T`, together with two cases, `Some` and `None`. `Some` is
+parameterized with a type parameter `T` and a value parameter `x`. It
+is a shorthand for writing a case class that extends `Option`. Since
+`None` is not parameterized it is treated as a normal enum value.
+
+The `extends` clauses that were omitted in the example above can also
+be given explicitly:
+
+```scala
+enum Option[+T] {
+ case Some[+T](x: T) extends Option[T]
+ case None extends Option[Nothing]
+}
+```
+
+Note that the parent type of `None` is inferred as
+`Option[Nothing]`. Generally, all covariant type parameters of the enum
+class are minimized in a compiler-generated extends clause whereas all
+contravariant type parameters are maximized. If `Option` was non-variant,
+you'd need to give the extends clause of `None` explicitly.
+
+As for normal enum values, the cases of an `enum` are all defined in
+the `enum`s companion object. So it's `Option.Some` and `Option.None`
+unless the definitions are "pulled out" with an import:
+
+```scala
+scala> Option.Some("hello")
+val res1: t2.Option[String] = Some(hello)
+scala> Option.None
+val res2: t2.Option[Nothing] = None
+```
+
+Note that the type of the expressions above is always `Option`. That
+is, the implementation case classes are not visible in the result
+types of their `apply` methods. This is a subtle difference with
+respect to normal case classes. The classes making up the cases do
+exist, and can be unvealed by constructing them directly with a `new`.
+
+```scala
+val res3: t2.Option.Some[Int] = Some(2)
+scala> scala> new Option.Some(2)
+```
+
+As all other enums, ADTs can have methods on both the enum class and
+its companion object. For instance, here is `Option` again, with an
+`isDefined` method and an `Option(...)` constructor.
+
+```scala
+enum class Option[+T] {
+ def isDefined: Boolean
+}
+object Option {
+ def apply[T >: Null](x: T): Option[T] =
+ if (x == null) None else Some(x)
+
+ case Some[+T](x: T) {
+ def isDefined = true
+ }
+ case None {
+ def isDefined = false
+ }
+}
+```
+
+Enumerations and ADTs have been presented as two different
+concepts. But since they share the same syntactic construct, they can
+be seen simply as two ends of a spectrum and it is perfectly possible
+to conctruct hybrids. For instance, the code below gives an
+implementation of `Color` either with three enum values or with a
+parameterized case that takes an RGB value.
+
+```scala
+enum Color(val rgb: Int) {
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+ case Mix(mix: Int) extends Color(mix)
+}
+```
+
+## Syntax of Enums
+
+Changes to the syntax fall in two categories: enum classes and cases inside enums.
+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)
+
+ 1. Enum definitions and enum classes are defined as follows:
+
+ TmplDef ::= `enum' `class’ ClassDef
+ | `enum' EnumDef
+ EnumDef ::= id ClassConstr [`extends' [ConstrApps]]
+ [nl] `{’ EnumCaseStat {semi EnumCaseStat} `}’
+
+2. Cases of enums are defined as follows:
+
+ EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase
+ EnumCase ::= `case' (EnumClassDef | ObjectDef | ids)
+ EnumClassDef ::= id [ClsTpeParamClause | ClsParamClause]
+ ClsParamClauses TemplateOpt
+ TemplateStat ::= ... | EnumCaseStat
+
+
+
+
+
diff --git a/docs/docs/reference/desugarEnums.md b/docs/docs/reference/desugarEnums.md
new file mode 100644
index 000000000000..c07d08d37d56
--- /dev/null
+++ b/docs/docs/reference/desugarEnums.md
@@ -0,0 +1,165 @@
+---
+layout: doc-page
+title: "Translation of Enums and ADTs"
+---
+
+The compiler expands enum classes and cases to code that only uses
+Scala's other language features. As such, enums in Scala are
+convenient _syntactic sugar_, but they are not essential to understand
+Scala's core.
+
+We now explain the expansion of enums is explained in detail. First,
+some terminology and notational conventions:
+
+ - 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`.
+ - We use `<...>` for syntactic constructs that in some circumstances might be empty. For instance `
` represents either the body of a case between `{...}` or nothing at all.
+
+ - Enum cases fall into three categories:
+
+ - _Class cases_ are those cases that are parameterized, either with a type parameter section `[...]` or with one or more (possibly empty) parameter sections `(...)`.
+ - _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.
+ - _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.
+
+ Simple cases and value cases are called collectively _singleton cases_.
+
+The desugaring rules imply that class cases are mapped to case classes, and singleton cases are mapped to `val` definitions.
+
+There are eight desugaring rules. Rules (1) and (2) desugar enums and
+enum classes. Rules (3) and (4) define extends clauses for cases that
+are missing them. Rules (5 - 7) define how such expanded cases map
+into case classes, case objects or vals. Finally, rule (8) expands
+comma separated simple cases into a sequence of cases.
+
+1. An `enum` definition
+
+ enum E ... { }
+
+ expands to an enum class and a companion object
+
+ enum class E ...
+ object E { }
+
+2. An enum class definition
+
+ enum class E ... extends ...
+
+ expands to a `sealed` `abstract` class that extends the `scala.Enum` trait:
+
+ sealed abstract class E ... extends with scala.Enum ...
+
+3. If `E` is an enum class without type parameters, then a case in its companion object without an extends clause
+
+ case C
+
+ expands to
+
+ case C extends E
+
+4. If `E` is an enum class with type parameters `Ts`, then a case in its
+ companion object without an extends clause
+
+ case C
+
+ expands according to two alternatives, depending whether `C` has type
+ parameters or not. If `C` has type parameters, they must have the same
+ names and appear in the same order as the enum type parameters `Ts`
+ (variances may be different, however). In this case
+
+ case C [Ts]
+
+ expands to
+
+ case C[Ts] extends E[Ts]
+
+ For the case where `C` does not have type parameters, assume `E`'s type
+ parameters are
+
+ V1 T1 > L1 <: U1 , ... , Vn Tn >: Ln <: Un (n > 0)
+
+ where each of the variances `Vi` is either `'+'` or `'-'`. Then the case
+ expands to
+
+ case C extends E[B1, ..., Bn]
+
+ where `Bi` is `Li` if `Vi = '+'` and `Ui` if `Vi = '-'`. It is an error if
+ `Bi` refers to some other type parameter `Tj (j = 0,..,n-1)`. It is also
+ an error if `E` has type parameters that are non-variant.
+
+5. A class case
+
+ case C ...
+
+ expands analogous to a case class:
+
+ final case class C ...
+
+ However, unlike for a regular case class, the return type of the associated
+ `apply` method is a fully parameterized type instance of the enum class `E`
+ itself instead of `C`. Also the enum case defines an `enumTag` method of
+ the form
+
+ def enumTag = n
+
+ where `n` is the ordinal number of the case in the companion object,
+ starting from 0.
+
+6. A value case
+
+ case C extends
+
+ expands to a value definition
+
+ val C = new { ; def enumTag = n; $values.register(this) }
+
+ where `n` is the ordinal number of the case in the companion object,
+ starting from 0. The statement `$values.register(this)` registers the value
+ as one of the `enumValues` of the enumeration (see below). `$values` is a
+ compiler-defined private value in the companion object.
+
+7. A simple case
+
+ case C
+
+ of an enum class `E` that does not take type parameters expands to
+
+ val C = $new(n, "C")
+
+ Here, `$new` is a private method that creates an instance of of `E` (see
+ below).
+
+8. A simple case consisting of a comma-separated list of enum names
+
+ case C_1, ..., C_n
+
+ expands to
+
+ case C_1; ...; case C_n
+
+ Any modifiers or annotations on the original case extend to all expanded
+ cases.
+
+## Translation of Enumerations
+
+Non-generic enum classes `E` that define one or more singleton cases
+are called _enumerations_. Companion objects of enumerations define
+the following additional members.
+
+ - A method `enumValue` of type `scala.collection.immutable.Map[Int, E]`.
+ `enumValue(n)` returns the singleton case value with ordinal number `n`.
+ - A method `enumValueNamed` of type `scala.collection.immutable.Map[String, E]`.
+ `enumValueNamed(s)` returns the singleton case value whose `toString`
+ representation is `s`.
+ - A method `enumValues` which returns an `Iterable[E]` of all singleton case
+ values in `E`, in the order of their definitions.
+
+Companion objects that contain at least one simple case define in addition:
+
+ - A private method `$new` which defines a new simple case value with given
+ ordinal number and name. This method can be thought as being defined as
+ follows.
+
+ def $new(tag: Int, name: String): ET = new E {
+ def enumTag = tag
+ def toString = name
+ $values.register(this) // register enum value so that `valueOf` and `values` can return it.
+ }
diff --git a/docs/docs/reference/enums.md b/docs/docs/reference/enums.md
new file mode 100644
index 000000000000..795c0d6210a1
--- /dev/null
+++ b/docs/docs/reference/enums.md
@@ -0,0 +1,139 @@
+---
+layout: doc-page
+title: "Enumerations"
+---
+
+An enumeration is used to define a type consisting of a set of named values.
+
+```scala
+enum Color {
+ case Red, Green, Blue
+}
+```
+
+This defines a new `sealed` class, `Color`, with three values, `Color.Red`,
+`Color.Green`, `Color.Blue`. The color values are members of `Color`s
+companion object. The `Color` definition above is equivalent to the
+following more explicit definition of an _enum class_ and a companion
+object:
+
+```scala
+enum class Color
+object Color {
+ case Red
+ case Green
+ case Blue
+}
+```
+
+## Parameterized enums
+
+Enum classes can be parameterized.
+
+```scala
+enum Color(val rgb: Int) {
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+}
+```
+
+As the example shows, you can define the parameter value by using an
+explicit extends clause.
+
+## Methods defined for enums
+
+The values of an enum correspond to unique integers. The integer
+associated with an enum value is returned by its `enumTag` method:
+
+```scala
+scala> val red = Color.Red
+val red: Color = Red
+scala> red.enumTag
+val res0: Int = 0
+```
+
+The companion object of an enum class also defines three utility methods.
+The `enumValue` and `enumValueNamed` methods obtain an enum value
+by its tag or its name. The `enumValues` method returns all enum values
+defined in an enumeration in an `Iterable`.
+
+```scala
+scala> Color.enumValue(1)
+val res1: Color = Green
+scala> Color.enumValueNamed("Blue")
+val res2: Color = Blue
+scala> Color.enumValues
+val res3: collection.Iterable[Color] = MapLike(Red, Green, Blue)
+```
+
+## User-defined members of enums
+
+It is possible to add your own definitions to an enum class or its
+companion object. To make clear what goes where you need to use the
+longer syntax which defines an enum class alongside its companion
+object explicitly. In the following example, we define some methods in
+class `Planet` and a `main` method in its companion object.
+
+```scala
+enum class Planet(mass: Double, radius: Double) {
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+}
+
+object Planet {
+ case MERCURY extends Planet(3.303e+23, 2.4397e6)
+ case VENUS extends Planet(4.869e+24, 6.0518e6)
+ case EARTH extends Planet(5.976e+24, 6.37814e6)
+ case MARS extends Planet(6.421e+23, 3.3972e6)
+ case JUPITER extends Planet(1.9e+27, 7.1492e7)
+ case SATURN extends Planet(5.688e+26, 6.0268e7)
+ case URANUS extends Planet(8.686e+25, 2.5559e7)
+ case NEPTUNE extends Planet(1.024e+26, 2.4746e7)
+
+ def main(args: Array[String]) = {
+ val earthWeight = args(0).toDouble
+ val mass = earthWeight/EARTH.surfaceGravity
+ for (p <- enumValues)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+ }
+}
+```
+
+## Implementation
+
+Enum classes are represented as `sealed` classes that extend the `scala.Enum` trait.
+This trait defines a single method, `enumTag`:
+
+```scala
+package scala
+
+/** A base trait of all enum classes */
+trait Enum {
+
+ /** A number uniquely identifying a case of an enum */
+ def enumTag: Int
+}
+```
+
+Enum values with `extends` clauses get expanded to anonymus class instances.
+For instance, the `VENUS` value above would be defined like this:
+
+```scala
+val VENUS: Planet =
+ new Planet(4.869E24, 6051800.0) {
+ def enumTag: Int = 1
+ override def toString: String = "VENUS"
+ // internal code to register value
+ }
+```
+
+Enum values without `extends` clauses all share a single implementation
+that can be instantiated using a private method that takes a tag and a name as arguments.
+For instance, the first
+definition of value `Color.Red` above would expand to:
+
+```scala
+val Red: Color = $new(0, "Red")
+```
diff --git a/docs/docs/reference/implicit-by-name-parameters.md b/docs/docs/reference/implicit-by-name-parameters.md
new file mode 100644
index 000000000000..af341fb982ee
--- /dev/null
+++ b/docs/docs/reference/implicit-by-name-parameters.md
@@ -0,0 +1,64 @@
+---
+layout: doc-page
+title: "Implicit By-Name Parameters"
+---
+
+Call-by-name implicit parameters can be used to avoid a divergent implicit expansion.
+
+```scala
+trait Codec[T] {
+ def write(x: T): Unit
+}
+
+implicit def intCodec: Codec[Int] = ???
+
+implicit def optionCodec[T]
+ (implicit ev: => Codec[T]): Codec[Option[T]] =
+ new {
+ def write(xo: Option[T]) = xo match {
+ case Some(x) => ev.write(x)
+ case None =>
+ }
+ }
+
+val s = implicitly[Codec[Option[Int]]]
+
+s.write(Some(33))
+s.write(None)
+```
+As is the case for a normal by-name parameter, the argument for the implicit parameter `ev`
+is evaluated on demand. In the example above, if the option value `x` is `None`, it is
+not evaluated at all.
+
+The synthesized argument for an implicit parameter is backed by a lazy
+val if this is necessary to prevent an otherwise diverging expansion.
+
+The precise steps for constructing an implicit argument for a by-name parameter of type `=> T` are as follows.
+
+ 1. Create a new implicit value with a fresh name _lv_, which has the signature of the following definition:
+
+ ```scala
+ implicit lazy val lv: T
+ ```
+
+ The current implementation uses the prefix `$lazy_implicit$` followed by a unique integer for _lv_.
+
+ 1. This lazy val is not immediately available as candidate for implicit search (making it immediately available would result in a looping implicit computation). But it becomes available in all nested contexts that look again for an implicit argument to a by-name parameter.
+
+ 1. If this implicit search succeeds with expression `E`, and `E` contains references to the lazy implicit value _lv_, replace `E` by
+
+
+ ```scala
+ { implicit lazy val lv: T = E; lv }
+ ```
+
+ Otherwise, return `E` unchanged.
+
+In the example above, the definition of `s` would be expanded as follows.
+
+```scala
+val s = implicitly[Test.Codec[Option[Int]]](
+ optionCodec[Int](intCodec))
+```
+
+No lazy val was generated because the synthesized argument is not recursive.
diff --git a/docs/docs/reference/intersection-types.md b/docs/docs/reference/intersection-types.md
new file mode 100644
index 000000000000..256fefa9742c
--- /dev/null
+++ b/docs/docs/reference/intersection-types.md
@@ -0,0 +1,65 @@
+---
+layout: doc-page
+title: "Intersection Types"
+---
+
+Used on types, the `&` operator creates an intersection type.
+
+```scala
+trait Resetable {
+ def reset(): this.type
+}
+trait Growable[T] {
+ def add(x: T): this.type
+}
+def f(x: Resetable & Growable[String]) = {
+ x.reset()
+ x.add("first")
+}
+```
+
+The value `x` is required to be _both_ a `Resetable` and a
+`Growable[String]`. Intersection types `A & B` replace compound types
+`A with B` in Scala 2 (for the moment, `A with B` is still allowed, but
+it will be deprecated and removed in the future).
+
+Unlike `with` types, `&` is _commutative_: `A & B` is the same type as
+`B & A`.
+
+The members of an intersection type `A & B` are all the members of `A`
+and all the members of `B`. For instance `Resetable & Growable[String]`
+has member methods `reset` and `add`.
+
+If a member appears in both `A` and `B`, its type in `A & B` is the
+intersection of its type in `A` and its type in `B`. For instance, assume the definitions:
+
+```scala
+trait A {
+ def children: List[A]
+}
+trait B {
+ def children: List[B]
+}
+val x: A & B = new C
+val ys: List[A & B] = x.children
+```
+
+The type of `children` in `A & B` is the intersection of `children`'s
+type in `A` and its type in `B`, which is `List[A] & List[B]`. This
+can be further simplified to `List[A & B]` because `List` is
+covariant.
+
+One might wonder how the compiler could come up with a definition for
+`children` of type `List[A & B]` since all its is given are `children`
+definitions of type `List[A]` and `List[B]`. The answer is it does not
+need to. `A & B` is just a type that represents a set of requirements for
+values of the type. At the point where a value is _constructed_, one
+must make sure that all inherited members are correctly defined.
+So if one defines a class `C` that inherits `A` and `B`, one needs
+to give at that point a definition of a `children` method with the required type.
+
+```scala
+class C extends A with B {
+ def children: List[A & B] = ???
+}
+```
diff --git a/docs/docs/reference/trait-parameters.md b/docs/docs/reference/trait-parameters.md
new file mode 100644
index 000000000000..62415e57f800
--- /dev/null
+++ b/docs/docs/reference/trait-parameters.md
@@ -0,0 +1,58 @@
+---
+layout: doc-page
+title: "Trait Parameters"
+---
+
+Dotty allows traits to have parameters, just like classes have parameters.
+
+```scala
+trait Greeting(val name: String) {
+ def msg = s"How are you, $name"
+}
+
+class C extends Greeting("Bob") {
+ println(msg)
+}
+```
+
+Arguments to a trait are evaluated immediately before the trait is initialized.
+
+One potential issue with trait parameters is how to prevent
+ambiguities. For instance, you might try to extend `Greeting` twice,
+with different parameters.
+
+```scala
+/*!*/ class D extends C with Greeting("Bill") // error: parameters passed twice
+```
+
+Should this print "Bob" or "Bill"? In fact this program is illegal,
+because it violates one of the following rules for trait parameters:
+
+ 1. If a class `C` extends a parameterized trait `T`, and its superclass does not, `C` _must_ pass arguments to `T`.
+
+ 2. If a class `C` extends a parameterized trait `T`, and its superclass does as well, `C` _may not_ pass arguments to `T`.
+
+ 3. Traits may never pass arguments to parent traits.
+
+Here's a trait extending the parameterized trait `Greeting`.
+
+```scala
+trait FormalGreeting extends Greeting {
+ override def msg = s"How do you do, $name"
+}
+```
+As is required, no arguments are passed to `Greeting`. However, this poses an issue
+when defining a class that extends `FormalGreeting`:
+
+```scala
+/*!*/ class E extends FormalGreeting // error: missing arguments for `Greeting`.
+```
+
+The correct way to write `E` is to extend both `Greeting` and
+`FormalGreeting` (in either order):
+
+```scala
+class E extends Greeting("Bob") with FormalGreeting
+```
+
+
diff --git a/docs/docs/reference/union-types.md b/docs/docs/reference/union-types.md
new file mode 100644
index 000000000000..14890d514331
--- /dev/null
+++ b/docs/docs/reference/union-types.md
@@ -0,0 +1,57 @@
+---
+layout: doc-page
+title: "Union Types"
+---
+
+Used on types, the `|` operator creates a union type.
+
+```scala
+case class UserName(name: String) {
+ def lookup(admin: Admin): UserData
+}
+case class Password(hash: Hash) {
+ def lookup(admin: Admin): UserData
+}
+
+def help(id: UserName | PassWord) = {
+ val user = id match {
+ case UserName(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ }
+ // ...
+}
+```
+
+Union types are dual of intersection types. Values of type `A | B` are
+all values of type `A` and all values of type `B`. `|` is _commutative_:
+`A | B` is the same type as `B | A`.
+
+The compiler will assign an expression a union type only if such a
+type is explicitly given.
+This can be seen in the folling REPL
+transcript:
+
+```scala
+scala> val password = Password(123)
+val password: Password = Password(123)
+scala> val name = UserName("Eve")
+val name: UserName = UserName(Eve)
+scala> if (true) name else password
+val res2: Object & Product = UserName(Eve)
+scala> val either: Password | UserName = if (true) name else password
+val either: Password | UserName = UserName(Eve)
+```
+
+The type of `res2` is `Object | Product`, which is a supertype of
+`UserName` and `Product`, but not the least supertype `Password |
+UserName`. If we want the least supertype, we have to give it
+explicitely, as is done for the type of `Either`. More precisely, the
+typechecker will _widen_ a union type to a non-union type when
+inferring the type of `val` or `var`, or the result type of a `def`,
+or the argument to pass for a type parameter. The widened type of `A
+| B` is usually the intersection of all class or trait types that are
+supertypes of both `A` and `B`; it does not include any refinements.
+Union types are in that sense analogous to singleton types `x.type`
+which are also widened to their underlying type unless explicitly
+specified.
+
diff --git a/docs/sidebar.yml b/docs/sidebar.yml
index 90e950134636..bf7e48153190 100644
--- a/docs/sidebar.yml
+++ b/docs/sidebar.yml
@@ -1,6 +1,22 @@
sidebar:
- title: Blog
url: blog/index.html
+ - title: Reference
+ subsection:
+ - title: Intersection types
+ url: docs/reference/intersection-types.html
+ - title: Union types
+ url: docs/reference/union-types.html
+ - title: Trait Parameters
+ url: docs/reference/trait-parameters.html
+ - title: Enumerations
+ url: docs/reference/enums.html
+ - title: Algebraic Data Types
+ url: docs/reference/adts.html
+ - title: Enum Translation
+ url: docs/reference/desugarEnums.html
+ - title: By-Name Implicits
+ url: docs/reference/implicit-by-name-parameters.html
- title: Usage
subsection:
- title: cbt-projects
diff --git a/tests/pos/intersection.scala b/tests/pos/intersection.scala
index d2e445dbafb0..faf9af401d58 100644
--- a/tests/pos/intersection.scala
+++ b/tests/pos/intersection.scala
@@ -15,4 +15,10 @@ object intersection {
type needsA = A => Nothing
type needsB = B => Nothing
+
+
+ class C[-T]
+ def f: C[A] & C[B] = ???
+ def g: C[A | B] = f
+ def h: C[A] & C[B] = g
}
diff --git a/tests/pos/news.scala b/tests/pos/news.scala
new file mode 100644
index 000000000000..2825044546e1
--- /dev/null
+++ b/tests/pos/news.scala
@@ -0,0 +1,10 @@
+object Test {
+
+ abstract class C[T] { def f: T }
+
+ val x: C[Int] = new { def f = 2 }
+
+ val y = new { val name = "Bob" }
+
+
+}
diff --git a/tests/pos/objXfun.scala b/tests/pos/objXfun.scala
new file mode 100644
index 000000000000..c05a08d9ba41
--- /dev/null
+++ b/tests/pos/objXfun.scala
@@ -0,0 +1,8 @@
+object Foo extends (Int => Int) { // OK
+ def apply(x: Int) = x
+}
+
+enum class E(x: Int) // used to generate Int => new E(x) as the parent of object E --> crash
+object E {
+ case C(x: Int) extends E(x)
+}
diff --git a/tests/pos/reference/adts.scala b/tests/pos/reference/adts.scala
new file mode 100644
index 000000000000..6fc670ada71b
--- /dev/null
+++ b/tests/pos/reference/adts.scala
@@ -0,0 +1,45 @@
+package adts
+object t1 {
+
+enum Option[+T] {
+ case Some[T](x: T)
+ case None
+}
+
+}
+
+object t2 {
+
+enum Option[+T] {
+ case Some[T](x: T) extends Option[T]
+ case None extends Option[Nothing]
+}
+
+
+}
+
+enum Color(val rgb: Int) {
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+ case Mix(mix: Int) extends Color(mix)
+}
+
+object t3 {
+
+enum class Option[+T] {
+ def isDefined: Boolean
+}
+object Option {
+ def apply[T >: Null](x: T): Option[T] =
+ if (x == null) None else Some(x)
+
+ case Some[+T](x: T) {
+ def isDefined = true
+ }
+ case None {
+ def isDefined = false
+ }
+}
+
+}
diff --git a/tests/pos/reference/enums.scala b/tests/pos/reference/enums.scala
new file mode 100644
index 000000000000..1db1b055d9b0
--- /dev/null
+++ b/tests/pos/reference/enums.scala
@@ -0,0 +1,66 @@
+package enums
+
+object t1 {
+
+enum Color {
+ case Red, Green, Blue
+}
+
+}
+
+object t2 {
+
+enum class Color
+object Color {
+ case Red
+ case Green
+ case Blue
+}
+
+}
+
+object t3 {
+
+enum class Color(val rgb: Int)
+object Color {
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+}
+
+}
+
+object t4 {
+
+enum Color(val rgb: Int) {
+ case Red extends Color(0xFF0000)
+ case Green extends Color(0x00FF00)
+ case Blue extends Color(0x0000FF)
+}
+}
+
+
+enum class Planet(mass: Double, radius: Double) {
+ private final val G = 6.67300E-11
+ def surfaceGravity = G * mass / (radius * radius)
+ def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity
+}
+
+object Planet {
+ case MERCURY extends Planet(3.303e+23, 2.4397e6)
+ case VENUS extends Planet(4.869e+24, 6.0518e6)
+ case EARTH extends Planet(5.976e+24, 6.37814e6)
+ case MARS extends Planet(6.421e+23, 3.3972e6)
+ case JUPITER extends Planet(1.9e+27, 7.1492e7)
+ case SATURN extends Planet(5.688e+26, 6.0268e7)
+ case URANUS extends Planet(8.686e+25, 2.5559e7)
+ case NEPTUNE extends Planet(1.024e+26, 2.4746e7)
+
+ def main(args: Array[String]) = {
+ val earthWeight = args(0).toDouble
+ val mass = earthWeight/EARTH.surfaceGravity
+ for (p <- enumValues)
+ println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
+ }
+}
+
diff --git a/tests/pos/reference/implicit-byname-parameters.scala b/tests/pos/reference/implicit-byname-parameters.scala
new file mode 100644
index 000000000000..8b82d2b22c9e
--- /dev/null
+++ b/tests/pos/reference/implicit-byname-parameters.scala
@@ -0,0 +1,24 @@
+package implicitByName
+
+object Test {
+
+trait Codec[T] {
+ def write(x: T): Unit
+}
+
+implicit def intCodec: Codec[Int] = ???
+
+implicit def optionCodec[T]
+ (implicit ev: => Codec[T]): Codec[Option[T]] =
+ new {
+ def write(xo: Option[T]) = xo match {
+ case Some(x) => ev.write(x)
+ case None =>
+ }
+ }
+
+val s = implicitly[Codec[Option[Int]]]
+
+s.write(Some(33))
+s.write(None)
+}
diff --git a/tests/pos/reference/intersection-types.scala b/tests/pos/reference/intersection-types.scala
new file mode 100644
index 000000000000..1d6a14ffa3b1
--- /dev/null
+++ b/tests/pos/reference/intersection-types.scala
@@ -0,0 +1,35 @@
+package intersectionTypes
+
+object t1 {
+
+trait Resetable {
+ def reset(): this.type
+}
+trait Growable[T] {
+ def add(x: T): this.type
+}
+def f(x: Resetable & Growable[String]) = {
+ x.reset()
+ x.add("first")
+}
+
+}
+
+object t2 {
+
+trait A {
+ def children: List[A]
+}
+trait B {
+ def children: List[B]
+}
+val x: A & B = new C
+val ys: List[A & B] = x.children
+
+
+class C extends A with B {
+ def children: List[A & B] = ???
+}
+
+
+}
diff --git a/tests/pos/reference/trait-parameters.scala b/tests/pos/reference/trait-parameters.scala
new file mode 100644
index 000000000000..8b043a4279d6
--- /dev/null
+++ b/tests/pos/reference/trait-parameters.scala
@@ -0,0 +1,19 @@
+trait Greeting(val name: String) {
+ def msg = s"How are you, $name"
+}
+
+trait FormalGreeting extends Greeting {
+ override def msg = s"How do you do, $name"
+}
+
+class C extends Greeting("Bob") {
+ println(msg)
+}
+
+class D extends C with Greeting
+
+class E extends Greeting("Bob") with FormalGreeting
+
+// class D2 extends C with Greeting("Bill") // error
+
+
diff --git a/tests/pos/reference/union-types.scala b/tests/pos/reference/union-types.scala
new file mode 100644
index 000000000000..7366305ad1a1
--- /dev/null
+++ b/tests/pos/reference/union-types.scala
@@ -0,0 +1,37 @@
+package unionTypes
+
+object t1 {
+
+type Hash = Int
+
+case class UserName(name: String)
+case class Password(hash: Hash)
+
+def help(id: UserName | Password) = {
+ val user = id match {
+ case UserName(name) => lookupName(name)
+ case Password(hash) => lookupPassword(hash)
+ }
+}
+
+def lookupName(name: String) = ???
+def lookupPassword(hash: Hash) = ???
+
+}
+
+object t2 {
+ import t1._
+
+trait Admin
+trait UserData
+
+trait L { def lookup(admin: Admin): Object }
+
+case class UserName(name: String) extends L {
+ def lookup(admin: Admin): UserData = ???
+}
+case class Password(hash: Hash) extends L {
+ def lookup(admin: Admin): UserData = ???
+}
+
+}