From b0a3ed097ce204a94a09865e3caed57e71d2ac9c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 1 Mar 2020 18:52:38 +0100 Subject: [PATCH 1/3] Fix #8404: Use both scrutinee type and given type in pattern ascriptions In a pattern ascription `x: T` type `x` to have the intersection of the given type `T` and the scrutinee type. This matches scalac's behavior. It now makes i5418.scala compile. The type intersection was enough to make that one compile, it did not need unsound covariant GADT matching (which was what I claimed before in the issue). --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 16 ++++++++++++++-- .../test/dotty/tools/dotc/CompilationTests.scala | 2 +- tests/{neg => pos}/i5418.scala | 0 tests/pos/i8404.scala | 10 ++++++++++ tests/{run => run-deep-subtype}/colltest4.check | 0 .../colltest4/CollectionStrawMan4_1.scala | 0 .../colltest4/CollectionTests_2.scala | 0 7 files changed, 25 insertions(+), 3 deletions(-) rename tests/{neg => pos}/i5418.scala (100%) create mode 100644 tests/pos/i8404.scala rename tests/{run => run-deep-subtype}/colltest4.check (100%) rename tests/{run => run-deep-subtype}/colltest4/CollectionStrawMan4_1.scala (100%) rename tests/{run => run-deep-subtype}/colltest4/CollectionTests_2.scala (100%) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2e5afd3cde0f..46ed6ca5a299 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1573,8 +1573,20 @@ class Typer extends Namer // for a singleton pattern like `x @ Nil`, `x` should get the type from the scrutinee // see tests/neg/i3200b.scala and SI-1503 val symTp = - if (body1.tpe.isInstanceOf[TermRef]) pt1 - else body1.tpe.underlyingIfRepeated(isJava = false) + if body1.tpe.isInstanceOf[TermRef] then pt1 + else if isWildcardStarArg(body1) + || pt1 == defn.ImplicitScrutineeTypeRef + || body1.tpe <:< pt // There is some strange interaction with gadt matching. + // and implicit scopes. + // run/t2755.scala fails to compile if this subtype test is omitted + // and the else clause is changed to `body1.tpe & pt1`. What + // happens is that we get either an Array[Float] or an Array[T] + // where T is GADT constrained to := Float. But the case body + // compiles only if the bound variable is Array[Float]. If + // it is Array[T] we get an implicit not found. To avoid fragility + // wrt to operand order for `&`, we include the explicit subtype test here. + then body1.tpe + else pt1 & body1.tpe val sym = ctx.newPatternBoundSymbol(name, symTp, tree.span) if (pt == defn.ImplicitScrutineeTypeRef || tree.mods.is(Given)) sym.setFlag(Given) if (ctx.mode.is(Mode.InPatternAlternative)) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index cf8a7cc6c91a..2b534dac7fbc 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -44,7 +44,7 @@ class CompilationTests extends ParallelTesting { compileFile("tests/pos-special/sourcepath/outer/nested/Test4.scala", defaultOptions.and("-sourcepath", "tests/pos-special/sourcepath")), compileFilesInDir("tests/pos-special/fatal-warnings", defaultOptions.and("-Xfatal-warnings", "-feature")), compileFilesInDir("tests/pos-special/spec-t5545", defaultOptions), - compileFilesInDir("tests/pos-special/strawman-collections", defaultOptions), + compileFilesInDir("tests/pos-special/strawman-collections", allowDeepSubtypes), compileFilesInDir("tests/pos-special/isInstanceOf", allowDeepSubtypes.and("-Xfatal-warnings")), compileFilesInDir("tests/new", defaultOptions), compileFilesInDir("tests/pos-scala2", scala2CompatMode), diff --git a/tests/neg/i5418.scala b/tests/pos/i5418.scala similarity index 100% rename from tests/neg/i5418.scala rename to tests/pos/i5418.scala diff --git a/tests/pos/i8404.scala b/tests/pos/i8404.scala new file mode 100644 index 000000000000..a9dc089eb5ad --- /dev/null +++ b/tests/pos/i8404.scala @@ -0,0 +1,10 @@ +trait ActorRefScope +class ActorRef +case class DeathWatchNotification(actor: ActorRef) +object Main { + val ref: ActorRef = ??? + ref match { + case r: ActorRefScope => DeathWatchNotification(r) + case _ => + } +} \ No newline at end of file diff --git a/tests/run/colltest4.check b/tests/run-deep-subtype/colltest4.check similarity index 100% rename from tests/run/colltest4.check rename to tests/run-deep-subtype/colltest4.check diff --git a/tests/run/colltest4/CollectionStrawMan4_1.scala b/tests/run-deep-subtype/colltest4/CollectionStrawMan4_1.scala similarity index 100% rename from tests/run/colltest4/CollectionStrawMan4_1.scala rename to tests/run-deep-subtype/colltest4/CollectionStrawMan4_1.scala diff --git a/tests/run/colltest4/CollectionTests_2.scala b/tests/run-deep-subtype/colltest4/CollectionTests_2.scala similarity index 100% rename from tests/run/colltest4/CollectionTests_2.scala rename to tests/run-deep-subtype/colltest4/CollectionTests_2.scala From ddad2ebef04edab2b3c69f93c781c6c3d7cedd70 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 1 Mar 2020 19:39:41 +0100 Subject: [PATCH 2/3] Another closed issue test --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 1 + tests/pos/i3208.scala | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 tests/pos/i3208.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 46ed6ca5a299..f8e33bc80621 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1585,6 +1585,7 @@ class Typer extends Namer // compiles only if the bound variable is Array[Float]. If // it is Array[T] we get an implicit not found. To avoid fragility // wrt to operand order for `&`, we include the explicit subtype test here. + // See also #5649. then body1.tpe else pt1 & body1.tpe val sym = ctx.newPatternBoundSymbol(name, symTp, tree.span) diff --git a/tests/pos/i3208.scala b/tests/pos/i3208.scala new file mode 100644 index 000000000000..eab55af54a78 --- /dev/null +++ b/tests/pos/i3208.scala @@ -0,0 +1,6 @@ +class Test { + trait E + trait Marker + + def test(es: List[E]): List[E] = es.collect { case e: Marker => e } +} \ No newline at end of file From 526670dac45be96fc8fb5aec503fb9d88f10e58c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 1 Mar 2020 19:40:55 +0100 Subject: [PATCH 3/3] Unrelated test for a previously closed issue --- tests/neg/i8338.scala | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/neg/i8338.scala diff --git a/tests/neg/i8338.scala b/tests/neg/i8338.scala new file mode 100644 index 000000000000..d9f20432e4c6 --- /dev/null +++ b/tests/neg/i8338.scala @@ -0,0 +1,8 @@ +object test { + trait B { + type X; def mkX(i: Int): B#X + } + val b: B = new B { + type X = Int; def mkX(i: Int): X = i // error + } +} \ No newline at end of file