Skip to content

Commit 46e82dd

Browse files
committed
Refine infoDependsOnPrefix
Make infoDependsOnPrefix return true even if the prefix is the ThisType of the enclosing class, in case that class has a selftype which refines the binding of an abstract type. This allows to implement withDenot without overwriting a NamedType's state.
1 parent ea87c08 commit 46e82dd

File tree

3 files changed

+39
-33
lines changed

3 files changed

+39
-33
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

+37-32
Original file line numberDiff line numberDiff line change
@@ -2501,10 +2501,36 @@ object Types {
25012501

25022502
/** A reference with the initial symbol in `symd` has an info that
25032503
* 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.
25042510
*/
25052511
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+
25062526
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
25082534

25092535
/** Is this a reference to a class or object member with an info that might depend
25102536
* on the prefix?
@@ -2653,40 +2679,19 @@ object Types {
26532679
else this
26542680

26552681
/** 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.
26752687
*/
26762688
final def withDenot(denot: Denotation)(using Context): ThisType =
26772689
if denot.exists then
26782690
val adapted =
26792691
if denot.symbol.exists then withSym(denot.symbol)
26802692
else if denot.isOverloaded then withName(denot.name)
26812693
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
26902695
denot match
26912696
case denot: SymDenotation
26922697
if denot.validFor.firstPhaseId < ctx.phase.id
@@ -2696,15 +2701,15 @@ object Types {
26962701
// In this case the new SymDenotation might be valid for all phases, which means
26972702
// we would not recompute the denotation when travelling to an earlier phase, maybe
26982703
// 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(
27012706
UniqueRefDenotation(
27022707
denot.symbol, denot.info,
27032708
Period(ctx.runId, ctx.phaseId, denot.validFor.lastPhaseId),
27042709
this.prefix))
27052710
case _ =>
2706-
result.setDenot(denot)
2707-
result.asInstanceOf[ThisType]
2711+
adapted.setDenot(denot)
2712+
adapted.asInstanceOf[ThisType]
27082713
else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala.
27092714
this
27102715

compiler/src/dotty/tools/dotc/reporting/messages.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ extends NotFoundMsg(MissingIdentID) {
245245
}
246246
}
247247

248-
class TypeMismatch(found: Type, expected: Type, inTree: Option[untpd.Tree], addenda: => String*)(using Context)
248+
class TypeMismatch(found: Type, expected: Type, inTree: Option[untpd.Tree], addenda: => String*)(using Context)
249249
extends TypeMismatchMsg(found, expected)(TypeMismatchID):
250250

251251
def msg(using Context) =

compiler/test/dotc/pos-test-pickling.blacklist

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ i12299a.scala
1919
i13871.scala
2020
i15181.scala
2121
i15922.scala
22+
t5031_2.scala
2223

2324
# Tree is huge and blows stack for printing Text
2425
i7034.scala

0 commit comments

Comments
 (0)