Skip to content

Commit 3d8ccc3

Browse files
committed
add tracking of NotNullInfo for Match, Case, Try trees (fix #21380)
1 parent b825f5a commit 3d8ccc3

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
@@ -2120,14 +2120,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
21202120
case1
21212121
}
21222122
.asInstanceOf[List[CaseDef]]
2123-
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt)
2123+
var nni = sel.notNullInfo
2124+
if(cases1.nonEmpty) nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
2125+
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt).withNotNullInfo(nni)
21242126
}
21252127

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

21332137
def typedCases(cases: List[untpd.CaseDef], sel: Tree, wideSelType0: Type, pt: Type)(using Context): List[CaseDef] =
@@ -2201,7 +2205,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
22012205
pat1.putAttachment(InferredGadtConstraints, ctx.gadt)
22022206
if (pt1.isValueType) // insert a cast if body does not conform to expected type if we disregard gadt bounds
22032207
body1 = body1.ensureConforms(pt1)(using originalCtx)
2204-
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), pat1, body1)
2208+
val nni = pat1.notNullInfo.seq(
2209+
guard1.notNullInfoIf(false).alt(
2210+
guard1.notNullInfoIf(true).seq(body1.notNullInfo)
2211+
)
2212+
)
2213+
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), pat1, body1).withNotNullInfo(nni)
22052214
}
22062215

22072216
val pat1 = typedPattern(tree.pat, wideSelType)(using gadtCtx)
@@ -2312,7 +2321,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
23122321
}: @unchecked
23132322
val finalizer1 = typed(tree.finalizer, defn.UnitType)
23142323
val cases2 = cases2x.asInstanceOf[List[CaseDef]]
2315-
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2)
2324+
val nni = expr2.notNullInfo.retractedInfo.seq(
2325+
cases2.map(_.notNullInfo.retractedInfo).fold(NotNullInfo.empty)(_.alt(_))
2326+
).seq(finalizer1.notNullInfo)
2327+
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(nni)
23162328
}
23172329

23182330
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)