aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeComparer.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-12-11 18:47:18 +0100
committerMartin Odersky <odersky@gmail.com>2014-12-16 17:46:14 +0100
commit16554c0efe2d09ab3ef760522f0811a964f7ee84 (patch)
treeb3c94dc415850f264c16dbd0b91418e49947045a /src/dotty/tools/dotc/core/TypeComparer.scala
parent21fa5dd1a47727c977848163e2610be745951dbc (diff)
downloaddotty-16554c0efe2d09ab3ef760522f0811a964f7ee84.tar.gz
dotty-16554c0efe2d09ab3ef760522f0811a964f7ee84.tar.bz2
dotty-16554c0efe2d09ab3ef760522f0811a964f7ee84.zip
Fixed #264 - failure to typecheck GADTs
The previous scheme derived the right bounds, but then failed to use them because a TypeRef already has a set info (its bounds). Changing the bounds in the symbol by a side effect does not affect that. This is good! But it showed that the previous scheme was too fragile because it used a sneaky side effect when updating the symbol info which failed to propgate into the cached info in TypeRef. We now keep GADT computed bounds separate form the symbol info in a map `gadt` in the current context.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeComparer.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 42af31553..5cb384361 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -617,9 +617,12 @@ class TypeComparer(initctx: Context) extends DotClass {
secondTry(OrType.make(derivedRef(tp11), derivedRef(tp12)), tp2)
*/
case TypeBounds(lo1, hi1) =>
- if ((ctx.mode is Mode.GADTflexible) && (tp1.symbol is GADTFlexType) &&
- !isSubTypeWhenFrozen(hi1, tp2))
- trySetType(tp1, TypeBounds(lo1, hi1 & tp2))
+ val gbounds1 = ctx.gadt.bounds(tp1.symbol)
+ if (gbounds1 != null)
+ isSubTypeWhenFrozen(gbounds1.hi, tp2) ||
+ (ctx.mode is Mode.GADTflexible) &&
+ narrowGADTBounds(tp1, TypeBounds(gbounds1.lo, gbounds1.hi & tp2)) ||
+ tryRebase2nd
else if (lo1 eq hi1) isSubType(hi1, tp2)
else tryRebase2nd
case _ =>
@@ -636,9 +639,12 @@ class TypeComparer(initctx: Context) extends DotClass {
}
def compareNamed: Boolean = tp2.info match {
case TypeBounds(lo2, hi2) =>
- if ((ctx.mode is Mode.GADTflexible) && (tp2.symbol is GADTFlexType) &&
- !isSubTypeWhenFrozen(tp1, lo2))
- trySetType(tp2, TypeBounds(lo2 | tp1, hi2))
+ val gbounds2 = ctx.gadt.bounds(tp2.symbol)
+ if (gbounds2 != null)
+ isSubTypeWhenFrozen(tp1, gbounds2.lo) ||
+ (ctx.mode is Mode.GADTflexible) &&
+ narrowGADTBounds(tp2, TypeBounds(gbounds2.lo | tp1, gbounds2.hi)) ||
+ tryRebase3rd
else
((frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2)
|| tryRebase3rd)
@@ -911,9 +917,9 @@ class TypeComparer(initctx: Context) extends DotClass {
tp.exists && !tp.isLambda
}
- def trySetType(tr: NamedType, bounds: TypeBounds): Boolean =
+ def narrowGADTBounds(tr: NamedType, bounds: TypeBounds): Boolean =
isSubType(bounds.lo, bounds.hi) &&
- { tr.symbol.changeGADTInfo(bounds); true }
+ { ctx.gadt.bounds = ctx.gadt.bounds.updated(tr.symbol, bounds); true }
// Tests around `matches`