From 2ed2826c27fd3cb486caef982bb6a8b4e7f9cc0b Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 5 Jul 2024 14:21:05 +0100 Subject: [PATCH] Strip null on the scrutinee Without that, we end up with either a flexible type or a `| Null`. --- .../dotty/tools/dotc/transform/patmat/Space.scala | 6 +++--- tests/warn/i20132.future-Left.scala | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 tests/warn/i20132.future-Left.scala diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 9a373ad3653d..ba67b9787fe9 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -835,7 +835,7 @@ object SpaceEngine { /** Return the underlying type of non-module, non-constant, non-enum case singleton types. * Also widen ExprType to its result type, and rewrap any annotation wrappers. * For example, with `val opt = None`, widen `opt.type` to `None.type`. */ - def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp)")(tp match { + def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp ${tp.className})")(tp match { case _: ConstantType => tp case tp: TermRef if tp.symbol.is(Module) => tp case tp: TermRef if tp.symbol.isAllOf(EnumCase) => tp @@ -846,7 +846,7 @@ object SpaceEngine { }) def checkExhaustivity(m: Match)(using Context): Unit = trace(i"checkExhaustivity($m)") { - val selTyp = toUnderlying(m.selector.tpe).dealias + val selTyp = toUnderlying(m.selector.tpe.stripNull()).dealias val targetSpace = trace(i"targetSpace($selTyp)")(project(selTyp)) val patternSpace = Or(m.cases.foldLeft(List.empty[Space]) { (acc, x) => @@ -879,7 +879,7 @@ object SpaceEngine { def checkReachability(m: Match)(using Context): Unit = trace(i"checkReachability($m)") { val cases = m.cases.toIndexedSeq - val selTyp = toUnderlying(m.selector.tpe).dealias + val selTyp = toUnderlying(m.selector.tpe.stripNull()).dealias val isNullable = selTyp.classSymbol.isNullableClass val targetSpace = trace(i"targetSpace($selTyp)")(if isNullable diff --git a/tests/warn/i20132.future-Left.scala b/tests/warn/i20132.future-Left.scala new file mode 100644 index 000000000000..a25718eadb6b --- /dev/null +++ b/tests/warn/i20132.future-Left.scala @@ -0,0 +1,13 @@ +//> using options -Yexplicit-nulls -Yno-flexible-types + +import scala.language.unsafeNulls + +import java.util.concurrent.CompletableFuture +import scala.jdk.CollectionConverters._ + +class Test1: + def m1 = + val fut: CompletableFuture[Either[String, List[String]]] = ??? + fut.thenApply: + case Right(edits: List[String]) => edits.asJava + case Left(error: String) => throw new Exception(error)