From ac1a641abac7554d155c2ff5b888d2de6b8e26ef Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 15 Sep 2022 17:35:51 +0100 Subject: [PATCH] Teach SpaceEngine that generic tuples are irrefutable --- .../tools/dotc/transform/patmat/Space.scala | 1 + tests/neg/i15991.abstract.scala | 20 +++++++++++++++++++ tests/neg/i15991.scala | 7 +++++++ tests/pos/i15991.abstract.scala | 20 +++++++++++++++++++ tests/pos/i15991.orig.scala | 9 +++++++++ tests/pos/i15991.scala | 8 ++++++++ 6 files changed, 65 insertions(+) create mode 100644 tests/neg/i15991.abstract.scala create mode 100644 tests/neg/i15991.scala create mode 100644 tests/pos/i15991.abstract.scala create mode 100644 tests/pos/i15991.orig.scala create mode 100644 tests/pos/i15991.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index a8432833d42a..d095bb1444ea 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -306,6 +306,7 @@ object SpaceEngine { val isEmptyTp = extractorMemberType(unappResult, nme.isEmpty, NoSourcePosition) isEmptyTp <:< ConstantType(Constant(false)) } + || unappResult.derivesFrom(defn.NonEmptyTupleClass) } /** Is the unapply or unapplySeq irrefutable? diff --git a/tests/neg/i15991.abstract.scala b/tests/neg/i15991.abstract.scala new file mode 100644 index 000000000000..aa974e487080 --- /dev/null +++ b/tests/neg/i15991.abstract.scala @@ -0,0 +1,20 @@ +object Foo: + def unapply[T <: Tuple](tup: T): String *: String *: T = + "a" *: "b" *: tup + +// like {pos,neg}/i15991, but with an abstract tuple tail +class Test: + val tup2: String *: String *: EmptyTuple = ("c", "d") + + def test3 = + val Foo(x, y, z) = tup2 // error: Wrong number of argument patterns for Foo; expected: (String, String, String, String) + x + y + z + + def test3a = + val x1x = tup2 match + case Foo(x, y, z) => // error: Wrong number of argument patterns for Foo; expected: (String, String, String, String) + (x, y, z) + val x = x1x._1 + val y = x1x._2 + val z = x1x._3 + x + y + z diff --git a/tests/neg/i15991.scala b/tests/neg/i15991.scala new file mode 100644 index 000000000000..9cd6b1c1d27e --- /dev/null +++ b/tests/neg/i15991.scala @@ -0,0 +1,7 @@ +object Foo: + def unapply(x: Any): String *: String *: EmptyTuple = ("a", "b") + +class Test: + def test = + val Foo(x, y, z) = 1 // error: Wrong number of argument patterns for Foo; expected: (String, String) + x + y + z diff --git a/tests/pos/i15991.abstract.scala b/tests/pos/i15991.abstract.scala new file mode 100644 index 000000000000..3499fa7a014d --- /dev/null +++ b/tests/pos/i15991.abstract.scala @@ -0,0 +1,20 @@ +object Foo: + def unapply[T <: Tuple](tup: T): String *: String *: T = + "a" *: "b" *: tup + +// like {pos,neg}/i15991, but with an abstract tuple tail +class Test: + val tup2: String *: String *: EmptyTuple = ("c", "d") + + def test2 = + val Foo(x, y, _, _) = tup2 + x + y + + // like test2, but as the desugaring of what PatternDef's become + def test2b = + val x1x = tup2 match + case Foo(x, y, _, _) => + (x, y) + val x = x1x._1 + val y = x1x._2 + x + y diff --git a/tests/pos/i15991.orig.scala b/tests/pos/i15991.orig.scala new file mode 100644 index 000000000000..f56bd2979b40 --- /dev/null +++ b/tests/pos/i15991.orig.scala @@ -0,0 +1,9 @@ +class Foo + +object Foo: +// def unapply(f: Foo): (Int, Int) = ??? // does not raise a warning + def unapply(f: Foo): Int *: Int *: EmptyTuple = ??? + +@main def example = + val Foo(x, y) = new Foo + println(x) diff --git a/tests/pos/i15991.scala b/tests/pos/i15991.scala new file mode 100644 index 000000000000..b5c30471bfdc --- /dev/null +++ b/tests/pos/i15991.scala @@ -0,0 +1,8 @@ +object Foo: + def unapply(x: Any): String *: String *: EmptyTuple = + ("a", "b") + +class Test: + def test = + val Foo(x, y) = 1 + x + y