Skip to content

Commit 63d1f86

Browse files
committed
Merge pull request #436 from dotty-staging/linked-class
use methods to find companion class
2 parents 008bf64 + e5618d2 commit 63d1f86

15 files changed

+158
-37
lines changed

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,10 @@ object desugar {
362362
companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters)
363363
}
364364
else if (defaultGetters.nonEmpty)
365-
companionDefs(anyRef, defaultGetters)
365+
companionDefs(anyRef, defaultGetters)
366366
else Nil
367367

368+
368369
// For an implicit class C[Ts](p11: T11, ..., p1N: T1N) ... (pM1: TM1, .., pMN: TMN), the method
369370
// synthetic implicit C[Ts](p11: T11, ..., p1N: T1N) ... (pM1: TM1, ..., pMN: TMN): C[Ts] =
370371
// new C[Ts](p11, ..., p1N) ... (pM1, ..., pMN) =
@@ -409,6 +410,8 @@ object desugar {
409410
flatTree(cdef1 :: companions ::: implicitWrappers)
410411
}
411412

413+
val AccessOrSynthetic = AccessFlags | Synthetic
414+
412415
/** Expand
413416
*
414417
* object name extends parents { self => body }
@@ -436,7 +439,7 @@ object desugar {
436439
.withPos(tmpl.self.pos orElse tmpl.pos.startPos)
437440
val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body)
438441
val cls = TypeDef(clsName, clsTmpl)
439-
.withMods(mods.toTypeFlags & AccessFlags | ModuleClassCreationFlags)
442+
.withMods(mods.toTypeFlags & AccessOrSynthetic | ModuleClassCreationFlags)
440443
Thicket(modul, classDef(cls))
441444
}
442445
}

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ object Denotations {
471471
* 2) the union of all validity periods is a contiguous
472472
* interval.
473473
*/
474-
private var nextInRun: SingleDenotation = this
474+
protected var nextInRun: SingleDenotation = this
475475

476476
/** The version of this SingleDenotation that was valid in the first phase
477477
* of this run.
@@ -611,7 +611,10 @@ object Denotations {
611611
val current = symbol.current
612612
// println(s"installing $this after $phase/${phase.id}, valid = ${current.validFor}")
613613
// printPeriods(current)
614-
this.nextInRun = current.nextInRun
614+
if (current.nextInRun ne current)
615+
this.nextInRun = current.nextInRun
616+
else
617+
this.nextInRun = this
615618
this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId)
616619
if (current.validFor.firstPhaseId == targetId) {
617620
// replace current with this denotation
@@ -622,6 +625,7 @@ object Denotations {
622625
} else {
623626
// insert this denotation after current
624627
current.validFor = Period(ctx.runId, current.validFor.firstPhaseId, targetId - 1)
628+
this.nextInRun = current.nextInRun
625629
current.nextInRun = this
626630
}
627631
// printPeriods(this)

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ object StdNames {
8383
final val HASHkw: N = kw("#")
8484
final val ATkw: N = kw("@")
8585

86-
val ANON_CLASS: N = "$anon"
87-
val ANON_FUN: N = "$anonfun"
86+
val ANON_CLASS: N = "$anon"
87+
val ANON_FUN: N = "$anonfun"
8888
val BITMAP_PREFIX: N = "bitmap$"
8989
val BITMAP_NORMAL: N = BITMAP_PREFIX // initialization bitmap for public/protected lazy vals
9090
val BITMAP_TRANSIENT: N = BITMAP_PREFIX + "trans$" // initialization bitmap for transient lazy vals
@@ -117,13 +117,15 @@ object StdNames {
117117
val PROTECTED_PREFIX: N = "protected$"
118118
val PROTECTED_SET_PREFIX: N = PROTECTED_PREFIX + "set"
119119
val ROOT: N = "<root>"
120-
val SHADOWED: N = "(shadowed)" // tag to be used until we have proper name kinds
120+
val SHADOWED: N = "(shadowed)" // tag to be used until we have proper name kinds
121121
val SINGLETON_SUFFIX: N = ".type"
122122
val SPECIALIZED_SUFFIX: N = "$sp"
123123
val SUPER_PREFIX: N = "super$"
124124
val WHILE_PREFIX: N = "while$"
125125
val DEFAULT_EXCEPTION_NAME: N = "ex$"
126126
val INITIALIZER_PREFIX: N = "initial$"
127+
val COMPANION_MODULE_METHOD: N = "companion$module"
128+
val COMPANION_CLASS_METHOD: N = "companion$class"
127129

128130
// value types (and AnyRef) are all used as terms as well
129131
// as (at least) arguments to the @specialize annotation.

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

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ object SymDenotations {
239239
final def ensureCompleted()(implicit ctx: Context): Unit = info
240240

241241
/** The symbols defined in this class or object.
242-
* Careful! This coes not force the type, so is compilation order dependent.
242+
* Careful! This does not force the type, so is compilation order dependent.
243243
* This method should be used only in the following circumstances:
244244
*
245245
* 1. When accessing type parameters or type parameter accessors (both are entered before
@@ -772,18 +772,36 @@ object SymDenotations {
772772
* and which is also defined in the same scope and compilation unit.
773773
* NoSymbol if this module does not exist.
774774
*/
775-
final def companionModule(implicit ctx: Context): Symbol =
776-
if (name == tpnme.ANON_CLASS)
777-
NoSymbol // avoid forcing anon classes, this might cause cyclic reference errors
778-
else
779-
companionNamed(effectiveName.moduleClassName).sourceModule
775+
final def companionModule(implicit ctx: Context): Symbol = {
776+
if (this.flagsUNSAFE is Flags.Module) this.sourceModule
777+
else {
778+
val companionMethod = info.decls.denotsNamed(nme.COMPANION_MODULE_METHOD, selectPrivate).first
779+
if (companionMethod.exists)
780+
companionMethod.info.resultType.classSymbol.sourceModule
781+
else
782+
NoSymbol
783+
}
784+
}
785+
780786

781787
/** The class with the same (type-) name as this module or module class,
782-
* and which is also defined in the same scope and compilation unit.
783-
* NoSymbol if this class does not exist.
784-
*/
785-
final def companionClass(implicit ctx: Context): Symbol =
786-
companionNamed(effectiveName.toTypeName)
788+
* and which is also defined in the same scope and compilation unit.
789+
* NoSymbol if this class does not exist.
790+
*/
791+
final def companionClass(implicit ctx: Context): Symbol = {
792+
val companionMethod = info.decls.denotsNamed(nme.COMPANION_CLASS_METHOD, selectPrivate).first
793+
794+
if (companionMethod.exists)
795+
companionMethod.info.resultType.classSymbol
796+
else
797+
NoSymbol
798+
}
799+
800+
final def scalacLinkedClass(implicit ctx: Context): Symbol =
801+
if (this is ModuleClass) companionNamed(effectiveName.toTypeName)
802+
else if (this.isClass) companionNamed(effectiveName.moduleClassName).sourceModule.moduleClass
803+
else NoSymbol
804+
787805

788806
/** Find companion class symbol with given name, or NoSymbol if none exists.
789807
* Three alternative strategies:
@@ -1265,15 +1283,21 @@ object SymDenotations {
12651283
myMemberCache
12661284
}
12671285

1268-
/** Enter a symbol in current scope.
1286+
/** Enter a symbol in current scope, and future scopes of same denotation.
12691287
* Note: We require that this does not happen after the first time
12701288
* someone does a findMember on a subclass.
12711289
* @param scope The scope in which symbol should be entered.
12721290
* If this is EmptyScope, the scope is `decls`.
12731291
*/
12741292
def enter(sym: Symbol, scope: Scope = EmptyScope)(implicit ctx: Context): Unit = {
12751293
val mscope = scope match {
1276-
case scope: MutableScope => scope
1294+
case scope: MutableScope =>
1295+
// if enter gets a scope as an argument,
1296+
// than this is a scope that will eventually become decls of this symbol.
1297+
// And this should only happen if this is first time the scope of symbol
1298+
// is computed, ie symbol yet has no future.
1299+
assert(this.nextInRun == this)
1300+
scope
12771301
case _ => unforcedDecls.openForMutations
12781302
}
12791303
if (this is PackageClass) {
@@ -1285,11 +1309,15 @@ object SymDenotations {
12851309
}
12861310
}
12871311
enterNoReplace(sym, mscope)
1312+
val nxt = this.nextInRun
1313+
if (nxt.validFor.code > this.validFor.code) {
1314+
this.nextInRun.asSymDenotation.asClass.enter(sym)
1315+
}
12881316
}
12891317

12901318
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
12911319
def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
1292-
require(!(this is Frozen))
1320+
require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen))
12931321
scope.enter(sym)
12941322

12951323
if (myMemberFingerPrint != FingerPrint.unknown)

src/dotty/tools/dotc/core/SymbolLoaders.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ abstract class SymbolLoader extends LazyType {
217217
denot.markAbsent()
218218
postProcess(root)
219219
if (!root.isRoot)
220-
postProcess(root.linkedClass.denot)
220+
postProcess(root.scalacLinkedClass.denot)
221221
}
222222
}
223223
}
@@ -229,7 +229,7 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {
229229
def description = "class file "+ classfile.toString
230230

231231
def rootDenots(rootDenot: ClassDenotation)(implicit ctx: Context): (ClassDenotation, ClassDenotation) = {
232-
val linkedDenot = rootDenot.linkedClass.denot match {
232+
val linkedDenot = rootDenot.scalacLinkedClass.denot match {
233233
case d: ClassDenotation => d
234234
case d =>
235235
// this can happen if the companion if shadowed by a val or type

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ trait Symbols { this: Context =>
161161
owner.thisType, modcls, parents, decls, TermRef.withSymAndName(owner.thisType, module, name)),
162162
privateWithin, coord, assocFile)
163163

164+
def synthesizeCompanionMethod(name: Name, target: SymDenotation, owner: SymDenotation)(implicit ctx: Context) =
165+
if(owner.exists && target.exists && !owner.isAbsent && !target.isAbsent) {
166+
val existing = owner.unforcedDecls.lookup(name)
167+
168+
existing.orElse{
169+
ctx.newSymbol(owner.symbol, name, Flags.Synthetic | Flags.Private, ExprType(target.typeRef))
170+
}
171+
} else NoSymbol
172+
164173
/** Create a package symbol with associated package class
165174
* from its non-info fields and a lazy type for loading the package's members.
166175
*/

src/dotty/tools/dotc/core/pickling/ClassfileParser.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ class ClassfileParser(
9292
if (c != classRoot.symbol) mismatchError(c)
9393
}
9494

95+
if(classRoot.symbol.id == 4812) {
96+
println("bar")
97+
}
98+
9599
addEnclosingTParams()
96100

97101
if (unpickleOrParseInnerClasses()) return
@@ -130,10 +134,17 @@ class ClassfileParser(
130134
for (i <- 0 until in.nextChar) parseMember(method = true)
131135
classInfo = parseAttributes(classRoot.symbol, classInfo)
132136
if (isAnnotation) addAnnotationConstructor(classInfo)
137+
138+
val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, classRoot, moduleRoot)
139+
if (companionClassMethod.exists) companionClassMethod.entered
140+
val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, moduleRoot, classRoot)
141+
if (companionModuleMethod.exists) companionModuleMethod.entered
142+
133143
setClassInfo(classRoot, classInfo)
134144
setClassInfo(moduleRoot, staticInfo)
135145
}
136146

147+
137148
/** Add type parameters of enclosing classes */
138149
def addEnclosingTParams()(implicit ctx: Context): Unit = {
139150
var sym = classRoot.owner

src/dotty/tools/dotc/core/pickling/UnPickler.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,24 @@ object UnPickler {
118118
denot.owner.thisType select denot.sourceModule
119119
else selfInfo
120120
if (!(denot.flagsUNSAFE is JavaModule)) ensureConstructor(denot.symbol.asClass, decls)
121+
122+
val scalacCompanion = denot.classSymbol.scalacLinkedClass
123+
124+
def registerCompanionPair(module: Symbol, claz: Symbol) = {
125+
val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, claz, module)
126+
if (companionClassMethod.exists)
127+
companionClassMethod.entered
128+
val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, module, claz)
129+
if (companionModuleMethod.exists)
130+
companionModuleMethod.entered
131+
}
132+
133+
if (denot.flagsUNSAFE is Module) {
134+
registerCompanionPair(denot.classSymbol, scalacCompanion)
135+
} else {
136+
registerCompanionPair(scalacCompanion, denot.classSymbol)
137+
}
138+
121139
denot.info = ClassInfo(denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost)
122140
}
123141
}
@@ -483,7 +501,11 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
483501
if (isModuleRoot) {
484502
moduleRoot setFlag flags
485503
moduleRoot.symbol
486-
} else ctx.newSymbol(owner, name.asTermName, flags, localMemberUnpickler, coord = start)
504+
} else ctx.newSymbol(owner, name.asTermName, flags,
505+
new LocalUnpickler() withModuleClass(implicit ctx =>
506+
owner.info.decls.lookup(name.moduleClassName)
507+
.suchThat(_ is Module).symbol)
508+
, coord = start)
487509
case _ =>
488510
errorBadSignature("bad symbol tag: " + tag)
489511
})

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import DenotTransformers._
1919
import typer.Checking
2020
import Names.Name
2121
import NameOps._
22+
import StdNames._
2223

2324

2425
/** The first tree transform
@@ -72,10 +73,13 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
7273
case Nil => Nil
7374
}
7475

75-
def newCompanion(name: TermName): Thicket = {
76+
def newCompanion(name: TermName, forClass: Symbol): Thicket = {
7677
val modul = ctx.newCompleteModuleSymbol(ctx.owner, name, Synthetic, Synthetic,
7778
defn.ObjectClass.typeRef :: Nil, Scopes.newScope)
79+
val mc = modul.moduleClass
7880
if (ctx.owner.isClass) modul.enteredAfter(thisTransformer)
81+
ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, forClass, mc).enteredAfter(thisTransformer)
82+
ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, mc, forClass).enteredAfter(thisTransformer)
7983
ModuleDef(modul, Nil)
8084
}
8185

@@ -89,7 +93,7 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
8993
false
9094
}
9195
val uniqueName = if (nameClash) objName.avoidClashName else objName
92-
Thicket(stat :: newCompanion(uniqueName).trees)
96+
Thicket(stat :: newCompanion(uniqueName, stat.symbol).trees)
9397
case stat => stat
9498
}
9599

src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,12 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
643643
// val outer = expectedTp.typeSymbol.newMethod(vpmName.outer, newFlags = SYNTHETIC | ARTIFACT) setInfo expectedTp.prefix
644644

645645
val expectedClass = expectedTp.dealias.classSymbol.asClass
646-
ExplicitOuter.ensureOuterAccessors(expectedClass)
647-
codegen._asInstanceOf(testedBinder, expectedTp).select(ExplicitOuter.outerAccessor(expectedClass)).select(defn.Object_eq).appliedTo(expectedOuter)
646+
val test = codegen._asInstanceOf(testedBinder, expectedTp)
647+
val outerAccessorTested = ctx.atPhase(ctx.explicitOuterPhase.next) { implicit ctx =>
648+
ExplicitOuter.ensureOuterAccessors(expectedClass)
649+
test.select(ExplicitOuter.outerAccessor(expectedClass)).select(defn.Object_eq).appliedTo(expectedOuter)
650+
}
651+
outerAccessorTested
648652
}
649653
}
650654

src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ trait Checking {
232232

233233
/** Check that type `tp` is stable. */
234234
def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit =
235-
if (!tp.isStable) ctx.error(d"$tp is not stable", pos)
235+
if (!tp.isStable)
236+
ctx.error(d"$tp is not stable", pos)
236237

237238
/** Check that type `tp` is a legal prefix for '#'.
238239
* @return The type itself

0 commit comments

Comments
 (0)