aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Typer.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/typer/Typer.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/typer/Typer.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala30
1 files changed, 22 insertions, 8 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index f6027165b..624a86c1c 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -628,10 +628,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedCases(cases: List[untpd.CaseDef], selType: Type, pt: Type)(implicit ctx: Context) = {
/** gadtSyms = "all type parameters of enclosing methods that appear
- * non-variantly in the selector type" todo: should typevars
- * which appear with variances +1 and -1 (in different
- * places) be considered as well?
- */
+ * non-variantly in the selector type" todo: should typevars
+ * which appear with variances +1 and -1 (in different
+ * places) be considered as well?
+ */
val gadtSyms: Set[Symbol] = ctx.traceIndented(i"GADT syms of $selType", gadts) {
val accu = new TypeAccumulator[Set[Symbol]] {
def apply(tsyms: Set[Symbol], t: Type): Set[Symbol] = {
@@ -650,9 +650,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
cases mapconserve (typedCase(_, pt, selType, gadtSyms))
}
+ /** Type a case. Overridden in ReTyper, that's why it's separate from
+ * typedCases.
+ */
def typedCase(tree: untpd.CaseDef, pt: Type, selType: Type, gadtSyms: Set[Symbol])(implicit ctx: Context): CaseDef = track("typedCase") {
+ val originalCtx = ctx
+
def caseRest(pat: Tree)(implicit ctx: Context) = {
- gadtSyms foreach (_.resetGADTFlexType)
pat foreachSubTree {
case b: Bind =>
if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(b.symbol)
@@ -661,11 +665,21 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
val guard1 = typedExpr(tree.guard, defn.BooleanType)
val body1 = typedExpr(tree.body, pt)
+ .ensureConforms(pt)(originalCtx) // insert a cast if body does not conform to expected type if we disregard gadt bounds
assignType(cpy.CaseDef(tree)(pat, guard1, body1), body1)
}
- val doCase: () => CaseDef =
- () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.setNewScope)
- (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))()
+
+ val gadtCtx =
+ if (gadtSyms.isEmpty) ctx
+ else {
+ val c = ctx.fresh.setFreshGADTBounds
+ for (sym <- gadtSyms)
+ if (!c.gadt.bounds.contains(sym))
+ c.gadt.bounds = c.gadt.bounds.updated(sym, TypeBounds.empty)
+ c
+ }
+ val pat1 = typedPattern(tree.pat, selType)(gadtCtx)
+ caseRest(pat1)(gadtCtx.fresh.setNewScope)
}
def typedReturn(tree: untpd.Return)(implicit ctx: Context): Return = track("typedReturn") {