diff options
author | Martin Odersky <odersky@gmail.com> | 2014-01-18 12:03:59 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-01-18 12:05:23 +0100 |
commit | cb3adb9ff93c45101150dd71b927295e327b3c81 (patch) | |
tree | 5fe09e319c738259e0f37f81c5ced22323fbce3d /src/dotty/tools/dotc/typer/Typer.scala | |
parent | 5a5806b4c5fb6678d63d9f1da06669447cb97eab (diff) | |
download | dotty-cb3adb9ff93c45101150dd71b927295e327b3c81.tar.gz dotty-cb3adb9ff93c45101150dd71b927295e327b3c81.tar.bz2 dotty-cb3adb9ff93c45101150dd71b927295e327b3c81.zip |
Refine avoiding local refs in block's type.
If all else fails, force all type variables with fullyDefinedType. This can avoid references to locals. Example in file dotctest: SourceFile.scala, method calculateLineIndices.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Typer.scala')
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index cc142e7bf..d16ec53ae 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -511,14 +511,30 @@ class Typer extends Namer with Applications with Implicits { val stats1 = typedStats(tree.stats, ctx.owner) val expr1 = typedExpr(tree.expr, pt)(exprCtx) val result = cpy.Block(tree, stats1, expr1).withType(avoid(expr1.tpe, localSyms(stats1))) - val leaks = CheckTrees.escapingRefs(result) - if (leaks.isEmpty) result + checkNoLocalRefs(result, pt) + } + + /** Check that block's type can be expressed without references to locally defined + * symbols. The following two remedies are tried before giving up: + * 1. If the expected type of the block is fully defined, pick it as the + * type of the result expressed by adding a type ascription. + * 2. If (1) fails, force all type variables so that the block's type is + * fully defined and try again. + */ + def checkNoLocalRefs(block: Block, pt: Type, forcedDefined: Boolean = false)(implicit ctx: Context): Tree = { + val Block(stats, expr) = block + val leaks = CheckTrees.escapingRefs(block) + if (leaks.isEmpty) block else if (isFullyDefined(pt, ForceDegree.all)) { - val expr2 = typed(untpd.Typed(untpd.TypedSplice(expr1), untpd.TypeTree(pt))) - untpd.Block(stats1, expr2) withType expr2.tpe + val expr1 = typed(untpd.Typed(untpd.TypedSplice(expr), untpd.TypeTree(pt))) + untpd.Block(stats, expr1) withType expr1.tpe + } else if (!forcedDefined) { + fullyDefinedType(block.tpe, "block", block.pos) + val block1 = block.withType(avoid(block.tpe, localSyms(stats))) + checkNoLocalRefs(block1, pt, forcedDefined = true) } else - errorTree(result, - i"local definition of ${leaks.head.name} escapes as part of block's type ${result.tpe}"/*; full type: ${result.tpe.toString}"*/) + errorTree(block, + i"local definition of ${leaks.head.name} escapes as part of block's type ${block.tpe}"/*; full type: ${result.tpe.toString}"*/) } def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = track("typedIf") { |