diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2017-03-16 20:27:09 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2017-03-18 20:43:25 +0100 |
commit | 00bbb97a5bf6ea32de7ca92cb1a7b32280fa4e9e (patch) | |
tree | f9b8c352581f3c2507e95479574757bc82af22f4 /tests | |
parent | 215c13408f7709c416baf561c513159622f10ba5 (diff) | |
download | dotty-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.scala | 34 |
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) +} |