Skip to content

Commit

Permalink
Fix pattern generation in "ordinal" mirror method (scala#17570)
Browse files Browse the repository at this point in the history
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 scala#17556
  • Loading branch information
bishabosha authored May 24, 2023
2 parents 32add3d + a0be3d6 commit aa74ac4
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 9 deletions.
33 changes: 29 additions & 4 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1509,16 +1509,29 @@ object SymDenotations {
* See tests/pos/i10769.scala
*/
def reachableTypeRef(using Context) =
TypeRef(owner.reachableThisType, symbol)
TypeRef(owner.reachablePrefix, symbol)

/** Like termRef, but objects in the prefix are represented by their singleton type,
/** The reachable typeRef with wildcard arguments for each type parameter */
def reachableRawTypeRef(using Context) =
reachableTypeRef.appliedTo(typeParams.map(_ => TypeBounds.emptyPolyKind))

/** Like termRef, if it is addressable from the current context,
* but objects in the prefix are represented by their singleton type,
* this means we output `pre.O.member` rather than `pre.O$.this.member`.
*
* This is required to avoid owner crash in ExplicitOuter.
* See tests/pos/i10769.scala
*
* If the reference is to an object that is not accessible from the
* current context since the object is nested in a class that is not an outer
* class of the current context, fall back to a TypeRef to the module class.
* Test case is tests/pos/i17556.scala.
* If the reference is to some other inaccessible object, throw an AssertionError.
*/
def reachableTermRef(using Context) =
TermRef(owner.reachableThisType, symbol)
def reachableTermRef(using Context): Type = owner.reachablePrefix match
case pre: SingletonType => TermRef(pre, symbol)
case pre if symbol.is(ModuleVal) => TypeRef(pre, symbol.moduleClass)
case _ => throw AssertionError(i"cannot compute path to TermRef $this from ${ctx.owner}")

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

/** Like `reachableThisType`, except if that would refer to a class where
* the `this` cannot be accessed. In that case, fall back to the
* rawTypeRef of the class. E.g. instead of `A.this.X` where `A.this`
* is inaccessible, use `A#X`.
*/
def reachablePrefix(using Context): Type = reachableThisType match
case pre: ThisType
if !pre.cls.isStaticOwner && !ctx.owner.isContainedIn(pre.cls) =>
pre.cls.reachableRawTypeRef
case pre =>
pre

/** The variance of this type parameter or type member as a subset of
* {Covariant, Contravariant}
*/
Expand Down
4 changes: 0 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/SymUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,6 @@ object SymUtils:
else owner.isLocal
}

/** The reachable typeRef with wildcard arguments for each type parameter */
def reachableRawTypeRef(using Context) =
self.reachableTypeRef.appliedTo(self.typeParams.map(_ => TypeBounds.emptyPolyKind))

/** Is symbol a type splice operation? */
def isTypeSplice(using Context): Boolean =
self == defn.QuotedType_splice
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
.map((pre, child) => rawRef(child).asSeenFrom(pre, child.owner))
case _ =>
cls.children.map(rawRef)
end computeChildTypes

val childTypes = computeChildTypes
val cases =
for (patType, idx) <- childTypes.zipWithIndex yield
Expand Down
8 changes: 8 additions & 0 deletions tests/pos/i17556.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
sealed trait A {
// must be `object` or `case class`
object X extends A
case class Y() extends A
}

// companion object must exist
object A

0 comments on commit aa74ac4

Please sign in to comment.