Skip to content

Commit a0be3d6

Browse files
committed
Fix pattern generation in "ordinal" mirror method
The "ordinal" method generated non-sensical patterns if the cases of a sealed trait were found in the trait itself. In that case the ordinal method would be placed in the companion object, but still tried to access the cases via the `this` of the companion class. We are now more careful and fall back to type projections in comparisons. Fixes #17556
1 parent fe08f5f commit a0be3d6

File tree

4 files changed

+38
-9
lines changed

4 files changed

+38
-9
lines changed

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,16 +1509,29 @@ object SymDenotations {
15091509
* See tests/pos/i10769.scala
15101510
*/
15111511
def reachableTypeRef(using Context) =
1512-
TypeRef(owner.reachableThisType, symbol)
1512+
TypeRef(owner.reachablePrefix, symbol)
15131513

1514-
/** Like termRef, but objects in the prefix are represented by their singleton type,
1514+
/** The reachable typeRef with wildcard arguments for each type parameter */
1515+
def reachableRawTypeRef(using Context) =
1516+
reachableTypeRef.appliedTo(typeParams.map(_ => TypeBounds.emptyPolyKind))
1517+
1518+
/** Like termRef, if it is addressable from the current context,
1519+
* but objects in the prefix are represented by their singleton type,
15151520
* this means we output `pre.O.member` rather than `pre.O$.this.member`.
15161521
*
15171522
* This is required to avoid owner crash in ExplicitOuter.
15181523
* See tests/pos/i10769.scala
1524+
*
1525+
* If the reference is to an object that is not accessible from the
1526+
* current context since the object is nested in a class that is not an outer
1527+
* class of the current context, fall back to a TypeRef to the module class.
1528+
* Test case is tests/pos/i17556.scala.
1529+
* If the reference is to some other inaccessible object, throw an AssertionError.
15191530
*/
1520-
def reachableTermRef(using Context) =
1521-
TermRef(owner.reachableThisType, symbol)
1531+
def reachableTermRef(using Context): Type = owner.reachablePrefix match
1532+
case pre: SingletonType => TermRef(pre, symbol)
1533+
case pre if symbol.is(ModuleVal) => TypeRef(pre, symbol.moduleClass)
1534+
case _ => throw AssertionError(i"cannot compute path to TermRef $this from ${ctx.owner}")
15221535

15231536
/** Like thisType, but objects in the type are represented by their singleton type,
15241537
* this means we output `pre.O.member` rather than `pre.O$.this.member`.
@@ -1533,6 +1546,18 @@ object SymDenotations {
15331546
else
15341547
ThisType.raw(TypeRef(owner.reachableThisType, symbol.asType))
15351548

1549+
/** Like `reachableThisType`, except if that would refer to a class where
1550+
* the `this` cannot be accessed. In that case, fall back to the
1551+
* rawTypeRef of the class. E.g. instead of `A.this.X` where `A.this`
1552+
* is inaccessible, use `A#X`.
1553+
*/
1554+
def reachablePrefix(using Context): Type = reachableThisType match
1555+
case pre: ThisType
1556+
if !pre.cls.isStaticOwner && !ctx.owner.isContainedIn(pre.cls) =>
1557+
pre.cls.reachableRawTypeRef
1558+
case pre =>
1559+
pre
1560+
15361561
/** The variance of this type parameter or type member as a subset of
15371562
* {Covariant, Contravariant}
15381563
*/

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,6 @@ object SymUtils:
311311
else owner.isLocal
312312
}
313313

314-
/** The reachable typeRef with wildcard arguments for each type parameter */
315-
def reachableRawTypeRef(using Context) =
316-
self.reachableTypeRef.appliedTo(self.typeParams.map(_ => TypeBounds.emptyPolyKind))
317-
318314
/** Is symbol a type splice operation? */
319315
def isTypeSplice(using Context): Boolean =
320316
self == defn.QuotedType_splice

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
552552
.map((pre, child) => rawRef(child).asSeenFrom(pre, child.owner))
553553
case _ =>
554554
cls.children.map(rawRef)
555-
end computeChildTypes
555+
556556
val childTypes = computeChildTypes
557557
val cases =
558558
for (patType, idx) <- childTypes.zipWithIndex yield

tests/pos/i17556.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
sealed trait A {
2+
// must be `object` or `case class`
3+
object X extends A
4+
case class Y() extends A
5+
}
6+
7+
// companion object must exist
8+
object A

0 commit comments

Comments
 (0)