From fac74a618ae4666490cd8c7fd3f9604d877562d9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 11 Mar 2017 20:56:02 +0100 Subject: Fix #1569: Improve avoidance algorithm The essential change is that we do not throw away more precise info of the avoided type if the expected type is fully defined. --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 14 ++++++++++---- tests/neg/t1569-failedAvoid.scala | 9 --------- tests/pos/t1569.scala | 6 ++++++ 3 files changed, 16 insertions(+), 13 deletions(-) delete mode 100644 tests/neg/t1569-failedAvoid.scala create mode 100644 tests/pos/t1569.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ba14b7498..c43a8adcd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -642,12 +642,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } val leaks = escapingRefs(tree, localSyms) if (leaks.isEmpty) tree - else if (isFullyDefined(pt, ForceDegree.none)) ascribeType(tree, pt) else if (!forcedDefined) { fullyDefinedType(tree.tpe, "block", tree.pos) - val tree1 = ascribeType(tree, avoid(tree.tpe, localSyms)) - ensureNoLocalRefs(tree1, pt, localSyms, forcedDefined = true) - } else + val avoidingType = avoid(tree.tpe, localSyms) + if (isFullyDefined(pt, ForceDegree.none) && !(avoidingType <:< pt)) + ascribeType(tree, pt) + else { + val tree1 = ascribeType(tree, avoidingType) + ensureNoLocalRefs(tree1, pt, localSyms, forcedDefined = true) + } + } else if (isFullyDefined(pt, ForceDegree.none)) + ascribeType(tree, pt) + else errorTree(tree, em"local definition of ${leaks.head.name} escapes as part of expression's type ${tree.tpe}"/*; full type: ${result.tpe.toString}"*/) } diff --git a/tests/neg/t1569-failedAvoid.scala b/tests/neg/t1569-failedAvoid.scala deleted file mode 100644 index 45bb96f36..000000000 --- a/tests/neg/t1569-failedAvoid.scala +++ /dev/null @@ -1,9 +0,0 @@ -// This was t1569.scala. -// It fails in dotty because the expected type of the anonymous function in the last line -// is fully determined (C). So that type is taken as the type of the anonymous function. -// See pos/t1569a.scala for related examples that work. -object Bug { - class C { type T } - def foo(x: Int)(y: C)(z: y.T): Unit = {} - foo(3)(new C { type T = String })("hello") // error -} diff --git a/tests/pos/t1569.scala b/tests/pos/t1569.scala new file mode 100644 index 000000000..5e48c03b1 --- /dev/null +++ b/tests/pos/t1569.scala @@ -0,0 +1,6 @@ +// See pos/t1569a.scala for related examples that work. +object Bug { + class C { type T } + def foo(x: Int)(y: C)(z: y.T): Unit = {} + foo(3)(new C { type T = String })("hello") +} -- cgit v1.2.3