From 0d7978043175103c91b151a97442b799dedd8791 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 11 Oct 2022 10:48:00 +0100 Subject: [PATCH 1/2] Fix exhaustivity warning --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 4 ++++ tests/pos/i15967.scala | 10 ++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/pos/i15967.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 739a06abb7f3..9932bee26f4a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -863,6 +863,10 @@ object TypeOps: } def instantiate(): Type = { + // if there's a change in variance in type parameters (between subtype tp1 and supertype tp2) + // then we don't want to maximise the type variables in the wrong direction. + // For instance 15967, A[-Z] and B[Y] extends A[Y], we don't want to maximise Y to Any + maximizeType(protoTp1.baseType(tp2.classSymbol), NoSpan) maximizeType(protoTp1, NoSpan) wildApprox(protoTp1) } diff --git a/tests/pos/i15967.scala b/tests/pos/i15967.scala new file mode 100644 index 000000000000..0ef00ae0cea1 --- /dev/null +++ b/tests/pos/i15967.scala @@ -0,0 +1,10 @@ +// scalac: -Werror +sealed trait A[-Z] +final case class B[Y]() extends A[Y] + +class Test: + def t1[X](a: A[X]) = a match // was inexhaustive + case _: B[X] @unchecked => + +//def t2[X](a: A[X]) = a match // was inexhaustive +// case _: B[X] => // expected unchecked warning From 99ba2a3181d39a659c40e60f5bbbe7c4c31cb08d Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 15 Sep 2022 17:35:51 +0100 Subject: [PATCH 2/2] 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 ca0e149f881f..8e891f822255 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