diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index aa97435d64bb..304840396641 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -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`. @@ -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} */ diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index c02a7d90cb8c..3fe05a45699e 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 48bcbaab3511..1560ae6e5618 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -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 diff --git a/tests/pos/i17556.scala b/tests/pos/i17556.scala new file mode 100644 index 000000000000..9f14cbfbb7c1 --- /dev/null +++ b/tests/pos/i17556.scala @@ -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 \ No newline at end of file