Skip to content

Commit 68e90c4

Browse files
committed
Treat companions of opaque types specially
Make them part of the OpaqueAlias annotation. This is has two benefits - opaque types stop being companions after FirstTransform. Previously, the LinkedType annotations would persist even though the Opaque flag was reset. - we gain the freedom to implement companions between classes differently.
1 parent 6a91a20 commit 68e90c4

File tree

6 files changed

+35
-19
lines changed

6 files changed

+35
-19
lines changed

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,23 @@ object Annotations {
186186
}
187187

188188
/** Extractor for opaque alias annotations */
189-
object OpaqueAlias extends TypeHintExtractor(implicit ctx => defn.OpaqueAliasAnnot)
189+
object OpaqueAlias {
190+
def apply(tp: Type, companion: Symbol)(implicit ctx: Context): Annotation = {
191+
val arg = if (companion.exists) RefinedType(tp, nme.companion, companion.termRef) else tp
192+
Annotation(TypeTree(defn.OpaqueAliasAnnot.typeRef.appliedTo(arg)))
193+
}
194+
def unapply(ann: Annotation)(implicit ctx: Context): Option[(Type, Symbol)] =
195+
if (ann.symbol == defn.OpaqueAliasAnnot) {
196+
ann.tree.tpe match {
197+
case AppliedType(_, RefinedType(tp, nme.companion, ref) :: Nil) => Some((tp, ref.termSymbol))
198+
case AppliedType(_, tp :: Nil) => Some((tp, NoSymbol))
199+
case _ => None
200+
}
201+
}
202+
else None
203+
}
190204

191-
/** Extractpr for linked type annotations */
205+
/** Extractor for linked type annotations */
192206
object LinkedType extends TypeHintExtractor(implicit ctx => defn.LinkedTypeAnnot)
193207

194208
def makeSourceFile(path: String)(implicit ctx: Context) =

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ object StdNames {
394394
val classOf: N = "classOf"
395395
val clone_ : N = "clone"
396396
// val conforms : N = "conforms" // Dotty deviation: no special treatment of conforms, so the occurrence of the name here would cause to unintended implicit shadowing. Should find a less common name for it in Predef.
397+
val companion: N = "companion"
397398
val copy: N = "copy"
398399
val currentMirror: N = "currentMirror"
399400
val create: N = "create"

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,8 @@ object SymDenotations {
391391
if (is(Opaque)) {
392392
info match {
393393
case tp @ TypeAlias(alias) =>
394-
addAnnotation(Annotation.OpaqueAlias(alias))
394+
val companion = companionNamed(name.moduleClassName).sourceModule
395+
addAnnotation(Annotation.OpaqueAlias(alias, companion))
395396
info = TypeBounds(defn.NothingType, abstractRHS(alias))
396397
setFlag(Deferred)
397398
case _ =>
@@ -968,10 +969,17 @@ object SymDenotations {
968969
*/
969970
final def companionModule(implicit ctx: Context): Symbol =
970971
if (is(Module)) sourceModule
971-
else getAnnotation(defn.LinkedTypeAnnot) match {
972-
case Some(Annotation.LinkedType(linked: TypeRef)) => linked.symbol.sourceModule
973-
case _ => NoSymbol
974-
}
972+
else if (is(Opaque))
973+
getAnnotation(defn.OpaqueAliasAnnot) match {
974+
case Some(Annotation.OpaqueAlias(_, ref)) => ref
975+
case _ => NoSymbol
976+
}
977+
else
978+
getAnnotation(defn.LinkedTypeAnnot) match {
979+
case Some(Annotation.LinkedType(linked: TypeRef)) =>
980+
linked.symbol.sourceModule
981+
case _ => NoSymbol
982+
}
975983

976984
private def companionType(implicit ctx: Context): Symbol =
977985
if (is(Package)) NoSymbol

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -740,16 +740,9 @@ class TreeUnpickler(reader: TastyReader,
740740
// The only case to check here is if `sym` is a root. In this case
741741
// `companion` might have been entered by the environment but it might
742742
// be missing from the Tasty file. So we check explicitly for that.
743-
def isCodefined =
744-
roots.contains(companion.denot) == seenRoots.contains(companion)
745-
if (companion.exists && isCodefined) {
746-
if (companion.isClass)
747-
sym.registerCompanion(companion)
748-
else if (sym.is(Module) && companion.is(Opaque)) {
749-
sym.registerCompanion(companion)
750-
companion.registerCompanion(sym)
751-
}
752-
}
743+
def isCodefined = roots.contains(companion.denot) == seenRoots.contains(companion)
744+
745+
if (companion.canHaveCompanion && isCodefined) sym.registerCompanion(companion)
753746
TypeDef(readTemplate(localCtx))
754747
} else {
755748
sym.info = TypeBounds.empty // needed to avoid cyclic references when unpicklin rhs, see i3816.scala

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class FirstTransform extends MiniPhase with SymTransformer { thisPhase =>
6666
case _ =>
6767
if (sym.is(Opaque))
6868
sym.getAnnotation(defn.OpaqueAliasAnnot) match {
69-
case Some(Annotation.OpaqueAlias(rhs)) =>
69+
case Some(Annotation.OpaqueAlias(rhs, _)) =>
7070
val result = sym.copySymDenotation(info = TypeAlias(rhs))
7171
result.removeAnnotation(defn.OpaqueAliasAnnot)
7272
result.resetFlag(Opaque)

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ trait NamerContextOps { this: Context =>
111111
if (ctx.owner.is(Module)) {
112112
val opaq = ctx.owner.companionOpaqueType
113113
opaq.getAnnotation(defn.OpaqueAliasAnnot) match {
114-
case Some(Annotation.OpaqueAlias(rhs)) =>
114+
case Some(Annotation.OpaqueAlias(rhs, _)) =>
115115
localCtx = localCtx.setFreshGADTBounds
116116
localCtx.gadt.setBounds(opaq, TypeAlias(rhs))
117117
case _ =>

0 commit comments

Comments
 (0)