From 4611bdf0972fc01dfdfa647a0e84e3bccf98ea05 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 8 Mar 2014 19:05:54 +0100 Subject: Appromiximate union types by intersections. Appromiximate union types by intersections of their common base classes. Controlled by option -Xkeep-unions. If option is set, no approximation is done. Motivations for approximating: There are two. First, union types are departure from Scala 2. From time to time they lead to failure of inference. One example experiences in Dotty was in a foldLeft, where the accumulator type was inferred to be Tree before and was now a union of two tree specific kinds. Tree was the correct type, whereas the union type was too specific. These failures are not common (in the Dotty codebase there were 3, I believe), but they cause considerable difficulty to diagnose. So it seems safer to have a compatibility mode with Scala 2. The second motivation is that union types can become large and unwieldy. A function like TreeCopier has a result type consisting of ~ 40 alternatives, where the alternative type would be just Tree. Once we gain more experience with union types, we might consider flipping the option, and making union types the default. But for now it is safer this way, I believe. --- tests/pos/approximateUnion.scala | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 tests/pos/approximateUnion.scala (limited to 'tests/pos/approximateUnion.scala') diff --git a/tests/pos/approximateUnion.scala b/tests/pos/approximateUnion.scala new file mode 100644 index 000000000..c3fe0e162 --- /dev/null +++ b/tests/pos/approximateUnion.scala @@ -0,0 +1,96 @@ +object approximateUnion { + + trait C[+T] + trait D + trait E + trait X[-T] + + { + trait A extends C[A] with D + trait B extends C[B] with D + + val coin = true + val x = if (coin) new A else new B + val y = Some(if (coin) new A else new B) + + val xtest: C[A | B] & D = x + val ytest: Some[C[A | B] & D] = y + } + + { + trait A extends C[X[A]] with D + trait B extends C[X[B]] with D with E + + val coin = true + val x = if (coin) new A else new B + val y = Some(if (coin) new A else new B) + + val xtest: C[X[A & B]] & D = x + val ytest: Some[C[X[A & B]] & D] = y + } +} + +object approximateUnion2 { + + trait C[T] + trait D + trait E + trait X[-T] + + { + trait A extends C[A] with D + trait B extends C[B] with D + + val coin = true + val x = if (coin) new A else new B + val y = Some(if (coin) new A else new B) + + val xtest: C[_ >: A & B <: A | B] & D = x + val ytest: Some[C[_ >: A & B <: A | B] & D] = y + } + + { + trait A extends C[X[A]] with D + trait B extends C[X[B]] with D with E + + val coin = true + val x = if (coin) new A else new B + val y = Some(if (coin) new A else new B) + + val xtest: C[_ >: X[A | B] <: X[A & B]] & D = x + val ytest: Some[C[_ >: X[A | B] <: X[A & B]]] = y + } +} + +object approximateUnion3 { + + trait C[-T] + trait D + trait E + trait X[-T] + + { + trait A extends C[A] with D + trait B extends C[B] with D + + val coin = true + val x = if (coin) new A else new B + val y = Some(if (coin) new A else new B) + + val xtest: C[A & B] & D = x + val ytest: Some[C[A & B] & D] = y + } + + { + trait A extends C[X[A]] with D + trait B extends C[X[B]] with D with E + + val coin = true + val x = if (coin) new A else new B + val y = Some(if (coin) new A else new B) + + val xtest: C[X[A | B]] & D = x + val ytest2: Some[C[X[A | B]] & D] = y + } +} + -- cgit v1.2.3