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