Skip to content

Commit 158af7d

Browse files
committed
Fix deep NotNullInfo
1 parent f859afe commit 158af7d

File tree

4 files changed

+57
-20
lines changed

4 files changed

+57
-20
lines changed

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,7 @@ trait Applications extends Compatibility {
11341134
case _ => ()
11351135
else ()
11361136

1137-
fun1.tpe match {
1137+
val result = fun1.tpe match {
11381138
case err: ErrorType => cpy.Apply(tree)(fun1, proto.typedArgs()).withType(err)
11391139
case TryDynamicCallType =>
11401140
val isInsertedApply = fun1 match {
@@ -1208,6 +1208,11 @@ trait Applications extends Compatibility {
12081208
else tryWithImplicitOnQualifier(fun1, proto).getOrElse(fail))
12091209
}
12101210
}
1211+
1212+
if result.tpe.isNothingType then
1213+
val nnInfo = result.notNullInfo
1214+
result.withNotNullInfo(nnInfo.terminatedInfo)
1215+
else result
12111216
}
12121217

12131218
/** Convert expression like

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

+37-17
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,29 @@ object Nullables:
319319
if !info.isEmpty then tree.putAttachment(NNInfo, info)
320320
tree
321321

322+
/* Collect the nullability info from parts of `tree` */
323+
def collectNotNullInfo(using Context): NotNullInfo = tree match
324+
case Typed(expr, _) =>
325+
expr.notNullInfo
326+
case Apply(fn, args) =>
327+
val argsInfo = args.map(_.notNullInfo)
328+
val fnInfo = fn.notNullInfo
329+
argsInfo.foldLeft(fnInfo)(_ seq _)
330+
case TypeApply(fn, _) =>
331+
fn.notNullInfo
332+
case _ =>
333+
// Other cases are handled specially in typer.
334+
NotNullInfo.empty
335+
322336
/* The nullability info of `tree` */
323337
def notNullInfo(using Context): NotNullInfo =
324-
stripInlined(tree).getAttachment(NNInfo) match
338+
val tree1 = stripInlined(tree)
339+
tree1.getAttachment(NNInfo) match
325340
case Some(info) if !ctx.erasedTypes => info
326-
case _ => NotNullInfo.empty
341+
case _ =>
342+
val nnInfo = tree1.collectNotNullInfo
343+
tree1.withNotNullInfo(nnInfo)
344+
nnInfo
327345

328346
/* The nullability info of `tree`, assuming it is a condition that evaluates to `c` */
329347
def notNullInfoIf(c: Boolean)(using Context): NotNullInfo =
@@ -404,21 +422,23 @@ object Nullables:
404422
end extension
405423

406424
extension (tree: Assign)
407-
def computeAssignNullable()(using Context): tree.type = tree.lhs match
408-
case TrackedRef(ref) =>
409-
val rhstp = tree.rhs.typeOpt
410-
if ctx.explicitNulls && ref.isNullableUnion then
411-
if rhstp.isNullType || rhstp.isNullableUnion then
412-
// If the type of rhs is nullable (`T|Null` or `Null`), then the nullability of the
413-
// lhs variable is no longer trackable. We don't need to check whether the type `T`
414-
// is correct here, as typer will check it.
415-
tree.withNotNullInfo(NotNullInfo(Set(), Set(ref)))
416-
else
417-
// If the initial type is nullable and the assigned value is non-null,
418-
// we add it to the NotNull.
419-
tree.withNotNullInfo(NotNullInfo(Set(ref), Set()))
420-
else tree
421-
case _ => tree
425+
def computeAssignNullable()(using Context): tree.type =
426+
var nnInfo = tree.rhs.notNullInfo
427+
tree.lhs match
428+
case TrackedRef(ref) if ctx.explicitNulls && ref.isNullableUnion =>
429+
nnInfo = nnInfo.seq:
430+
val rhstp = tree.rhs.typeOpt
431+
if rhstp.isNullType || rhstp.isNullableUnion then
432+
// If the type of rhs is nullable (`T|Null` or `Null`), then the nullability of the
433+
// lhs variable is no longer trackable. We don't need to check whether the type `T`
434+
// is correct here, as typer will check it.
435+
NotNullInfo(Set(), Set(ref))
436+
else
437+
// If the initial type is nullable and the assigned value is non-null,
438+
// we add it to the NotNull.
439+
NotNullInfo(Set(ref), Set())
440+
case _ =>
441+
tree.withNotNullInfo(nnInfo)
422442
end extension
423443

424444
private val analyzedOps = Set(nme.EQ, nme.NE, nme.eq, nme.ne, nme.ZAND, nme.ZOR, nme.UNARY_!)

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

-1
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12011201
untpd.unsplice(tree.expr).putAttachment(AscribedToUnit, ())
12021202
typed(tree.expr, underlyingTreeTpe.tpe.widenSkolem)
12031203
assignType(cpy.Typed(tree)(expr1, tpt), underlyingTreeTpe)
1204-
.withNotNullInfo(expr1.notNullInfo)
12051204
}
12061205

12071206
if (untpd.isWildcardStarArg(tree)) {

tests/explicit-nulls/neg/i21619.scala

+14-1
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,17 @@ def test5: Unit =
7676
catch
7777
case _ =>
7878
val z1: String = x.replace("", "") // error
79-
val z2: String = y.replace("", "")
79+
val z2: String = y.replace("", "")
80+
81+
def test6 = {
82+
var x: String | Null = ""
83+
var y: String = ""
84+
x = ""
85+
y = if (false) x else 1 match {
86+
case _ => {
87+
x = null
88+
y
89+
}
90+
}
91+
x.replace("", "") // error
92+
}

0 commit comments

Comments
 (0)