From 793626428dba234019e65cb6402b83fe8d8e8cf7 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Tue, 16 Jan 2024 18:40:03 +0100 Subject: [PATCH 1/4] Passing NotNullInfos to a mutable field of a Completer --- .../src/dotty/tools/dotc/typer/Namer.scala | 6 ++++- .../src/dotty/tools/dotc/typer/Typer.scala | 3 +-- tests/explicit-nulls/pos/i19202.scala | 27 +++++++++++++++++++ tests/pos/i19202.scala | 27 +++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 tests/explicit-nulls/pos/i19202.scala create mode 100644 tests/pos/i19202.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index f8ced1c6599a..b0e82d922362 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -22,6 +22,7 @@ import parsing.JavaParsers.JavaParser import parsing.Parsers.Parser import Annotations.* import Inferencing.* +import Nullables.* import transform.ValueClasses.* import TypeErasure.erasure import reporting.* @@ -784,8 +785,11 @@ class Namer { typer: Typer => protected def localContext(owner: Symbol): FreshContext = ctx.fresh.setOwner(owner).setTree(original) + var myNotNullInfos: List[NotNullInfo] | Null = null + /** The context with which this completer was created */ - given creationContext: Context = ictx + given creationContext[T]: Context = + if myNotNullInfos == null then ictx else ictx.withNotNullInfos(myNotNullInfos.nn) // make sure testing contexts are not captured by completers assert(!ictx.reporter.isInstanceOf[ExploringReporter]) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 10d8f45b6d01..463c067ca69a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3365,8 +3365,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // The RHS of a val def should know about not null facts established // in preceding statements (unless the DefTree is completed ahead of time, // then it is impossible). - sym.info = Completer(completer.original)( - completer.creationContext.withNotNullInfos(ctx.notNullInfos)) + completer.myNotNullInfos = ctx.notNullInfos true case _ => // If it has been completed, then it must be because there is a forward reference diff --git a/tests/explicit-nulls/pos/i19202.scala b/tests/explicit-nulls/pos/i19202.scala new file mode 100644 index 000000000000..1bba0875f9a9 --- /dev/null +++ b/tests/explicit-nulls/pos/i19202.scala @@ -0,0 +1,27 @@ +class Test { + def test1(s: String | Null): Unit = { + if s == null then return + + case class XXX() + } + + def test2(s: String | Null): Unit = { + if s == "" then return + + case class XXX() + } + + def test3(s: String | Null): Unit = { + if s == null then return + + case class XXX() + () + } + + def test4(s: String | Null): String | Null = { + if s == null then return "" + + case class XXX() + "xxx" + } +} \ No newline at end of file diff --git a/tests/pos/i19202.scala b/tests/pos/i19202.scala new file mode 100644 index 000000000000..75226b0c8b65 --- /dev/null +++ b/tests/pos/i19202.scala @@ -0,0 +1,27 @@ +class Test { + def test1(s: String): Unit = { + if s == null then return + + case class XXX() + } + + def test2(s: String): Unit = { + if s == "" then return + + case class XXX() + } + + def test3(s: String): Unit = { + if s == null then return + + case class XXX() + () + } + + def test4(s: String): String = { + if s == null then return "" + + case class XXX() + "xxx" + } +} \ No newline at end of file From bc057dbb18cffd45ce461ee7f77eab8c7e95ea6d Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 19 Jan 2024 00:56:41 +0100 Subject: [PATCH 2/4] Make myNotNullInfos field private --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 5 ++++- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index b0e82d922362..86a84adca56d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -785,7 +785,7 @@ class Namer { typer: Typer => protected def localContext(owner: Symbol): FreshContext = ctx.fresh.setOwner(owner).setTree(original) - var myNotNullInfos: List[NotNullInfo] | Null = null + private var myNotNullInfos: List[NotNullInfo] | Null = null /** The context with which this completer was created */ given creationContext[T]: Context = @@ -794,6 +794,9 @@ class Namer { typer: Typer => // make sure testing contexts are not captured by completers assert(!ictx.reporter.isInstanceOf[ExploringReporter]) + def setNotNullInfos(infos: List[NotNullInfo]): Unit = + myNotNullInfos = infos + protected def typeSig(sym: Symbol): Type = original match case original: ValDef => if (sym.is(Module)) moduleValSig(sym) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 463c067ca69a..222640124db3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3361,11 +3361,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer mdef.getAttachment(SymOfTree) match { case Some(sym) => sym.infoOrCompleter match { case completer: Namer#Completer => - if (completer.creationContext.notNullInfos ne ctx.notNullInfos) + if completer.creationContext.notNullInfos ne ctx.notNullInfos then // The RHS of a val def should know about not null facts established // in preceding statements (unless the DefTree is completed ahead of time, // then it is impossible). - completer.myNotNullInfos = ctx.notNullInfos + completer.setNotNullInfos(ctx.notNullInfos) true case _ => // If it has been completed, then it must be because there is a forward reference From 9d1e5a6d9d9fb4392747ff15ca12fbe8eb4bf6a4 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 19 Jan 2024 01:04:13 +0100 Subject: [PATCH 3/4] Change the name of dummy type parameter --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 86a84adca56d..ecbb48f641cc 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -788,7 +788,7 @@ class Namer { typer: Typer => private var myNotNullInfos: List[NotNullInfo] | Null = null /** The context with which this completer was created */ - given creationContext[T]: Context = + given creationContext[Dummy_so_its_a_def]: Context = if myNotNullInfos == null then ictx else ictx.withNotNullInfos(myNotNullInfos.nn) // make sure testing contexts are not captured by completers From 44e63a113ee833fcb50250cc88157ced0d51fa3d Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 19 Jan 2024 12:19:09 +0100 Subject: [PATCH 4/4] Add a comment for myNotNullInfos --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index ecbb48f641cc..e9264366dfc0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -785,6 +785,7 @@ class Namer { typer: Typer => protected def localContext(owner: Symbol): FreshContext = ctx.fresh.setOwner(owner).setTree(original) + /** Stores the latest NotNullInfos (updated by `setNotNullInfos`) */ private var myNotNullInfos: List[NotNullInfo] | Null = null /** The context with which this completer was created */