From 00bbb97a5bf6ea32de7ca92cb1a7b32280fa4e9e Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 16 Mar 2017 20:27:09 +0100 Subject: 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. --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compiler/src/dotty/tools/dotc/core/TypeOps.scala') diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 6c40794e3..3d2906320 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -282,7 +282,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. */ def harmonizeUnion(tp: Type): Type = tp match { case tp: OrType => - joinIfScala2(typeComparer.fluidly(tp.tp1 | tp.tp2)) + joinIfScala2(ctx.typeComparer.lub(harmonizeUnion(tp.tp1), harmonizeUnion(tp.tp2), canConstrain = true)) case tp @ AndType(tp1, tp2) => tp derived_& (harmonizeUnion(tp1), harmonizeUnion(tp2)) case tp: RefinedType => -- cgit v1.2.3