@@ -1201,7 +1201,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1201
1201
untpd.unsplice(tree.expr).putAttachment(AscribedToUnit , ())
1202
1202
typed(tree.expr, underlyingTreeTpe.tpe.widenSkolem)
1203
1203
assignType(cpy.Typed (tree)(expr1, tpt), underlyingTreeTpe)
1204
- .withNotNullInfo(expr1.notNullInfo)
1205
1204
}
1206
1205
1207
1206
if (untpd.isWildcardStarArg(tree)) {
@@ -1551,11 +1550,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1551
1550
1552
1551
def thenPathInfo = cond1.notNullInfoIf(true ).seq(result.thenp.notNullInfo)
1553
1552
def elsePathInfo = cond1.notNullInfoIf(false ).seq(result.elsep.notNullInfo)
1554
- result.withNotNullInfo(
1555
- if result.thenp.tpe.isRef(defn.NothingClass ) then elsePathInfo
1556
- else if result.elsep.tpe.isRef(defn.NothingClass ) then thenPathInfo
1557
- else thenPathInfo.alt(elsePathInfo)
1558
- )
1553
+ result.withNotNullInfo(thenPathInfo.alt(elsePathInfo))
1559
1554
end typedIf
1560
1555
1561
1556
/** Decompose function prototype into a list of parameter prototypes and a result
@@ -2139,20 +2134,25 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2139
2134
case1
2140
2135
}
2141
2136
.asInstanceOf [List [CaseDef ]]
2142
- var nni = sel.notNullInfo
2143
- if cases1.nonEmpty then nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
2144
- assignType(cpy.Match (tree)(sel, cases1), sel, cases1).cast(pt).withNotNullInfo(nni)
2137
+ assignType(cpy.Match (tree)(sel, cases1), sel, cases1).cast(pt)
2138
+ .withNotNullInfo(notNullInfoFromCases(sel.notNullInfo, cases1))
2145
2139
}
2146
2140
2147
2141
// Overridden in InlineTyper for inline matches
2148
2142
def typedMatchFinish (tree : untpd.Match , sel : Tree , wideSelType : Type , cases : List [untpd.CaseDef ], pt : Type )(using Context ): Tree = {
2149
2143
val cases1 = harmonic(harmonize, pt)(typedCases(cases, sel, wideSelType, pt.dropIfProto))
2150
2144
.asInstanceOf [List [CaseDef ]]
2151
- var nni = sel.notNullInfo
2152
- if cases1.nonEmpty then nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
2153
- assignType(cpy.Match (tree)(sel, cases1), sel, cases1).withNotNullInfo(nni)
2145
+ assignType(cpy.Match (tree)(sel, cases1), sel, cases1)
2146
+ .withNotNullInfo(notNullInfoFromCases(sel.notNullInfo, cases1))
2154
2147
}
2155
2148
2149
+ private def notNullInfoFromCases (initInfo : NotNullInfo , cases : List [CaseDef ])(using Context ): NotNullInfo =
2150
+ if cases.isEmpty then
2151
+ // Empty cases is not allowed for match tree in the source code,
2152
+ // but it can be generated by inlining: `tests/pos/i19198.scala`.
2153
+ initInfo
2154
+ else cases.map(_.notNullInfo).reduce(_.alt(_))
2155
+
2156
2156
def typedCases (cases : List [untpd.CaseDef ], sel : Tree , wideSelType0 : Type , pt : Type )(using Context ): List [CaseDef ] =
2157
2157
var caseCtx = ctx
2158
2158
var wideSelType = wideSelType0
@@ -2241,7 +2241,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2241
2241
def typedLabeled (tree : untpd.Labeled )(using Context ): Labeled = {
2242
2242
val bind1 = typedBind(tree.bind, WildcardType ).asInstanceOf [Bind ]
2243
2243
val expr1 = typed(tree.expr, bind1.symbol.info)
2244
- assignType(cpy.Labeled (tree)(bind1, expr1))
2244
+ assignType(cpy.Labeled (tree)(bind1, expr1)).withNotNullInfo(expr1.notNullInfo.retractedInfo)
2245
2245
}
2246
2246
2247
2247
/** Type a case of a type match */
@@ -2291,7 +2291,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2291
2291
// Hence no adaptation is possible, and we assume WildcardType as prototype.
2292
2292
(from, proto)
2293
2293
val expr1 = typedExpr(tree.expr orElse untpd.syntheticUnitLiteral.withSpan(tree.span), proto)
2294
- assignType(cpy.Return (tree)(expr1, from))
2294
+ assignType(cpy.Return (tree)(expr1, from)).withNotNullInfo(expr1.notNullInfo.terminatedInfo)
2295
2295
end typedReturn
2296
2296
2297
2297
def typedWhileDo (tree : untpd.WhileDo )(using Context ): Tree =
@@ -2332,7 +2332,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2332
2332
val capabilityProof = caughtExceptions.reduce(OrType (_, _, true ))
2333
2333
untpd.Block (makeCanThrow(capabilityProof), expr)
2334
2334
2335
- def typedTry (tree : untpd.Try , pt : Type )(using Context ): Try = {
2335
+ def typedTry (tree : untpd.Try , pt : Type )(using Context ): Try =
2336
+ var nnInfo = NotNullInfo .empty
2336
2337
val expr2 :: cases2x = harmonic(harmonize, pt) {
2337
2338
// We want to type check tree.expr first to comput NotNullInfo, but `addCanThrowCapabilities`
2338
2339
// uses the types of patterns in `tree.cases` to determine the capabilities.
@@ -2344,18 +2345,26 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2344
2345
val casesEmptyBody1 = tree.cases.mapconserve(cpy.CaseDef (_)(body = EmptyTree ))
2345
2346
val casesEmptyBody2 = typedCases(casesEmptyBody1, EmptyTree , defn.ThrowableType , WildcardType )
2346
2347
val expr1 = typed(addCanThrowCapabilities(tree.expr, casesEmptyBody2), pt.dropIfProto)
2347
- val casesCtx = ctx.addNotNullInfo(expr1.notNullInfo.retractedInfo)
2348
+
2349
+ // Since we don't know at which point the the exception is thrown in the body,
2350
+ // we have to collect any reference that is once retracted.
2351
+ nnInfo = expr1.notNullInfo.retractedInfo
2352
+
2353
+ val casesCtx = ctx.addNotNullInfo(nnInfo)
2348
2354
val cases1 = typedCases(tree.cases, EmptyTree , defn.ThrowableType , pt.dropIfProto)(using casesCtx)
2349
2355
expr1 :: cases1
2350
2356
}: @ unchecked
2351
2357
val cases2 = cases2x.asInstanceOf [List [CaseDef ]]
2352
2358
2353
- var nni = expr2.notNullInfo.retractedInfo
2354
- if cases2.nonEmpty then nni = nni.seq(cases2.map(_.notNullInfo.retractedInfo).reduce(_.alt(_)))
2355
- val finalizer1 = typed(tree.finalizer, defn.UnitType )(using ctx.addNotNullInfo(nni))
2356
- nni = nni.seq(finalizer1.notNullInfo)
2357
- assignType(cpy.Try (tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(nni)
2358
- }
2359
+ // It is possible to have non-exhaustive cases, and some exceptions are thrown and not caught.
2360
+ // Therefore, the code in the finalizer and after the try block can only rely on the retracted
2361
+ // info from the cases' body.
2362
+ if cases2.nonEmpty then
2363
+ nnInfo = nnInfo.seq(cases2.map(_.notNullInfo.retractedInfo).reduce(_.alt(_)))
2364
+
2365
+ val finalizer1 = typed(tree.finalizer, defn.UnitType )(using ctx.addNotNullInfo(nnInfo))
2366
+ nnInfo = nnInfo.seq(finalizer1.notNullInfo)
2367
+ assignType(cpy.Try (tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(nnInfo)
2359
2368
2360
2369
def typedTry (tree : untpd.ParsedTry , pt : Type )(using Context ): Try =
2361
2370
val cases : List [untpd.CaseDef ] = tree.handler match
@@ -2369,15 +2378,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2369
2378
def typedThrow (tree : untpd.Throw )(using Context ): Tree =
2370
2379
val expr1 = typed(tree.expr, defn.ThrowableType )
2371
2380
val cap = checkCanThrow(expr1.tpe.widen, tree.span)
2372
- val res = Throw (expr1).withSpan(tree.span)
2381
+ var res = Throw (expr1).withSpan(tree.span)
2373
2382
if Feature .ccEnabled && ! cap.isEmpty && ! ctx.isAfterTyper then
2374
2383
// Record access to the CanThrow capabulity recovered in `cap` by wrapping
2375
2384
// the type of the `throw` (i.e. Nothing) in a `@requiresCapability` annotation.
2376
- Typed (res,
2385
+ res = Typed (res,
2377
2386
TypeTree (
2378
2387
AnnotatedType (res.tpe,
2379
2388
Annotation (defn.RequiresCapabilityAnnot , cap, tree.span))))
2380
- else res
2389
+ res.withNotNullInfo(expr1.notNullInfo.terminatedInfo)
2381
2390
2382
2391
def typedSeqLiteral (tree : untpd.SeqLiteral , pt : Type )(using Context ): SeqLiteral = {
2383
2392
val elemProto = pt.stripNull().elemType match {
@@ -2842,6 +2851,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2842
2851
val vdef1 = assignType(cpy.ValDef (vdef)(name, tpt1, rhs1), sym)
2843
2852
postProcessInfo(vdef1, sym)
2844
2853
vdef1.setDefTree
2854
+ val nnInfo = rhs1.notNullInfo
2855
+ vdef1.withNotNullInfo(if sym.is(Lazy ) then nnInfo.retractedInfo else nnInfo)
2845
2856
}
2846
2857
2847
2858
private def retractDefDef (sym : Symbol )(using Context ): Tree =
0 commit comments