Skip to content

Commit a459716

Browse files
committed
Establish companionship directly
Don't use synthetic companion methods to achieve this. The advantages of the direct approach are: - it's overall simpler - it can be more easily extended to opaque types
1 parent 378ddce commit a459716

File tree

13 files changed

+54
-99
lines changed

13 files changed

+54
-99
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,9 @@ object Phases {
360360
assert(start <= Periods.MaxPossiblePhaseId, s"Too many phases, Period bits overflow")
361361
myBase = base
362362
myPeriod = Period(NoRunId, start, end)
363-
myErasedTypes = prev.getClass == classOf[Erasure] || prev.erasedTypes
364-
myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
365-
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
363+
myErasedTypes = prev.getClass == classOf[Erasure] || prev.erasedTypes
364+
myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
365+
myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
366366
myLabelsReordered = prev.getClass == classOf[LabelDefs] || prev.labelsReordered
367367
mySameMembersStartId = if (changesMembers) id else prev.sameMembersStartId
368368
mySameParentsStartId = if (changesParents) id else prev.sameParentsStartId

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ object StdNames {
140140
val WHILE_PREFIX: N = "while$"
141141
val DEFAULT_EXCEPTION_NAME: N = "ex$"
142142
val INITIALIZER_PREFIX: N = "initial$"
143-
val COMPANION_MODULE_METHOD: N = "companion$module"
144-
val COMPANION_CLASS_METHOD: N = "companion$class"
145143
val BOUNDTYPE_ANNOT: N = "$boundType$"
146144
val QUOTE: N = "'"
147145
val TYPE_QUOTE: N = "type_'"
@@ -245,6 +243,7 @@ object StdNames {
245243

246244
// Compiler-internal
247245
val ANYname: N = "<anyname>"
246+
val COMPANION: N = "<companion>"
248247
val CONSTRUCTOR: N = "<init>"
249248
val STATIC_CONSTRUCTOR: N = "<clinit>"
250249
val DEFAULT_CASE: N = "defaultCase$"

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

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -471,15 +471,6 @@ object SymDenotations {
471471
final def isAnonymousModuleVal(implicit ctx: Context): Boolean =
472472
this.symbol.is(ModuleVal) && (initial.name startsWith str.ANON_CLASS)
473473

474-
/** Is this a companion class method or companion object method?
475-
* These methods are generated by Symbols#synthesizeCompanionMethod
476-
* and used in SymDenotations#companionClass and
477-
* SymDenotations#companionModule .
478-
*/
479-
final def isCompanionMethod(implicit ctx: Context): Boolean =
480-
name.toTermName == nme.COMPANION_CLASS_METHOD ||
481-
name.toTermName == nme.COMPANION_MODULE_METHOD
482-
483474
/** Is this a synthetic method that represents conversions between representations of a value class
484475
* These methods are generated in ExtensionMethods
485476
* and used in ElimErasedValueType.
@@ -526,6 +517,11 @@ object SymDenotations {
526517
/** Is this symbol an abstract type or type parameter? */
527518
final def isAbstractOrParamType(implicit ctx: Context): Boolean = this is DeferredOrTypeParam
528519

520+
/** Can this symbol have a companion module?
521+
* This is the case if it is a class or an opaque type alias.
522+
*/
523+
final def canHaveCompanion(implicit ctx: Context) = isClass
524+
529525
/** Is this the denotation of a self symbol of some class?
530526
* This is the case if one of two conditions holds:
531527
* 1. It is the symbol referred to in the selfInfo part of the ClassInfo
@@ -598,12 +594,9 @@ object SymDenotations {
598594
* - not an accessor
599595
* - not a label
600596
* - not an anonymous function
601-
* - not a companion method
602597
*/
603-
final def isRealMethod(implicit ctx: Context): Boolean =
604-
this.is(Method, butNot = AccessorOrLabel) &&
605-
!isAnonymousFunction &&
606-
!isCompanionMethod
598+
final def isRealMethod(implicit ctx: Context) : Boolean =
599+
this.is(Method, butNot = AccessorOrLabel) && !isAnonymousFunction
607600

608601
/** Is this a getter? */
609602
final def isGetter(implicit ctx: Context): Boolean =
@@ -950,34 +943,32 @@ object SymDenotations {
950943
final def enclosingPackageClass(implicit ctx: Context): Symbol =
951944
if (this is PackageClass) symbol else owner.enclosingPackageClass
952945

946+
/** Register target as a companion; overridden in ClassDenotation */
947+
def registerCompanion(target: Symbol)(implicit ctx: Context) = ()
948+
949+
/** The registered companion; overridden in ClassDenotation */
950+
def registeredCompanion(implicit ctx: Context): Symbol = NoSymbol
951+
def registeredCompanion_=(c: Symbol): Unit = ()
952+
953953
/** The module object with the same (term-) name as this class or module class,
954954
* and which is also defined in the same scope and compilation unit.
955955
* NoSymbol if this module does not exist.
956956
*/
957-
final def companionModule(implicit ctx: Context): Symbol = {
958-
if (this.flagsUNSAFE is Flags.Module) this.sourceModule
959-
else {
960-
val companionMethod = info.decls.denotsNamed(nme.COMPANION_MODULE_METHOD, selectPrivate).first
961-
if (companionMethod.exists)
962-
companionMethod.info.resultType.classSymbol.sourceModule
963-
else
964-
NoSymbol
965-
}
966-
}
957+
final def companionModule(implicit ctx: Context): Symbol =
958+
if (is(Module)) sourceModule
959+
else registeredCompanion.sourceModule
960+
961+
private def companionType(implicit ctx: Context): Symbol =
962+
if (is(Package)) NoSymbol
963+
else if (is(ModuleVal)) moduleClass.denot.companionType
964+
else registeredCompanion
967965

968966
/** The class with the same (type-) name as this module or module class,
969-
* and which is also defined in the same scope and compilation unit.
970-
* NoSymbol if this class does not exist.
971-
*/
967+
* and which is also defined in the same scope and compilation unit.
968+
* NoSymbol if this class does not exist.
969+
*/
972970
final def companionClass(implicit ctx: Context): Symbol =
973-
if (is(Package)) NoSymbol
974-
else {
975-
val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first
976-
if (companionMethod.exists)
977-
companionMethod.info.resultType.classSymbol
978-
else
979-
NoSymbol
980-
}
971+
companionType.suchThat(_.isClass).symbol
981972

982973
final def scalacLinkedClass(implicit ctx: Context): Symbol =
983974
if (this is ModuleClass) companionNamed(effectiveName.toTypeName)
@@ -1240,6 +1231,7 @@ object SymDenotations {
12401231
val annotations1 = if (annotations != null) annotations else this.annotations
12411232
val d = ctx.SymDenotation(symbol, owner, name, initFlags1, info1, privateWithin1)
12421233
d.annotations = annotations1
1234+
d.registeredCompanion = registeredCompanion
12431235
d
12441236
}
12451237

@@ -1832,6 +1824,16 @@ object SymDenotations {
18321824
.copyCaches(this, phase.next)
18331825
.installAfter(phase)
18341826
}
1827+
1828+
private[this] var myCompanion: Symbol = NoSymbol
1829+
1830+
/** Register companion class */
1831+
override def registerCompanion(companion: Symbol)(implicit ctx: Context) =
1832+
if (companion.canHaveCompanion && !unforcedIsAbsent && !companion.unforcedIsAbsent)
1833+
myCompanion = companion
1834+
1835+
override def registeredCompanion(implicit ctx: Context) = { ensureCompleted(); myCompanion }
1836+
override def registeredCompanion_=(c: Symbol) = { myCompanion = c }
18351837
}
18361838

18371839
/** The denotation of a package class.

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,6 @@ trait Symbols { this: Context =>
186186

187187
val companionMethodFlags: FlagSet = Flags.Synthetic | Flags.Private | Flags.Method
188188

189-
def synthesizeCompanionMethod(name: Name, target: SymDenotation, owner: SymDenotation)(implicit ctx: Context): Symbol =
190-
if (owner.exists && target.exists && !owner.unforcedIsAbsent && !target.unforcedIsAbsent) {
191-
val existing = owner.unforcedDecls.lookup(name)
192-
193-
existing.orElse{
194-
ctx.newSymbol(owner.symbol, name, companionMethodFlags , ExprType(target.typeRef))
195-
}
196-
} else NoSymbol
197-
198189
/** Create a package symbol with associated package class
199190
* from its non-info fields and a lazy type for loading the package's members.
200191
*/

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,17 +161,14 @@ object TypeErasure {
161161
* - For $asInstanceOf : [T]T
162162
* - For $isInstanceOf : [T]Boolean
163163
* - For all abstract types : = ?
164-
* - For companion methods : the erasure of their type with semiEraseVCs = false.
165-
* The signature of these methods are used to keep a
166-
* link between companions and should not be semi-erased.
167164
* - For Java-defined symbols: : the erasure of their type with isJava = true,
168165
* semiEraseVCs = false. Semi-erasure never happens in Java.
169166
* - For all other symbols : the semi-erasure of their types, with
170167
* isJava, isConstructor set according to symbol.
171168
*/
172169
def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = {
173170
val isJava = sym is JavaDefined
174-
val semiEraseVCs = !isJava && !sym.isCompanionMethod
171+
val semiEraseVCs = !isJava
175172
val erase = erasureFn(isJava, semiEraseVCs, sym.isConstructor, wildcardOK = false)
176173

177174
def eraseParamBounds(tp: PolyType): Type =

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,8 @@ class ClassfileParser(
168168
classInfo = parseAttributes(classRoot.symbol, classInfo)
169169
if (isAnnotation) addAnnotationConstructor(classInfo)
170170

171-
val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, classRoot, moduleRoot)
172-
if (companionClassMethod.exists) companionClassMethod.entered
173-
val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, moduleRoot, classRoot)
174-
if (companionModuleMethod.exists) companionModuleMethod.entered
171+
classRoot.registerCompanion(moduleRoot.symbol)
172+
moduleRoot.registerCompanion(classRoot.symbol)
175173

176174
setClassInfo(classRoot, classInfo)
177175
setClassInfo(moduleRoot, staticInfo)

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -789,12 +789,9 @@ class TreeUnpickler(reader: TastyReader,
789789
// The only case to check here is if `sym` is a root. In this case
790790
// `companion` might have been entered by the environment but it might
791791
// be missing from the Tasty file. So we check explicitly for that.
792-
def isCodefined =
793-
roots.contains(companion.denot) == seenRoots.contains(companion)
794-
if (companion.exists && isCodefined) {
795-
if (sym is Flags.ModuleClass) sym.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, companion)
796-
else sym.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, companion)
797-
}
792+
def isCodefined = roots.contains(companion.denot) == seenRoots.contains(companion)
793+
794+
if (companion.exists && isCodefined) sym.registerCompanion(companion)
798795
TypeDef(readTemplate(localCtx))
799796
} else {
800797
sym.info = TypeBounds.empty // needed to avoid cyclic references when unpicklin rhs, see i3816.scala

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,18 +119,14 @@ object Scala2Unpickler {
119119
val scalacCompanion = denot.classSymbol.scalacLinkedClass
120120

121121
def registerCompanionPair(module: Symbol, claz: Symbol) = {
122-
import transform.SymUtils._
123-
module.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, claz)
124-
if (claz.isClass) {
125-
claz.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, module)
126-
}
122+
module.registerCompanion(claz)
123+
claz.registerCompanion(module)
127124
}
128125

129-
if (denot.flagsUNSAFE is Module) {
126+
if (denot.flagsUNSAFE is Module)
130127
registerCompanionPair(denot.classSymbol, scalacCompanion)
131-
} else {
128+
else
132129
registerCompanionPair(scalacCompanion, denot.classSymbol)
133-
}
134130

135131
tempInfo.finalize(denot, normalizedParents) // install final info, except possibly for typeparams ordering
136132
denot.ensureTypeParamsInCorrectOrder()

compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder
262262

263263
// Synthetic methods that are always present do not affect the API
264264
// and can therefore be ignored.
265-
def alwaysPresent(s: Symbol) =
266-
s.isCompanionMethod || (csym.is(ModuleClass) && s.isConstructor)
265+
def alwaysPresent(s: Symbol) = csym.is(ModuleClass) && s.isConstructor
267266
val decls = cinfo.decls.filter(!alwaysPresent(_))
268267
val apiDecls = apiDefinitions(decls)
269268

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,6 @@ class RestoreScopes extends MiniPhase with IdentityDenotTransformer { thisPhase
4141
val cls = tree.symbol.asClass
4242
val pkg = cls.owner.asClass
4343

44-
// Bring back companion links
45-
val companionClass = cls.info.decls.lookup(nme.COMPANION_CLASS_METHOD)
46-
val companionModule = cls.info.decls.lookup(nme.COMPANION_MODULE_METHOD)
47-
48-
if (companionClass.exists) {
49-
restoredDecls.enter(companionClass)
50-
}
51-
52-
if (companionModule.exists) {
53-
restoredDecls.enter(companionModule)
54-
}
55-
5644
pkg.enter(cls)
5745
val cinfo = cls.classInfo
5846
tree.symbol.copySymDenotation(

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,6 @@ class SymUtils(val self: Symbol) extends AnyVal {
121121
self
122122
}
123123

124-
def registerCompanionMethod(name: Name, target: Symbol)(implicit ctx: Context): Any = {
125-
if (!self.unforcedDecls.lookup(name).exists) {
126-
val companionMethod = ctx.synthesizeCompanionMethod(name, target, self)
127-
if (companionMethod.exists) {
128-
companionMethod.entered
129-
}
130-
}
131-
}
132-
133124
/** If this symbol is an enum value or a named class, register it as a child
134125
* in all direct parent classes which are sealed.
135126
* @param @late If true, register only inaccessible children (all others are already

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ class TreeChecker extends Phase with SymTransformer {
374374

375375
def isNonMagicalMethod(x: Symbol) =
376376
x.is(Method) &&
377-
!x.isCompanionMethod &&
378377
!x.isValueClassConvertMethod &&
379378
!(x.is(Macro) && ctx.phase.refChecked) &&
380379
!x.name.is(DocArtifactName)

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -609,10 +609,8 @@ class Namer { typer: Typer =>
609609
def createLinks(classTree: TypeDef, moduleTree: TypeDef)(implicit ctx: Context) = {
610610
val claz = ctx.effectiveScope.lookup(classTree.name)
611611
val modl = ctx.effectiveScope.lookup(moduleTree.name)
612-
if (claz.isClass && modl.isClass) {
613-
ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, modl).entered
614-
ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, modl, claz).entered
615-
}
612+
modl.registerCompanion(claz)
613+
claz.registerCompanion(modl)
616614
}
617615

618616
def createCompanionLinks(implicit ctx: Context): Unit = {

0 commit comments

Comments
 (0)