aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
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 /compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
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 'compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala21
1 files changed, 10 insertions, 11 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
index 2a1f4ee6e..a12936c58 100644
--- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
+++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
@@ -35,15 +35,6 @@ trait ConstraintHandling {
/** If the constraint is frozen we cannot add new bounds to the constraint. */
protected var frozenConstraint = false
- protected var alwaysFluid = false
-
- /** Perform `op` in a mode where all attempts to set `frozen` to true are ignored */
- def fluidly[T](op: => T): T = {
- val saved = alwaysFluid
- alwaysFluid = true
- try op finally alwaysFluid = saved
- }
-
/** If set, align arguments `S1`, `S2`when taking the glb
* `T1 { X = S1 } & T2 { X = S2 }` of a constraint upper bound for some type parameter.
* Aligning means computing `S1 =:= S2` which may change the current constraint.
@@ -156,16 +147,24 @@ trait ConstraintHandling {
up.forall(addOneBound(_, lo, isUpper = false))
}
+
+ protected def isSubType(tp1: Type, tp2: Type, whenFrozen: Boolean): Boolean = {
+ if (whenFrozen)
+ isSubTypeWhenFrozen(tp1, tp2)
+ else
+ isSubType(tp1, tp2)
+ }
+
final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
- frozenConstraint = !alwaysFluid
+ frozenConstraint = true
try isSubType(tp1, tp2)
finally frozenConstraint = saved
}
final def isSameTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
val saved = frozenConstraint
- frozenConstraint = !alwaysFluid
+ frozenConstraint = true
try isSameType(tp1, tp2)
finally frozenConstraint = saved
}