Skip to content

Commit 51dc1af

Browse files
olhotakWojciechMazur
authored andcommitted
add tracking of NotNullInfo for Match, Case, Try trees (fix #21380)
[Cherry-picked 10497c9]
1 parent 3b2435f commit 51dc1af

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

+16-4
Original file line numberDiff line numberDiff line change
@@ -1856,14 +1856,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
18561856
case1
18571857
}
18581858
.asInstanceOf[List[CaseDef]]
1859-
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt)
1859+
var nni = sel.notNullInfo
1860+
if(cases1.nonEmpty) nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
1861+
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt).withNotNullInfo(nni)
18601862
}
18611863

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

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

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

20522064
def typedTry(tree: untpd.ParsedTry, pt: Type)(using Context): Try =

tests/explicit-nulls/neg/i21380.scala

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@main def test() = {
2+
var x: String | Null = null
3+
if (false) {
4+
x = ""
5+
6+
} else {
7+
x = ""
8+
}
9+
try {
10+
x = ""
11+
throw new Exception()
12+
}
13+
catch {
14+
case e: Exception => {
15+
x = null
16+
}
17+
}
18+
x.replace("", "") // error
19+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@main def test() = {
2+
var x: String | Null = null
3+
x = ""
4+
1 match {
5+
case 1 => x = null
6+
}
7+
x.replace("", "") // error
8+
}

0 commit comments

Comments
 (0)