From ab240f1d5b12e242a79b8791e020a89b1a877c7f Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 5 Aug 2024 16:19:18 +0100 Subject: [PATCH] Only strip under unsafeNulls --- .../dotty/tools/dotc/transform/patmat/Space.scala | 7 +++++-- tests/warn/i20132.stream-Tuple2.safeNulls.check | 8 ++++++++ .../warn/i20132.stream-Tuple2.safeNulls.fixed.scala | 12 ++++++++++++ tests/warn/i20132.stream-Tuple2.safeNulls.scala | 11 +++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/warn/i20132.stream-Tuple2.safeNulls.check create mode 100644 tests/warn/i20132.stream-Tuple2.safeNulls.fixed.scala create mode 100644 tests/warn/i20132.stream-Tuple2.safeNulls.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index f7ec95e21c90..20b0099d82e2 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -808,12 +808,15 @@ object SpaceEngine { doShow(s) } + extension (self: Type) private def stripUnsafeNulls()(using Context): Type = + if Nullables.unsafeNullsEnabled then self.stripNull() else self + private def exhaustivityCheckable(sel: Tree)(using Context): Boolean = trace(i"exhaustivityCheckable($sel ${sel.className})") { val seen = collection.mutable.Set.empty[Symbol] // Possible to check everything, but be compatible with scalac by default def isCheckable(tp: Type): Boolean = trace(i"isCheckable($tp ${tp.className})"): - val tpw = tp.widen.dealias.stripNull() + val tpw = tp.widen.dealias.stripUnsafeNulls() val classSym = tpw.classSymbol classSym.is(Sealed) && !tpw.isLargeGenericTuple || // exclude large generic tuples from exhaustivity // requires an unknown number of changes to make work @@ -860,7 +863,7 @@ object SpaceEngine { }) def checkExhaustivity(m: Match)(using Context): Unit = trace(i"checkExhaustivity($m)") { - val selTyp = toUnderlying(m.selector.tpe.stripNull()).dealias + val selTyp = toUnderlying(m.selector.tpe.stripUnsafeNulls()).dealias val targetSpace = trace(i"targetSpace($selTyp)")(project(selTyp)) val patternSpace = Or(m.cases.foldLeft(List.empty[Space]) { (acc, x) => diff --git a/tests/warn/i20132.stream-Tuple2.safeNulls.check b/tests/warn/i20132.stream-Tuple2.safeNulls.check new file mode 100644 index 000000000000..e444ef8c3340 --- /dev/null +++ b/tests/warn/i20132.stream-Tuple2.safeNulls.check @@ -0,0 +1,8 @@ +-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i20132.stream-Tuple2.safeNulls.scala:8:24 --------------------- +8 | xs.asJava.forEach { case (a, b) => // warn + | ^ + | match may not be exhaustive. + | + | It would fail on pattern case: _: Null + | + | longer explanation available when compiling with `-explain` diff --git a/tests/warn/i20132.stream-Tuple2.safeNulls.fixed.scala b/tests/warn/i20132.stream-Tuple2.safeNulls.fixed.scala new file mode 100644 index 000000000000..817d8ce06cee --- /dev/null +++ b/tests/warn/i20132.stream-Tuple2.safeNulls.fixed.scala @@ -0,0 +1,12 @@ +//> using options -Yexplicit-nulls -Yno-flexible-types + +import scala.jdk.CollectionConverters.* + +class Test2: + def t1: Unit = { + val xs = List.empty[(String, String)] + xs.asJava.forEach { + case (a, b) => () + case null => () + } + } diff --git a/tests/warn/i20132.stream-Tuple2.safeNulls.scala b/tests/warn/i20132.stream-Tuple2.safeNulls.scala new file mode 100644 index 000000000000..2d4a2318039e --- /dev/null +++ b/tests/warn/i20132.stream-Tuple2.safeNulls.scala @@ -0,0 +1,11 @@ +//> using options -Yexplicit-nulls -Yno-flexible-types + +import scala.jdk.CollectionConverters.* + +class Test2: + def t1: Unit = { + val xs = List.empty[(String, String)] + xs.asJava.forEach { case (a, b) => // warn + () + } + }