Skip to content

Commit f9cf3d0

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 9a992f0 commit f9cf3d0

File tree

12 files changed

+50
-95
lines changed

12 files changed

+50
-95
lines changed

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: 36 additions & 34 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
@@ -597,12 +593,9 @@ object SymDenotations {
597593
/** Is this a "real" method? A real method is a method which is:
598594
* - not an accessor
599595
* - not an anonymous function
600-
* - not a companion method
601596
*/
602597
final def isRealMethod(implicit ctx: Context): Boolean =
603-
this.is(Method, butNot = Accessor) &&
604-
!isAnonymousFunction &&
605-
!isCompanionMethod
598+
this.is(Method, butNot = Accessor) && !isAnonymousFunction
606599

607600
/** Is this a getter? */
608601
final def isGetter(implicit ctx: Context): Boolean =
@@ -948,34 +941,32 @@ object SymDenotations {
948941
final def enclosingPackageClass(implicit ctx: Context): Symbol =
949942
if (this is PackageClass) symbol else owner.enclosingPackageClass
950943

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

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

980971
final def scalacLinkedClass(implicit ctx: Context): Symbol =
981972
if (this is ModuleClass) companionNamed(effectiveName.toTypeName)
@@ -1238,6 +1229,7 @@ object SymDenotations {
12381229
val annotations1 = if (annotations != null) annotations else this.annotations
12391230
val d = ctx.SymDenotation(symbol, owner, name, initFlags1, info1, privateWithin1)
12401231
d.annotations = annotations1
1232+
d.registeredCompanion = registeredCompanion
12411233
d
12421234
}
12431235

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

18361838
/** 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
@@ -796,12 +796,9 @@ class TreeUnpickler(reader: TastyReader,
796796
// The only case to check here is if `sym` is a root. In this case
797797
// `companion` might have been entered by the environment but it might
798798
// be missing from the Tasty file. So we check explicitly for that.
799-
def isCodefined =
800-
roots.contains(companion.denot) == seenRoots.contains(companion)
801-
if (companion.exists && isCodefined) {
802-
if (sym is Flags.ModuleClass) sym.registerCompanionMethod(nme.COMPANION_CLASS_METHOD, companion)
803-
else sym.registerCompanionMethod(nme.COMPANION_MODULE_METHOD, companion)
804-
}
799+
def isCodefined = roots.contains(companion.denot) == seenRoots.contains(companion)
800+
801+
if (companion.exists && isCodefined) sym.registerCompanion(companion)
805802
TypeDef(readTemplate(localCtx))
806803
} else {
807804
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
@@ -370,7 +370,6 @@ class TreeChecker extends Phase with SymTransformer {
370370

371371
def isNonMagicalMethod(x: Symbol) =
372372
x.is(Method) &&
373-
!x.isCompanionMethod &&
374373
!x.isValueClassConvertMethod &&
375374
!(x.is(Macro) && ctx.phase.refChecked) &&
376375
!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)