@@ -1000,7 +1000,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1000
1000
untpd.unsplice(tree.expr).putAttachment(AscribedToUnit , ())
1001
1001
typed(tree.expr, underlyingTreeTpe.tpe.widenSkolem)
1002
1002
assignType(cpy.Typed (tree)(expr1, tpt), underlyingTreeTpe)
1003
- .withNotNullInfo(expr1.notNullInfo)
1004
1003
}
1005
1004
1006
1005
if (untpd.isWildcardStarArg(tree)) {
@@ -1333,11 +1332,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1333
1332
1334
1333
def thenPathInfo = cond1.notNullInfoIf(true ).seq(result.thenp.notNullInfo)
1335
1334
def elsePathInfo = cond1.notNullInfoIf(false ).seq(result.elsep.notNullInfo)
1336
- result.withNotNullInfo(
1337
- if result.thenp.tpe.isRef(defn.NothingClass ) then elsePathInfo
1338
- else if result.elsep.tpe.isRef(defn.NothingClass ) then thenPathInfo
1339
- else thenPathInfo.alt(elsePathInfo)
1340
- )
1335
+ result.withNotNullInfo(thenPathInfo.alt(elsePathInfo))
1341
1336
end typedIf
1342
1337
1343
1338
/** Decompose function prototype into a list of parameter prototypes and a result
@@ -1860,20 +1855,25 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1860
1855
case1
1861
1856
}
1862
1857
.asInstanceOf [List [CaseDef ]]
1863
- var nni = sel.notNullInfo
1864
- if cases1.nonEmpty then nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
1865
- assignType(cpy.Match (tree)(sel, cases1), sel, cases1).cast(pt).withNotNullInfo(nni)
1858
+ assignType(cpy.Match (tree)(sel, cases1), sel, cases1).cast(pt)
1859
+ .withNotNullInfo(notNullInfoFromCases(sel.notNullInfo, cases1))
1866
1860
}
1867
1861
1868
1862
// Overridden in InlineTyper for inline matches
1869
1863
def typedMatchFinish (tree : untpd.Match , sel : Tree , wideSelType : Type , cases : List [untpd.CaseDef ], pt : Type )(using Context ): Tree = {
1870
1864
val cases1 = harmonic(harmonize, pt)(typedCases(cases, sel, wideSelType, pt.dropIfProto))
1871
1865
.asInstanceOf [List [CaseDef ]]
1872
- var nni = sel.notNullInfo
1873
- if cases1.nonEmpty then nni = nni.seq(cases1.map(_.notNullInfo).reduce(_.alt(_)))
1874
- assignType(cpy.Match (tree)(sel, cases1), sel, cases1).withNotNullInfo(nni)
1866
+ assignType(cpy.Match (tree)(sel, cases1), sel, cases1)
1867
+ .withNotNullInfo(notNullInfoFromCases(sel.notNullInfo, cases1))
1875
1868
}
1876
1869
1870
+ private def notNullInfoFromCases (initInfo : NotNullInfo , cases : List [CaseDef ])(using Context ): NotNullInfo =
1871
+ if cases.isEmpty then
1872
+ // Empty cases is not allowed for match tree in the source code,
1873
+ // but it can be generated by inlining: `tests/pos/i19198.scala`.
1874
+ initInfo
1875
+ else cases.map(_.notNullInfo).reduce(_.alt(_))
1876
+
1877
1877
def typedCases (cases : List [untpd.CaseDef ], sel : Tree , wideSelType : Type , pt : Type )(using Context ): List [CaseDef ] =
1878
1878
var caseCtx = ctx
1879
1879
cases.mapconserve { cas =>
@@ -1960,7 +1960,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1960
1960
def typedLabeled (tree : untpd.Labeled )(using Context ): Labeled = {
1961
1961
val bind1 = typedBind(tree.bind, WildcardType ).asInstanceOf [Bind ]
1962
1962
val expr1 = typed(tree.expr, bind1.symbol.info)
1963
- assignType(cpy.Labeled (tree)(bind1, expr1))
1963
+ assignType(cpy.Labeled (tree)(bind1, expr1)).withNotNullInfo(expr1.notNullInfo.retractedInfo)
1964
1964
}
1965
1965
1966
1966
/** Type a case of a type match */
@@ -2010,7 +2010,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2010
2010
// Hence no adaptation is possible, and we assume WildcardType as prototype.
2011
2011
(from, proto)
2012
2012
val expr1 = typedExpr(tree.expr orElse untpd.syntheticUnitLiteral.withSpan(tree.span), proto)
2013
- assignType(cpy.Return (tree)(expr1, from))
2013
+ assignType(cpy.Return (tree)(expr1, from)).withNotNullInfo(expr1.notNullInfo.terminatedInfo)
2014
2014
end typedReturn
2015
2015
2016
2016
def typedWhileDo (tree : untpd.WhileDo )(using Context ): Tree =
@@ -2051,7 +2051,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2051
2051
val capabilityProof = caughtExceptions.reduce(OrType (_, _, true ))
2052
2052
untpd.Block (makeCanThrow(capabilityProof), expr)
2053
2053
2054
- def typedTry (tree : untpd.Try , pt : Type )(using Context ): Try = {
2054
+ def typedTry (tree : untpd.Try , pt : Type )(using Context ): Try =
2055
+ var nnInfo = NotNullInfo .empty
2055
2056
val expr2 :: cases2x = harmonic(harmonize, pt) {
2056
2057
// We want to type check tree.expr first to comput NotNullInfo, but `addCanThrowCapabilities`
2057
2058
// uses the types of patterns in `tree.cases` to determine the capabilities.
@@ -2063,18 +2064,26 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2063
2064
val casesEmptyBody1 = tree.cases.mapconserve(cpy.CaseDef (_)(body = EmptyTree ))
2064
2065
val casesEmptyBody2 = typedCases(casesEmptyBody1, EmptyTree , defn.ThrowableType , WildcardType )
2065
2066
val expr1 = typed(addCanThrowCapabilities(tree.expr, casesEmptyBody2), pt.dropIfProto)
2066
- val casesCtx = ctx.addNotNullInfo(expr1.notNullInfo.retractedInfo)
2067
+
2068
+ // Since we don't know at which point the the exception is thrown in the body,
2069
+ // we have to collect any reference that is once retracted.
2070
+ nnInfo = expr1.notNullInfo.retractedInfo
2071
+
2072
+ val casesCtx = ctx.addNotNullInfo(nnInfo)
2067
2073
val cases1 = typedCases(tree.cases, EmptyTree , defn.ThrowableType , pt.dropIfProto)(using casesCtx)
2068
2074
expr1 :: cases1
2069
2075
}: @ unchecked
2070
2076
val cases2 = cases2x.asInstanceOf [List [CaseDef ]]
2071
2077
2072
- var nni = expr2.notNullInfo.retractedInfo
2073
- if cases2.nonEmpty then nni = nni.seq(cases2.map(_.notNullInfo.retractedInfo).reduce(_.alt(_)))
2074
- val finalizer1 = typed(tree.finalizer, defn.UnitType )(using ctx.addNotNullInfo(nni))
2075
- nni = nni.seq(finalizer1.notNullInfo)
2076
- assignType(cpy.Try (tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(nni)
2077
- }
2078
+ // It is possible to have non-exhaustive cases, and some exceptions are thrown and not caught.
2079
+ // Therefore, the code in the finalizer and after the try block can only rely on the retracted
2080
+ // info from the cases' body.
2081
+ if cases2.nonEmpty then
2082
+ nnInfo = nnInfo.seq(cases2.map(_.notNullInfo.retractedInfo).reduce(_.alt(_)))
2083
+
2084
+ val finalizer1 = typed(tree.finalizer, defn.UnitType )(using ctx.addNotNullInfo(nnInfo))
2085
+ nnInfo = nnInfo.seq(finalizer1.notNullInfo)
2086
+ assignType(cpy.Try (tree)(expr2, cases2, finalizer1), expr2, cases2).withNotNullInfo(nnInfo)
2078
2087
2079
2088
def typedTry (tree : untpd.ParsedTry , pt : Type )(using Context ): Try =
2080
2089
val cases : List [untpd.CaseDef ] = tree.handler match
@@ -2088,15 +2097,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2088
2097
def typedThrow (tree : untpd.Throw )(using Context ): Tree =
2089
2098
val expr1 = typed(tree.expr, defn.ThrowableType )
2090
2099
val cap = checkCanThrow(expr1.tpe.widen, tree.span)
2091
- val res = Throw (expr1).withSpan(tree.span)
2100
+ var res = Throw (expr1).withSpan(tree.span)
2092
2101
if Feature .ccEnabled && ! cap.isEmpty && ! ctx.isAfterTyper then
2093
2102
// Record access to the CanThrow capabulity recovered in `cap` by wrapping
2094
- // the type of the `throw` (i.e. Nothing) in a `@requiresCapability` annotatoon .
2095
- Typed (res,
2103
+ // the type of the `throw` (i.e. Nothing) in a `@requiresCapability` annotation .
2104
+ res = Typed (res,
2096
2105
TypeTree (
2097
2106
AnnotatedType (res.tpe,
2098
2107
Annotation (defn.RequiresCapabilityAnnot , cap, tree.span))))
2099
- else res
2108
+ res.withNotNullInfo(expr1.notNullInfo.terminatedInfo)
2100
2109
2101
2110
def typedSeqLiteral (tree : untpd.SeqLiteral , pt : Type )(using Context ): SeqLiteral = {
2102
2111
val elemProto = pt.stripNull.elemType match {
@@ -2507,6 +2516,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2507
2516
val vdef1 = assignType(cpy.ValDef (vdef)(name, tpt1, rhs1), sym)
2508
2517
postProcessInfo(vdef1, sym)
2509
2518
vdef1.setDefTree
2519
+ val nnInfo = rhs1.notNullInfo
2520
+ vdef1.withNotNullInfo(if sym.is(Lazy ) then nnInfo.retractedInfo else nnInfo)
2510
2521
}
2511
2522
2512
2523
private def retractDefDef (sym : Symbol )(using Context ): Tree =
0 commit comments