Skip to content

Commit

Permalink
add tracking of NotNullInfo for Match, Case, Try trees (fix #21380)
Browse files Browse the repository at this point in the history
[Cherry-picked 10497c9]
  • Loading branch information
olhotak authored and WojciechMazur committed Dec 3, 2024
1 parent 3b2435f commit 51dc1af
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 4 deletions.
20 changes: 16 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1856,14 +1856,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case1
}
.asInstanceOf[List[CaseDef]]
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt)
var nni = sel.notNullInfo
if(cases1.nonEmpty) nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt).withNotNullInfo(nni)
}

// Overridden in InlineTyper for inline matches
def typedMatchFinish(tree: untpd.Match, sel: Tree, wideSelType: Type, cases: List[untpd.CaseDef], pt: Type)(using Context): Tree = {
val cases1 = harmonic(harmonize, pt)(typedCases(cases, sel, wideSelType, pt.dropIfProto))
.asInstanceOf[List[CaseDef]]
assignType(cpy.Match(tree)(sel, cases1), sel, cases1)
var nni = sel.notNullInfo
if(cases1.nonEmpty) nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).withNotNullInfo(nni)
}

def typedCases(cases: List[untpd.CaseDef], sel: Tree, wideSelType: Type, pt: Type)(using Context): List[CaseDef] =
Expand Down Expand Up @@ -1935,7 +1939,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
pat1.putAttachment(InferredGadtConstraints, ctx.gadt)
if (pt1.isValueType) // insert a cast if body does not conform to expected type if we disregard gadt bounds
body1 = body1.ensureConforms(pt1)(using originalCtx)
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), pat1, body1)
val nni = pat1.notNullInfo.seq(
guard1.notNullInfoIf(false).alt(
guard1.notNullInfoIf(true).seq(body1.notNullInfo)
)
)
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), pat1, body1).withNotNullInfo(nni)
}

val pat1 = typedPattern(tree.pat, wideSelType)(using gadtCtx)
Expand Down Expand Up @@ -2046,7 +2055,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
}: @unchecked
val finalizer1 = typed(tree.finalizer, defn.UnitType)
val cases2 = cases2x.asInstanceOf[List[CaseDef]]
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2)
val nni = expr2.notNullInfo.retractedInfo.seq(
cases2.map(_.notNullInfo.retractedInfo).fold(NotNullInfo.empty)(_.alt(_))
).seq(finalizer1.notNullInfo)
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(nni)
}

def typedTry(tree: untpd.ParsedTry, pt: Type)(using Context): Try =
Expand Down
19 changes: 19 additions & 0 deletions tests/explicit-nulls/neg/i21380.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@main def test() = {
var x: String | Null = null
if (false) {
x = ""

} else {
x = ""
}
try {
x = ""
throw new Exception()
}
catch {
case e: Exception => {
x = null
}
}
x.replace("", "") // error
}
8 changes: 8 additions & 0 deletions tests/explicit-nulls/neg/i21380b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@main def test() = {
var x: String | Null = null
x = ""
1 match {
case 1 => x = null
}
x.replace("", "") // error
}

0 comments on commit 51dc1af

Please sign in to comment.