From 5c557cd7dfa7fddada5a96e2d2bb2d1e71bd90cb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 22 Jan 2018 10:58:25 +0100 Subject: [PATCH 1/2] Fix #3882: Take LazyRefs into account for monitored subtype checking Two types can differ only in their LazyRefs, but still need to be treated as the same for the purpose of subtype cycle checking. --- .../dotty/tools/dotc/core/TypeComparer.scala | 18 +++++++++++++++++- tests/neg/i3882.scala | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i3882.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index fe9355c55d28..4265f57851d6 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -148,7 +148,23 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { if (Config.traceDeepSubTypeRecursions && !this.isInstanceOf[ExplainingTypeComparer]) ctx.log(TypeComparer.explained(implicit ctx => ctx.typeComparer.isSubType(tp1, tp2))) } - val p = (tp1, tp2) + // Eliminate LazyRefs before checking whether we have seen a type before + val normalize = new TypeMap { + val DerefLimit = 10 + var derefCount = 0 + def apply(t: Type) = t match { + case t: LazyRef => + // Dereference a lazyref to detect underlying matching types, but + // be careful not to get into an infinite recursion. If recursion count + // exceeds `DerefLimit`, approximate with `NoType` instead. + derefCount += 1 + if (derefCount >= DerefLimit) NoType + else try mapOver(t.ref) finally derefCount -= 1 + case _ => + mapOver(t) + } + } + val p = (normalize(tp1), normalize(tp2)) !pendingSubTypes(p) && { try { pendingSubTypes += p diff --git a/tests/neg/i3882.scala b/tests/neg/i3882.scala new file mode 100644 index 000000000000..eb28fd5632ce --- /dev/null +++ b/tests/neg/i3882.scala @@ -0,0 +1,5 @@ +trait Ring[A <: Ring[A]] + +object Test { + def crash[T <: Ring[_ <: T]]: Ring[T] = ??? // error: Type argument T does not conform to upper bound Ring[LazyRef(T)] +} From 95f52734bcd50128bcf4d9f13535bbad74e750c1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 22 Jan 2018 13:16:31 +0100 Subject: [PATCH 2/2] Fix test i3882.scala can be compiled only if deep subtypes are allowed. --- compiler/test/dotty/tools/dotc/CompilationTests.scala | 1 + tests/{neg => neg-custom-args}/i3882.scala | 0 2 files changed, 1 insertion(+) rename tests/{neg => neg-custom-args}/i3882.scala (100%) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 480f1d3ee122..53b6d775675f 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -191,6 +191,7 @@ class CompilationTests extends ParallelTesting { compileFile("../tests/neg-custom-args/pureStatement.scala", defaultOptions.and("-Xfatal-warnings")) + compileFile("../tests/neg-custom-args/i3589-a.scala", defaultOptions.and("-Xfatal-warnings")) + compileFile("../tests/neg-custom-args/i2333.scala", defaultOptions.and("-Xfatal-warnings")) + + compileFile("../tests/neg-custom-args/i3882.scala", allowDeepSubtypes) + compileFile("../tests/neg-custom-args/phantom-overload.scala", allowDoubleBindings) + compileFile("../tests/neg-custom-args/phantom-overload-2.scala", allowDoubleBindings) + compileFile("../tests/neg-custom-args/structural.scala", defaultOptions.and("-Xfatal-warnings")) diff --git a/tests/neg/i3882.scala b/tests/neg-custom-args/i3882.scala similarity index 100% rename from tests/neg/i3882.scala rename to tests/neg-custom-args/i3882.scala