@@ -410,91 +410,109 @@ object TypeOps:
410
410
}
411
411
}
412
412
413
- /** An upper approximation of the given type `tp` that does not refer to any symbol in `symsToAvoid`.
413
+ /** An approximating map that drops NamedTypes matching `toAvoid` and wildcard types. */
414
+ abstract class AvoidMap (using Context ) extends AvoidWildcardsMap :
415
+ @ threadUnsafe lazy val localParamRefs = util.HashSet [Type ]()
416
+
417
+ def toAvoid (tp : NamedType ): Boolean
418
+
419
+ /** True iff all NamedTypes on this prefix are static */
420
+ override def isStaticPrefix (pre : Type )(using Context ): Boolean = pre match
421
+ case pre : NamedType =>
422
+ val sym = pre.currentSymbol
423
+ sym.is(Package ) || sym.isStatic && isStaticPrefix(pre.prefix)
424
+ case _ => true
425
+
426
+ override def apply (tp : Type ): Type = tp match
427
+ case tp : TermRef
428
+ if toAvoid(tp) =>
429
+ tp.info.widenExpr.dealias match {
430
+ case info : SingletonType => apply(info)
431
+ case info => range(defn.NothingType , apply(info))
432
+ }
433
+ case tp : TypeRef if toAvoid(tp) =>
434
+ tp.info match {
435
+ case info : AliasingBounds =>
436
+ apply(info.alias)
437
+ case TypeBounds (lo, hi) =>
438
+ range(atVariance(- variance)(apply(lo)), apply(hi))
439
+ case info : ClassInfo =>
440
+ range(defn.NothingType , apply(classBound(info)))
441
+ case _ =>
442
+ emptyRange // should happen only in error cases
443
+ }
444
+ case tp : ThisType =>
445
+ // ThisType is only used inside a class.
446
+ // Therefore, either they don't appear in the type to be avoided, or
447
+ // it must be a class that encloses the block whose type is to be avoided.
448
+ tp
449
+ case tp : LazyRef =>
450
+ if localParamRefs.contains(tp.ref) then tp
451
+ else if isExpandingBounds then emptyRange
452
+ else mapOver(tp)
453
+ case tl : HKTypeLambda =>
454
+ localParamRefs ++= tl.paramRefs
455
+ mapOver(tl)
456
+ case _ =>
457
+ super .apply(tp)
458
+ end apply
459
+
460
+ /** Three deviations from standard derivedSelect:
461
+ * 1. We first try a widening conversion to the type's info with
462
+ * the original prefix. Since the original prefix is known to
463
+ * be a subtype of the returned prefix, this can improve results.
464
+ * 2. Then, if the approximation result is a singleton reference C#x.type, we
465
+ * replace by the widened type, which is usually more natural.
466
+ * 3. Finally, we need to handle the case where the prefix type does not have a member
467
+ * named `tp.name` anymmore. In that case, we need to fall back to Bot..Top.
468
+ */
469
+ override def derivedSelect (tp : NamedType , pre : Type ) =
470
+ if (pre eq tp.prefix)
471
+ tp
472
+ else tryWiden(tp, tp.prefix).orElse {
473
+ if (tp.isTerm && variance > 0 && ! pre.isSingleton)
474
+ apply(tp.info.widenExpr)
475
+ else if (upper(pre).member(tp.name).exists)
476
+ super .derivedSelect(tp, pre)
477
+ else
478
+ range(defn.NothingType , defn.AnyType )
479
+ }
480
+ end AvoidMap
481
+
482
+ /** An upper approximation of the given type `tp` that does not refer to any symbol in `symsToAvoid`
483
+ * and does not contain any WildcardType.
414
484
* We need to approximate with ranges:
415
485
*
416
486
* term references to symbols in `symsToAvoid`,
417
487
* term references that have a widened type of which some part refers
418
488
* to a symbol in `symsToAvoid`,
419
489
* type references to symbols in `symsToAvoid`,
420
- * this types of classes in `symsToAvoid`.
421
490
*
422
491
* Type variables that would be interpolated to a type that
423
492
* needs to be widened are replaced by the widened interpolation instance.
493
+ *
494
+ * TODO: Could we replace some or all usages of this method by
495
+ * `LevelAvoidMap` instead? It would be good to investigate this in details
496
+ * but when I tried it, avoidance for inlined trees broke because `TreeMap`
497
+ * does not update `ctx.nestingLevel` when entering a block so I'm leaving
498
+ * this as Future Work™.
424
499
*/
425
500
def avoid (tp : Type , symsToAvoid : => List [Symbol ])(using Context ): Type = {
426
- val widenMap = new ApproximatingTypeMap {
501
+ val widenMap = new AvoidMap {
427
502
@ threadUnsafe lazy val forbidden = symsToAvoid.toSet
428
- @ threadUnsafe lazy val localParamRefs = util.HashSet [Type ]()
429
- def toAvoid (sym : Symbol ) = ! sym.isStatic && forbidden.contains(sym)
430
- def partsToAvoid = new NamedPartsAccumulator (tp => toAvoid(tp.symbol))
431
-
432
- /** True iff all NamedTypes on this prefix are static */
433
- override def isStaticPrefix (pre : Type )(using Context ): Boolean = pre match
434
- case pre : NamedType =>
435
- val sym = pre.currentSymbol
436
- sym.is(Package ) || sym.isStatic && isStaticPrefix(pre.prefix)
437
- case _ => true
438
-
439
- def apply (tp : Type ): Type = tp match
440
- case tp : TermRef
441
- if toAvoid(tp.symbol) || partsToAvoid(Nil , tp.info).nonEmpty =>
442
- tp.info.widenExpr.dealias match {
443
- case info : SingletonType => apply(info)
444
- case info => range(defn.NothingType , apply(info))
445
- }
446
- case tp : TypeRef if toAvoid(tp.symbol) =>
447
- tp.info match {
448
- case info : AliasingBounds =>
449
- apply(info.alias)
450
- case TypeBounds (lo, hi) =>
451
- range(atVariance(- variance)(apply(lo)), apply(hi))
452
- case info : ClassInfo =>
453
- range(defn.NothingType , apply(classBound(info)))
454
- case _ =>
455
- emptyRange // should happen only in error cases
456
- }
457
- case tp : ThisType =>
458
- // ThisType is only used inside a class.
459
- // Therefore, either they don't appear in the type to be avoided, or
460
- // it must be a class that encloses the block whose type is to be avoided.
461
- tp
503
+ def toAvoid (tp : NamedType ) =
504
+ val sym = tp.symbol
505
+ ! sym.isStatic && forbidden.contains(sym)
506
+
507
+ override def apply (tp : Type ): Type = tp match
462
508
case tp : TypeVar if mapCtx.typerState.constraint.contains(tp) =>
463
509
val lo = TypeComparer .instanceType(
464
510
tp.origin, fromBelow = variance > 0 || variance == 0 && tp.hasLowerBound)(using mapCtx)
465
511
val lo1 = apply(lo)
466
512
if (lo1 ne lo) lo1 else tp
467
- case tp : LazyRef =>
468
- if localParamRefs.contains(tp.ref) then tp
469
- else if isExpandingBounds then emptyRange
470
- else mapOver(tp)
471
- case tl : HKTypeLambda =>
472
- localParamRefs ++= tl.paramRefs
473
- mapOver(tl)
474
513
case _ =>
475
- mapOver (tp)
514
+ super .apply (tp)
476
515
end apply
477
-
478
- /** Three deviations from standard derivedSelect:
479
- * 1. We first try a widening conversion to the type's info with
480
- * the original prefix. Since the original prefix is known to
481
- * be a subtype of the returned prefix, this can improve results.
482
- * 2. Then, if the approximation result is a singleton reference C#x.type, we
483
- * replace by the widened type, which is usually more natural.
484
- * 3. Finally, we need to handle the case where the prefix type does not have a member
485
- * named `tp.name` anymmore. In that case, we need to fall back to Bot..Top.
486
- */
487
- override def derivedSelect (tp : NamedType , pre : Type ) =
488
- if (pre eq tp.prefix)
489
- tp
490
- else tryWiden(tp, tp.prefix).orElse {
491
- if (tp.isTerm && variance > 0 && ! pre.isSingleton)
492
- apply(tp.info.widenExpr)
493
- else if (upper(pre).member(tp.name).exists)
494
- super .derivedSelect(tp, pre)
495
- else
496
- range(defn.NothingType , defn.AnyType )
497
- }
498
516
}
499
517
500
518
widenMap(tp)
0 commit comments