aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2017-03-16 20:27:09 +0100
committerGuillaume Martres <smarter@ubuntu.com>2017-03-18 20:43:25 +0100
commit00bbb97a5bf6ea32de7ca92cb1a7b32280fa4e9e (patch)
treef9b8c352581f3c2507e95479574757bc82af22f4 /tests
parent215c13408f7709c416baf561c513159622f10ba5 (diff)
downloaddotty-00bbb97a5bf6ea32de7ca92cb1a7b32280fa4e9e.tar.gz
dotty-00bbb97a5bf6ea32de7ca92cb1a7b32280fa4e9e.tar.bz2
dotty-00bbb97a5bf6ea32de7ca92cb1a7b32280fa4e9e.zip
Better type inference in harmonizeUnion
Before this commit, the added testcase failed because the type of `inv` was inferred to be `Inv[Any]` instead of `Inv[Int]`. The situation looks like this: def inv(cond: Boolean) = if (cond) new Inv(1) // : Inv[A] where A >: Int else Inv.empty // : Inv[A'] where A' unconstrained // : Inv[A] | Inv[A'] To get the type of `inv`, we call `harmonizeUnion` which will take the lub of `Inv[A]` and `Inv[A']`, eventually this mean that we do: A' <:< A But since `harmonizeUnion` uses `fluidly`, this does not result in `A'` getting constrained to be a subtype of `A`, instead we constrain `A` to the upper bound of `A'`: Any <:< A We use `fluidly` to avoid creating OrTypes in `lub`, but it turns out that there is a less aggressive solution: `lub` calls `mergeIfSuper` which then calls `isSubTypeWhenFrozen`, if we just make these subtype calls non-frozen, we can achieve what we want. This is what the new `lub` parameter `canConstrain` allows.
Diffstat (limited to 'tests')
-rw-r--r--tests/pos/constraining-lub.scala34
1 files changed, 34 insertions, 0 deletions
diff --git a/tests/pos/constraining-lub.scala b/tests/pos/constraining-lub.scala
new file mode 100644
index 000000000..80da2ec86
--- /dev/null
+++ b/tests/pos/constraining-lub.scala
@@ -0,0 +1,34 @@
+class Inv[A](x: A)
+object Inv {
+ def empty[A]: Inv[A] = new Inv(???)
+}
+
+class Inv2[A](x: A)
+object Inv2 {
+ def empty[A]: Inv2[A] = new Inv2(???)
+}
+
+object Test {
+ def inv(cond: Boolean) =
+ if (cond)
+ new Inv(1)
+ else
+ Inv.empty
+
+ val x: Inv[Int] = inv(true)
+
+ def inv2(cond: Boolean) =
+ if (cond) {
+ if (cond)
+ new Inv(1)
+ else
+ Inv.empty
+ } else {
+ if (cond)
+ new Inv2(1)
+ else
+ Inv2.empty
+ }
+
+ val y: Inv[Int] | Inv2[Int] = inv2(true)
+}