From f351ec4c255841031c7d4099cc23c602b4d3289c Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Thu, 13 Jul 2023 21:07:51 -0400 Subject: [PATCH 1/2] allow nullability flow typing even in presence of pattern match Nullability flow typing is conservatively disabled for mutable variables to which a write occurs nested inside a Tree other than some known ones, such as If and WhileDo. This is to prevent flow-sensitive reasoning for variables that are captured and written to in a closure. Pattern matches do not create a closure. This change enables nullability flow typing even for mutable variables that are written to inside a pattern match. --- compiler/src/dotty/tools/dotc/typer/Nullables.scala | 2 +- tests/explicit-nulls/pos/match-flow-typing.scala | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/explicit-nulls/pos/match-flow-typing.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Nullables.scala b/compiler/src/dotty/tools/dotc/typer/Nullables.scala index 9104418d406f..f4748eb03849 100644 --- a/compiler/src/dotty/tools/dotc/typer/Nullables.scala +++ b/compiler/src/dotty/tools/dotc/typer/Nullables.scala @@ -445,7 +445,7 @@ object Nullables: else candidates -= name case None => traverseChildren(tree) - case _: (If | WhileDo | Typed) => + case _: (If | WhileDo | Typed | Match | CaseDef) => traverseChildren(tree) // assignments to candidate variables are OK here ... case _ => reachable = Set.empty // ... but not here diff --git a/tests/explicit-nulls/pos/match-flow-typing.scala b/tests/explicit-nulls/pos/match-flow-typing.scala new file mode 100644 index 000000000000..cda8b25da5ff --- /dev/null +++ b/tests/explicit-nulls/pos/match-flow-typing.scala @@ -0,0 +1,8 @@ +def m(): String = { + var x: String|Null = "foo" + 1 match { + case 1 => x = x + } + if(x == null) "foo" + else x +} From 74f6851f0f7db62f1fcdb9e2362a6c2b5944aa85 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Mon, 24 Jul 2023 15:33:19 -0400 Subject: [PATCH 2/2] additionally include writes under try/catch/finally --- compiler/src/dotty/tools/dotc/typer/Nullables.scala | 2 +- tests/explicit-nulls/pos/match-flow-typing.scala | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Nullables.scala b/compiler/src/dotty/tools/dotc/typer/Nullables.scala index f4748eb03849..68e3c0f8ccd6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Nullables.scala +++ b/compiler/src/dotty/tools/dotc/typer/Nullables.scala @@ -445,7 +445,7 @@ object Nullables: else candidates -= name case None => traverseChildren(tree) - case _: (If | WhileDo | Typed | Match | CaseDef) => + case _: (If | WhileDo | Typed | Match | CaseDef | untpd.ParsedTry) => traverseChildren(tree) // assignments to candidate variables are OK here ... case _ => reachable = Set.empty // ... but not here diff --git a/tests/explicit-nulls/pos/match-flow-typing.scala b/tests/explicit-nulls/pos/match-flow-typing.scala index cda8b25da5ff..200af36a73e0 100644 --- a/tests/explicit-nulls/pos/match-flow-typing.scala +++ b/tests/explicit-nulls/pos/match-flow-typing.scala @@ -6,3 +6,16 @@ def m(): String = { if(x == null) "foo" else x } + +def m2(): String = { + var x: String|Null = "foo" + try { + x = x + } catch { + case e => x = x + } finally { + x = x + } + if(x == null) "foo" + else x +}