diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index f8ced1c6599a..e9264366dfc0 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,12 +785,19 @@ 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 */ - given creationContext: Context = ictx + 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 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 10d8f45b6d01..222640124db3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3361,12 +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). - sym.info = Completer(completer.original)( - completer.creationContext.withNotNullInfos(ctx.notNullInfos)) + completer.setNotNullInfos(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