@@ -41,6 +41,7 @@ import transform.SymUtils._
4141import transform .TypeUtils ._
4242import reporting .trace
4343import Nullables .{NotNullInfo , given }
44+ import NullOpsDecorator ._
4445
4546object Typer {
4647
@@ -347,6 +348,16 @@ class Typer extends Namer
347348 findRefRecur(NoType , BindingPrec .NothingBound , NoContext )
348349 }
349350
351+ // If `tree`'s type is a `TermRef` identified by flow typing to be non-null, then
352+ // cast away `tree`s nullability. Otherwise, `tree` remains unchanged.
353+ def toNotNullTermRef (tree : Tree , pt : Type )(implicit ctx : Context ): Tree = tree.tpe match
354+ case ref @ OrNull (tpnn) : TermRef
355+ if pt != AssignProto && // Ensure it is not the lhs of Assign
356+ ctx.notNullInfos.impliesNotNull(ref) =>
357+ tree.select(defn.Any_typeCast ).appliedToType(AndType (ref, tpnn))
358+ case _ =>
359+ tree
360+
350361 /** Attribute an identifier consisting of a simple name or wildcard
351362 *
352363 * @param tree The tree representing the identifier.
@@ -417,7 +428,9 @@ class Typer extends Namer
417428 tree.withType(ownType)
418429 }
419430
420- checkStableIdentPattern(tree1, pt)
431+ val tree2 = toNotNullTermRef(tree1, pt)
432+
433+ checkStableIdentPattern(tree2, pt)
421434 }
422435
423436 /** Check that a stable identifier pattern is indeed stable (SLS 8.1.5)
@@ -442,8 +455,11 @@ class Typer extends Namer
442455 case qual =>
443456 if (tree.name.isTypeName) checkStable(qual.tpe, qual.sourcePos)
444457 val select = assignType(cpy.Select (tree)(qual, tree.name), qual)
445- if (select.tpe ne TryDynamicCallType ) ConstFold (checkStableIdentPattern(select, pt))
446- else if (pt.isInstanceOf [FunOrPolyProto ] || pt == AssignProto ) select
458+
459+ val select1 = toNotNullTermRef(select, pt)
460+
461+ if (select1.tpe ne TryDynamicCallType ) ConstFold (checkStableIdentPattern(select1, pt))
462+ else if (pt.isInstanceOf [FunOrPolyProto ] || pt == AssignProto ) select1
447463 else typedDynamicSelect(tree, Nil , pt)
448464 }
449465
@@ -1554,16 +1570,6 @@ class Typer extends Namer
15541570 typed(annot, defn.AnnotationClass .typeRef)
15551571
15561572 def typedValDef (vdef : untpd.ValDef , sym : Symbol )(implicit ctx : Context ): Tree = {
1557- sym.infoOrCompleter match
1558- case completer : Namer # Completer
1559- if completer.creationContext.notNullInfos ne ctx.notNullInfos =>
1560- // The RHS of a val def should know about not null facts established
1561- // in preceding statements (unless the ValDef is completed ahead of time,
1562- // then it is impossible).
1563- vdef.symbol.info = Completer (completer.original)(
1564- given completer .creationContext.withNotNullInfos(ctx.notNullInfos))
1565- case _ =>
1566-
15671573 val ValDef (name, tpt, _) = vdef
15681574 completeAnnotations(vdef, sym)
15691575 if (sym.isOneOf(GivenOrImplicit )) checkImplicitConversionDefOK(sym)
@@ -2216,14 +2222,31 @@ class Typer extends Namer
22162222 case Some (xtree) =>
22172223 traverse(xtree :: rest)
22182224 case none =>
2219- val defCtx = mdef match
2225+ def defCtx = ctx.withNotNullInfos(initialNotNullInfos)
2226+ val newCtx = if (ctx.owner.isTerm) {
22202227 // Keep preceding not null facts in the current context only if `mdef`
22212228 // cannot be executed out-of-sequence.
2222- case _ : ValDef if ! mdef.mods.is(Lazy ) && ctx.owner.isTerm =>
2223- ctx // all preceding statements will have been executed in this case
2224- case _ =>
2225- ctx.withNotNullInfos(initialNotNullInfos)
2226- typed(mdef)(given defCtx ) match {
2229+ // We have to check the Completer of symbol befor typedValDef,
2230+ // otherwise the symbol is already completed using creation context.
2231+ mdef.getAttachment(SymOfTree ).map(s => (s, s.infoOrCompleter)) match {
2232+ case Some ((sym, completer : Namer # Completer )) =>
2233+ if (completer.creationContext.notNullInfos ne ctx.notNullInfos)
2234+ // The RHS of a val def should know about not null facts established
2235+ // in preceding statements (unless the DefTree is completed ahead of time,
2236+ // then it is impossible).
2237+ sym.info = Completer (completer.original)(
2238+ given completer .creationContext.withNotNullInfos(ctx.notNullInfos))
2239+ ctx // all preceding statements will have been executed in this case
2240+ case _ =>
2241+ // If it has been completed, then it must be because there is a forward reference
2242+ // to the definition in the program. Hence, we don't Keep preceding not null facts
2243+ // in the current context.
2244+ defCtx
2245+ }
2246+ }
2247+ else defCtx
2248+
2249+ typed(mdef)(given newCtx ) match {
22272250 case mdef1 : DefDef if ! Inliner .bodyToInline(mdef1.symbol).isEmpty =>
22282251 buf += inlineExpansion(mdef1)
22292252 // replace body with expansion, because it will be used as inlined body
0 commit comments