@@ -2501,10 +2501,36 @@ object Types {
2501
2501
2502
2502
/** A reference with the initial symbol in `symd` has an info that
2503
2503
* might depend on the given prefix.
2504
+ * Note: If T is an abstract type in trait or class C, its info depends
2505
+ * even on C.this if class C has a self type that refines the info of T.
2506
+ * Currently, "refines" means an actual refinement type that constrains the
2507
+ * name `T`. We should try to extend that also to other classes that introduce
2508
+ * a new bining for `T`. Furthermore, we should also treat term members
2509
+ * in this way.
2504
2510
*/
2505
2511
private def infoDependsOnPrefix (symd : SymDenotation , prefix : Type )(using Context ): Boolean =
2512
+
2513
+ def refines (tp : Type , name : Name ): Boolean = tp match
2514
+ case AndType (tp1, tp2) => refines(tp1, name) || refines(tp2, name)
2515
+ case RefinedType (parent, rname, _) => rname == name || refines(parent, name)
2516
+ case tp : RecType => refines(tp.parent, name)
2517
+ case _ => false
2518
+
2519
+ def givenSelfTypeOrCompleter (cls : Symbol ) = cls.infoOrCompleter match
2520
+ case cinfo : ClassInfo =>
2521
+ cinfo.selfInfo match
2522
+ case sym : Symbol => sym.infoOrCompleter
2523
+ case tpe : Type => tpe
2524
+ case _ => NoType
2525
+
2506
2526
symd.maybeOwner.membersNeedAsSeenFrom(prefix) && ! symd.is(NonMember )
2507
- || prefix.isInstanceOf [Types .ThisType ] && symd.is(Opaque ) // see pos/i11277.scala for a test where this matters
2527
+ || prefix.match
2528
+ case prefix : Types .ThisType =>
2529
+ symd.isAbstractType
2530
+ && prefix.sameThis(symd.maybeOwner.thisType)
2531
+ && refines(givenSelfTypeOrCompleter(prefix.cls), symd.name)
2532
+ case _ => false
2533
+ end infoDependsOnPrefix
2508
2534
2509
2535
/** Is this a reference to a class or object member with an info that might depend
2510
2536
* on the prefix?
@@ -2653,40 +2679,19 @@ object Types {
2653
2679
else this
2654
2680
2655
2681
/** A reference like this one, but with the given denotation, if it exists.
2656
- * Returns a new named type with the denotation's symbol if that symbol exists, and
2657
- * one of the following alternatives applies:
2658
- * 1. The current designator is a symbol and the symbols differ, or
2659
- * 2. The current designator is a name and the new symbolic named type
2660
- * does not have a currently known denotation.
2661
- * 3. The current designator is a name and the new symbolic named type
2662
- * has the same info as the current info
2663
- * Returns a new named type with a name as designator if the denotation is
2664
- * overloaded and the name is different from the current designator.
2665
- * Otherwise the current denotation is overwritten with the given one.
2666
- *
2667
- * Note: (2) and (3) are a "lock in mechanism" where a reference with a name as
2668
- * designator can turn into a symbolic reference.
2669
- *
2670
- * Note: This is a subtle dance to keep the balance between going to symbolic
2671
- * references as much as we can (since otherwise we'd risk getting cycles)
2672
- * and to still not lose any type info in the denotation (since symbolic
2673
- * references often recompute their info directly from the symbol's info).
2674
- * A test case is neg/opaque-self-encoding.scala.
2682
+ * Returns a new named type with the denotation's symbol as designator
2683
+ * if that symbol exists and it is different from the current designator.
2684
+ * Returns a new named type with the denotations's name as designator
2685
+ * if the denotation is overloaded and its name is different from the
2686
+ * current designator.
2675
2687
*/
2676
2688
final def withDenot (denot : Denotation )(using Context ): ThisType =
2677
2689
if denot.exists then
2678
2690
val adapted =
2679
2691
if denot.symbol.exists then withSym(denot.symbol)
2680
2692
else if denot.isOverloaded then withName(denot.name)
2681
2693
else this
2682
- val result =
2683
- if adapted.eq(this )
2684
- || designator.isInstanceOf [Symbol ]
2685
- || ! adapted.denotationIsCurrent
2686
- || adapted.info.eq(denot.info)
2687
- then adapted
2688
- else this
2689
- val lastDenot = result.lastDenotation
2694
+ val lastDenot = adapted.lastDenotation
2690
2695
denot match
2691
2696
case denot : SymDenotation
2692
2697
if denot.validFor.firstPhaseId < ctx.phase.id
@@ -2696,15 +2701,15 @@ object Types {
2696
2701
// In this case the new SymDenotation might be valid for all phases, which means
2697
2702
// we would not recompute the denotation when travelling to an earlier phase, maybe
2698
2703
// in the next run. We fix that problem by creating a UniqueRefDenotation instead.
2699
- core.println(i " overwrite ${result .toString} / ${result .lastDenotation}, ${result .lastDenotation.getClass} with $denot at ${ctx.phaseId}" )
2700
- result .setDenot(
2704
+ core.println(i " overwrite ${adapted .toString} / ${adapted .lastDenotation}, ${adapted .lastDenotation.getClass} with $denot at ${ctx.phaseId}" )
2705
+ adapted .setDenot(
2701
2706
UniqueRefDenotation (
2702
2707
denot.symbol, denot.info,
2703
2708
Period (ctx.runId, ctx.phaseId, denot.validFor.lastPhaseId),
2704
2709
this .prefix))
2705
2710
case _ =>
2706
- result .setDenot(denot)
2707
- result .asInstanceOf [ThisType ]
2711
+ adapted .setDenot(denot)
2712
+ adapted .asInstanceOf [ThisType ]
2708
2713
else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala.
2709
2714
this
2710
2715
0 commit comments