Skip to content

Commit 0dc91e2

Browse files
committed
More PR changes
1 parent 9b62f71 commit 0dc91e2

File tree

2 files changed

+134
-25
lines changed

2 files changed

+134
-25
lines changed

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

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,20 +2452,17 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
24522452
* │ Finally ├──────┐ │ Finally ├──┐
24532453
* └────┬────┘ │ └────┬────┘ │
24542454
* ▼ └─────────┴───────┴─►
2455-
* α = tryEffect
2456-
* λ = α.retracted.seq.(catchEffects.reduce.alt)
2457-
* β = α.alt(λ)
2458-
* finallyCtx = β.retracted
2459-
* δ = finallyEffect
2460-
* resultNNInfo = β.seq(δ).alt(β.retracted.seq(δ).seq(empty.terminated))
2455+
* exprNNInfo = Effect of the try block if completed normally
2456+
* casesNNInfo = Effect of catch blocks completing normally
2457+
* normalAfterCasesInfo = Exceptional try followed by normal catches
2458+
* We type finalizer with normalAfterCasesInfo.retracted
24612459
*
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).
2460+
* Overall effect of try-catch-finally =
2461+
* resNNInfo =
2462+
* (exprNNInfo OR normalAfterCasesInfo) followed by normal finally block
2463+
*
2464+
* For all nninfo, if a tree can be typed using nninfo.retractedInfo, then it can
2465+
* also be typed using nninfo.
24692466
*/
24702467
def typedTry(tree: untpd.Try, pt: Type)(using Context): Try =
24712468
val expr2 :: cases2x = harmonic(harmonize, pt) {
@@ -2486,20 +2483,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
24862483
}: @unchecked
24872484
val cases2 = cases2x.asInstanceOf[List[CaseDef]]
24882485
val exprNNInfo = expr2.notNullInfo
2486+
val casesNNInfo =
2487+
cases2.map(_.notNullInfo)
2488+
.foldLeft(NotNullInfo.empty.terminatedInfo)(_.alt(_))
2489+
val normalAfterCasesInfo = exprNNInfo.retractedInfo.seq(casesNNInfo)
2490+
24892491
// It is possible to have non-exhaustive cases, and some exceptions are thrown and not caught.
24902492
// Therefore, the code in the finalizer and after the try block can only rely on the retracted
24912493
// info from the cases' body.
2492-
val casesNNInfo = if cases2.nonEmpty then
2493-
exprNNInfo.retractedInfo.seq(cases2.map(_.notNullInfo).reduce(_.alt(_)))
2494-
else
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))
2494+
val finalizer1 = typed(tree.finalizer, defn.UnitType)(using ctx.addNotNullInfo(normalAfterCasesInfo.retractedInfo))
2495+
val resNNInfo = exprNNInfo.alt(normalAfterCasesInfo).seq(finalizer1.notNullInfo)
25032496
assignType(cpy.Try(tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(resNNInfo)
25042497

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

tests/explicit-nulls/neg/i21619.scala

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
class SomeException extends Exception
2+
13
def test1: String =
24
var x: String | Null = null
35
x = ""
@@ -247,4 +249,118 @@ def test13() =
247249
} finally {
248250
x.trim() // error
249251
}
250-
x.trim() // OK
252+
x.trim() // OK
253+
254+
def test14() =
255+
var x: String | Null = ""
256+
x = ""
257+
try {
258+
try {
259+
} catch {
260+
case e =>
261+
x = null
262+
throw e
263+
}
264+
} catch {
265+
case e =>
266+
x.trim() // error
267+
}
268+
269+
270+
271+
def test15: String =
272+
var x: String | Null = ???
273+
var y: String | Null = ???
274+
// ...
275+
try
276+
x = null
277+
// ...
278+
x = ""
279+
catch
280+
case e: SomeException =>
281+
x = null
282+
// situation 1: don't throw or return
283+
// situation 2:
284+
return ""
285+
finally
286+
y = x
287+
// should always error on y.trim
288+
289+
y.trim // error (ideally, should error if situation 1, should not error if situation 2)
290+
291+
def test16: String =
292+
var x: String | Null = ???
293+
x = ""
294+
try
295+
// call some method that throws
296+
// ...
297+
x = ""
298+
catch
299+
case e: SomeException =>
300+
x = null
301+
// call some method that throws
302+
// ...
303+
x = "<error>"
304+
finally {}
305+
306+
x.trim() // ok
307+
308+
def test17: String =
309+
var x: String | Null = ???
310+
x = ""
311+
try
312+
// call some method that throws
313+
// ...
314+
x = ""
315+
catch
316+
case e: SomeException =>
317+
x = null
318+
// call some method that throws
319+
// ...
320+
x = "<error>"
321+
finally
322+
println(x.trim()) // error
323+
324+
""
325+
326+
def test18: String =
327+
var x: String | Null = ???
328+
var y: String | Null = ???
329+
// ...
330+
try
331+
x = null
332+
y = null
333+
// ...
334+
x = ""
335+
y = ""
336+
catch
337+
case e: SomeException =>
338+
x = null
339+
return ""
340+
finally {}
341+
342+
x.trim + y.trim
343+
344+
345+
def test19: String =
346+
var x: String | Null = ???
347+
try
348+
x = null
349+
catch
350+
case e: SomeException =>
351+
x = null
352+
throw e
353+
finally
354+
throw new Exception()
355+
x.trim // ok
356+
357+
def test20: String =
358+
var x: String | Null = ???
359+
x = ""
360+
try
361+
x = ""
362+
catch
363+
case e: SomeException =>
364+
x = ""
365+
finally {}
366+
x.trim // ok

0 commit comments

Comments
 (0)