Skip to content

Commit 9b62f71

Browse files
committed
Address PR comments
1 parent 5285598 commit 9b62f71

File tree

2 files changed

+119
-32
lines changed

2 files changed

+119
-32
lines changed

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

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2436,29 +2436,36 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
24362436
val capabilityProof = caughtExceptions.reduce(OrType(_, _, true))
24372437
untpd.Block(makeCanThrow(capabilityProof), expr)
24382438

2439-
/** Graphic explaination of NotNullInfo logic:
2439+
/** Graphic explanation of NotNullInfo logic:
24402440
* Leftward exit indicates exceptional case
24412441
* Downward exit indicates normal case
24422442
*
2443-
* ┌─────┐ α.retractedInfo
2443+
* ┌─────┐
24442444
* │ Try ├─────┬────────┬─────┐
24452445
* └──┬──┘ ▼ ▼ │
24462446
* │ ┌───────┐┌───────┐ │
2447-
* α │ │ Catch ││ Catch ├─┤
2447+
* │ │ Catch ││ Catch ├─┤
24482448
* │ └───┬───┘└───┬───┘ │
2449-
* │ β │ │ │
2450-
* └──┬─────┴────────┘ │
2451-
* │ γ = α.alt(β) │ ε = β.retractedInfo
2452-
* ▼ ▼
2453-
* ┌─────────┐ ┌─────────┐
2454-
* δ = type(ε)│ Finally ├──────┐ │ Finally ├─────────┐
2455-
* └────┬────┘ │ └────┬────┘ │
2456-
* │ │ ▼ ▼
2457-
* │ γ.seq(δ) └──────────────────────────►
2458-
* ▼ ε.seq(δ)
2459-
* We choose to use γ.seq(δ) as the NotNullInfo of the
2460-
* overall tree if all the catch cases have NothingType,
2461-
* otherwise we use ε.seq(δ).
2449+
* └─┬──────┴────────┘ │
2450+
* ▼ ▼
2451+
* ┌─────────┐ ┌─────────┐
2452+
* │ Finally ├──────┐ │ Finally ├──┐
2453+
* └────┬────┘ │ └────┬────┘ │
2454+
* ▼ └─────────┴───────┴─►
2455+
* α = tryEffect
2456+
* λ = α.retracted.seq.(catchEffects.reduce.alt)
2457+
* β = α.alt(λ)
2458+
* finallyCtx = β.retracted
2459+
* δ = finallyEffect
2460+
* resultNNInfo = β.seq(δ).alt(β.retracted.seq(δ).seq(empty.terminated))
2461+
*
2462+
* It is sufficient to type finally once provided that we type it in a context
2463+
* that considers all the paths before it that reach the finally. Since the NNinfo
2464+
* that we get from typing finally summarizes the effect of the finally, we can
2465+
* type the finally once and use the obtained NN info twice: once sequenced
2466+
* with β (normalNNInfo) and once sequenced with β.retractedInfo but post-sequenced
2467+
* by empty.terminated (to indicate that this path does not reach the code after
2468+
* the try-catch-finally).
24622469
*/
24632470
def typedTry(tree: untpd.Try, pt: Type)(using Context): Try =
24642471
val expr2 :: cases2x = harmonic(harmonize, pt) {
@@ -2478,25 +2485,21 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
24782485
expr1 :: cases1
24792486
}: @unchecked
24802487
val cases2 = cases2x.asInstanceOf[List[CaseDef]]
2481-
val tryNNInfo = expr2.notNullInfo
2488+
val exprNNInfo = expr2.notNullInfo
24822489
// It is possible to have non-exhaustive cases, and some exceptions are thrown and not caught.
24832490
// Therefore, the code in the finalizer and after the try block can only rely on the retracted
24842491
// info from the cases' body.
2485-
val catchNNInfo = if cases2.nonEmpty then
2486-
tryNNInfo.seq(cases2.map(_.notNullInfo).reduce(_.alt(_)))
2492+
val casesNNInfo = if cases2.nonEmpty then
2493+
exprNNInfo.retractedInfo.seq(cases2.map(_.notNullInfo).reduce(_.alt(_)))
24872494
else
2488-
NotNullInfo.empty
2489-
val normalResolveNNInfo = tryNNInfo.alt(catchNNInfo)
2490-
val exceptionalResolveNNInfo = catchNNInfo.retractedInfo
2491-
2492-
val finalizer1 = typed(tree.finalizer, defn.UnitType)(using ctx.addNotNullInfo(exceptionalResolveNNInfo))
2493-
val normalFinalNNInfo = normalResolveNNInfo.seq(finalizer1.notNullInfo)
2494-
val exceptionalFinalNNInfo = exceptionalResolveNNInfo.seq(finalizer1.notNullInfo)
2495-
val resNNInfo =
2496-
if (cases2.forall(_.tpe == defn.NothingType)) then
2497-
normalFinalNNInfo
2498-
else
2499-
exceptionalFinalNNInfo
2495+
NotNullInfo.empty.terminatedInfo
2496+
val catchSuccessNNInfo = exprNNInfo.alt(casesNNInfo)
2497+
val catchFailNNInfo = catchSuccessNNInfo.retractedInfo
2498+
2499+
val finalizer1 = typed(tree.finalizer, defn.UnitType)(using ctx.addNotNullInfo(catchFailNNInfo))
2500+
val normalFinalNNInfo = catchSuccessNNInfo.seq(finalizer1.notNullInfo)
2501+
val exceptionalFinalNNInfo = catchFailNNInfo.seq(finalizer1.notNullInfo)
2502+
val resNNInfo = normalFinalNNInfo.alt(exceptionalFinalNNInfo.seq(NotNullInfo.empty.terminatedInfo))
25002503
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(resNNInfo)
25012504

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

tests/explicit-nulls/neg/i21619.scala

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@ def test1: String =
1313
x.replace("", "") // error
1414

1515
def test2: String =
16+
var x: String | Null = null
17+
x = ""
18+
var i: Int = 1
19+
try
20+
i match
21+
case _ =>
22+
x = null
23+
throw new Exception()
24+
x = ""
25+
catch
26+
case e: NoSuchMethodError =>
27+
x = "e"
28+
x.replace("", "") // ok
29+
30+
// From i24296
31+
def test2_2: String =
1632
var x: String | Null = null
1733
x = ""
1834
var i: Int = 1
@@ -25,8 +41,43 @@ def test2: String =
2541
catch
2642
case e: Exception =>
2743
x = "e"
44+
case _ =>
2845
x.replace("", "") // error
2946

47+
def test2_3: String =
48+
var x: String | Null = null
49+
x = ""
50+
var i: Int = 1
51+
try
52+
i match
53+
case _ =>
54+
x = null
55+
throw new Exception()
56+
x = ""
57+
catch
58+
case e: NoSuchMethodError =>
59+
x = "e"
60+
case e: AbstractMethodError =>
61+
x = "e"
62+
x.replace("", "") // ok
63+
64+
def test2_4: String =
65+
var x: String | Null = null
66+
x = ""
67+
var i: Int = 1
68+
try
69+
i match
70+
case _ =>
71+
x = null
72+
throw new Exception()
73+
x = ""
74+
catch
75+
case e: NoSuchMethodError =>
76+
x = "e"
77+
case e: AbstractMethodError =>
78+
throw new Exception()
79+
x.replace("", "") // ok
80+
3081
def test3: String =
3182
var x: String | Null = null
3283
x = ""
@@ -126,6 +177,16 @@ def test9() =
126177
}
127178
x.trim() // error
128179

180+
def test9_2() =
181+
var x: String | Null = null
182+
try {
183+
x = ""
184+
} catch {
185+
case e: AssertionError =>
186+
throw e
187+
}
188+
x.trim() // ok
189+
129190
def test10() =
130191
var x: String | Null = null
131192
try {
@@ -163,4 +224,27 @@ def test12() =
163224
throw new Exception
164225
x = ""
165226
}
166-
x.trim() // ok
227+
x.trim() // ok
228+
229+
def test12_2() =
230+
var x: String | Null = null
231+
try {
232+
x = ""
233+
} catch {
234+
case e =>
235+
x = null
236+
throw e
237+
} finally {
238+
throw new Exception
239+
}
240+
x.trim() // ok
241+
242+
def test13() =
243+
var x: String | Null = null
244+
try {
245+
x = null
246+
throw new RuntimeException
247+
} finally {
248+
x.trim() // error
249+
}
250+
x.trim() // OK

0 commit comments

Comments
 (0)