Skip to content

Commit 10497c9

Browse files
olhotaknoti0na1
authored andcommitted
add tracking of NotNullInfo for Match, Case, Try trees (fix #21380)
1 parent 614170f commit 10497c9

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,14 +2135,18 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
21352135
case1
21362136
}
21372137
.asInstanceOf[List[CaseDef]]
2138-
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt)
2138+
var nni = sel.notNullInfo
2139+
if(cases1.nonEmpty) nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
2140+
assignType(cpy.Match(tree)(sel, cases1), sel, cases1).cast(pt).withNotNullInfo(nni)
21392141
}
21402142

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

21482152
def typedCases(cases: List[untpd.CaseDef], sel: Tree, wideSelType0: Type, pt: Type)(using Context): List[CaseDef] =
@@ -2216,7 +2220,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
22162220
pat1.putAttachment(InferredGadtConstraints, ctx.gadt)
22172221
if (pt1.isValueType) // insert a cast if body does not conform to expected type if we disregard gadt bounds
22182222
body1 = body1.ensureConforms(pt1)(using originalCtx)
2219-
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), pat1, body1)
2223+
val nni = pat1.notNullInfo.seq(
2224+
guard1.notNullInfoIf(false).alt(
2225+
guard1.notNullInfoIf(true).seq(body1.notNullInfo)
2226+
)
2227+
)
2228+
assignType(cpy.CaseDef(tree)(pat1, guard1, body1), pat1, body1).withNotNullInfo(nni)
22202229
}
22212230

22222231
val pat1 = typedPattern(tree.pat, wideSelType)(using gadtCtx)
@@ -2327,7 +2336,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
23272336
}: @unchecked
23282337
val finalizer1 = typed(tree.finalizer, defn.UnitType)
23292338
val cases2 = cases2x.asInstanceOf[List[CaseDef]]
2330-
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2)
2339+
val nni = expr2.notNullInfo.retractedInfo.seq(
2340+
cases2.map(_.notNullInfo.retractedInfo).fold(NotNullInfo.empty)(_.alt(_))
2341+
).seq(finalizer1.notNullInfo)
2342+
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(nni)
23312343
}
23322344

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

tests/explicit-nulls/neg/i21380.scala

Lines changed: 19 additions & 0 deletions
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+
}
Lines changed: 8 additions & 0 deletions
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)