diff options
author | Martin Odersky <odersky@gmail.com> | 2014-12-11 18:47:18 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-12-16 17:46:14 +0100 |
commit | 16554c0efe2d09ab3ef760522f0811a964f7ee84 (patch) | |
tree | b3c94dc415850f264c16dbd0b91418e49947045a /src/dotty/tools/dotc/core/TypeComparer.scala | |
parent | 21fa5dd1a47727c977848163e2610be745951dbc (diff) | |
download | dotty-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.scala | 22 |
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` |