@@ -41,6 +41,7 @@ import transform.SymUtils._
41
41
import transform .TypeUtils ._
42
42
import reporting .trace
43
43
import Nullables .{NotNullInfo , given }
44
+ import NullOpsDecorator ._
44
45
45
46
object Typer {
46
47
@@ -347,6 +348,16 @@ class Typer extends Namer
347
348
findRefRecur(NoType , BindingPrec .NothingBound , NoContext )
348
349
}
349
350
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
+
350
361
/** Attribute an identifier consisting of a simple name or wildcard
351
362
*
352
363
* @param tree The tree representing the identifier.
@@ -417,7 +428,9 @@ class Typer extends Namer
417
428
tree.withType(ownType)
418
429
}
419
430
420
- checkStableIdentPattern(tree1, pt)
431
+ val tree2 = toNotNullTermRef(tree1, pt)
432
+
433
+ checkStableIdentPattern(tree2, pt)
421
434
}
422
435
423
436
/** Check that a stable identifier pattern is indeed stable (SLS 8.1.5)
@@ -442,8 +455,11 @@ class Typer extends Namer
442
455
case qual =>
443
456
if (tree.name.isTypeName) checkStable(qual.tpe, qual.sourcePos)
444
457
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
447
463
else typedDynamicSelect(tree, Nil , pt)
448
464
}
449
465
@@ -1554,16 +1570,6 @@ class Typer extends Namer
1554
1570
typed(annot, defn.AnnotationClass .typeRef)
1555
1571
1556
1572
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
-
1567
1573
val ValDef (name, tpt, _) = vdef
1568
1574
completeAnnotations(vdef, sym)
1569
1575
if (sym.isOneOf(GivenOrImplicit )) checkImplicitConversionDefOK(sym)
@@ -2216,14 +2222,31 @@ class Typer extends Namer
2216
2222
case Some (xtree) =>
2217
2223
traverse(xtree :: rest)
2218
2224
case none =>
2219
- val defCtx = mdef match
2225
+ def defCtx = ctx.withNotNullInfos(initialNotNullInfos)
2226
+ val newCtx = if (ctx.owner.isTerm) {
2220
2227
// Keep preceding not null facts in the current context only if `mdef`
2221
2228
// 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 {
2227
2250
case mdef1 : DefDef if ! Inliner .bodyToInline(mdef1.symbol).isEmpty =>
2228
2251
buf += inlineExpansion(mdef1)
2229
2252
// replace body with expansion, because it will be used as inlined body
0 commit comments