Skip to content

Commit

Permalink
Treat asserted set of terminated NotNullInfo as universal set; fix test
Browse files Browse the repository at this point in the history
  • Loading branch information
noti0na1 committed Dec 7, 2024
1 parent 158af7d commit 00430c0
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 19 deletions.
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -777,13 +777,13 @@ object Contexts {

extension (c: Context)
def addNotNullInfo(info: NotNullInfo) =
c.withNotNullInfos(c.notNullInfos.extendWith(info))
if c.explicitNulls then c.withNotNullInfos(c.notNullInfos.extendWith(info)) else c

def addNotNullRefs(refs: Set[TermRef]) =
c.addNotNullInfo(NotNullInfo(refs, Set()))
if c.explicitNulls then c.addNotNullInfo(NotNullInfo(refs, Set())) else c

def withNotNullInfos(infos: List[NotNullInfo]): Context =
if c.notNullInfos eq infos then c else c.fresh.setNotNullInfos(infos)
if !c.explicitNulls || (c.notNullInfos eq infos) then c else c.fresh.setNotNullInfos(infos)

def relaxedOverrideContext: Context =
c.withModeBits(c.mode &~ Mode.SafeNulls | Mode.RelaxedOverriding)
Expand Down
22 changes: 12 additions & 10 deletions compiler/src/dotty/tools/dotc/typer/Nullables.scala
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ object Nullables:
*/
@tailrec def impliesNotNull(ref: TermRef): Boolean = infos match
case info :: infos1 =>
if info.asserted != null && info.asserted.contains(ref) then true
if info.asserted == null || info.asserted.contains(ref) then true
else if info.retracted.contains(ref) then false
else infos1.impliesNotNull(ref)
case _ =>
Expand Down Expand Up @@ -315,8 +315,8 @@ object Nullables:
extension (tree: Tree)

/* The `tree` with added nullability attachment */
def withNotNullInfo(info: NotNullInfo): tree.type =
if !info.isEmpty then tree.putAttachment(NNInfo, info)
def withNotNullInfo(info: NotNullInfo)(using Context): tree.type =
if ctx.explicitNulls && !info.isEmpty then tree.putAttachment(NNInfo, info)
tree

/* Collect the nullability info from parts of `tree` */
Expand All @@ -335,13 +335,15 @@ object Nullables:

/* The nullability info of `tree` */
def notNullInfo(using Context): NotNullInfo =
val tree1 = stripInlined(tree)
tree1.getAttachment(NNInfo) match
case Some(info) if !ctx.erasedTypes => info
case _ =>
val nnInfo = tree1.collectNotNullInfo
tree1.withNotNullInfo(nnInfo)
nnInfo
if !ctx.explicitNulls then NotNullInfo.empty
else
val tree1 = stripInlined(tree)
tree1.getAttachment(NNInfo) match
case Some(info) if !ctx.erasedTypes => info
case _ =>
val nnInfo = tree1.collectNotNullInfo
tree1.withNotNullInfo(nnInfo)
nnInfo

/* The nullability info of `tree`, assuming it is a condition that evaluates to `c` */
def notNullInfoIf(c: Boolean)(using Context): NotNullInfo =
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2849,6 +2849,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
postProcessInfo(vdef1, sym)
vdef1.setDefTree
val nnInfo = rhs1.notNullInfo
vdef1.withNotNullInfo(if sym.is(Lazy) then nnInfo.retractedInfo else nnInfo)
}

private def retractDefDef(sym: Symbol)(using Context): Tree =
Expand Down
17 changes: 17 additions & 0 deletions tests/explicit-nulls/pos/after-termination.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class C(val x: Int, val next: C | Null)

def test1(x: String | Null, c: C | Null): Int =
return 0
// We know that the following code is unreachable,
// so we can treat `x`, `c`, and any variable/path non-nullable.
x.length + c.next.x

def test2(x: String | Null, c: C | Null): Int =
throw new Exception()
x.length + c.next.x

def fail(): Nothing = ???

def test3(x: String | Null, c: C | Null): Int =
fail()
x.length + c.next.x
12 changes: 6 additions & 6 deletions tests/explicit-nulls/unsafe-common/unsafe-overload.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class S {
val o: O = ???

locally {
def h1(hh: String => String) = ???
def h2(hh: Array[String] => Array[String]) = ???
def h1(hh: String => String): Unit = ???
def h2(hh: Array[String] => Array[String]): Unit = ???
def f1(x: String | Null): String | Null = ???
def f2(x: Array[String | Null]): Array[String | Null] = ???

Expand All @@ -29,10 +29,10 @@ class S {
}

locally {
def h1(hh: String | Null => String | Null) = ???
def h2(hh: Array[String | Null] => Array[String | Null]) = ???
def h1(hh: String | Null => String | Null): Unit = ???
def h2(hh: Array[String | Null] => Array[String | Null]): Unit = ???
def g1(x: String): String = ???
def g2(x: Array[String]): Array[String] = ???
def g2(x: Array[String]): Array[String] = ???

h1(g1) // error
h1(o.g) // error
Expand All @@ -51,7 +51,7 @@ class S {

locally {
def g1(x: String): String = ???
def g2(x: Array[String]): Array[String] = ???
def g2(x: Array[String]): Array[String] = ???

o.i(g1) // error
o.i(g2) // error
Expand Down

0 comments on commit 00430c0

Please sign in to comment.