Skip to content

Commit dabec1a

Browse files
authored
Merge pull request scala#5700 from retronym/ticket/10154-refactor
Refactor lookupCompanion
2 parents 2f1e0c2 + 06eee79 commit dabec1a

File tree

3 files changed

+43
-39
lines changed

3 files changed

+43
-39
lines changed

src/compiler/scala/tools/nsc/typechecker/Contexts.scala

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,27 +1196,33 @@ trait Contexts { self: Analyzer =>
11961196
res
11971197
}
11981198

1199-
final def lookupCompanionOf(original: Symbol): Symbol = {
1200-
if (original.isModuleClass) original.sourceModule
1201-
else lookupScopeEntry(original) match {
1202-
case null => NoSymbol
1203-
case entry => entry.owner.lookupCompanion(original)
1199+
final def lookupCompanionInIncompleteOwner(original: Symbol): Symbol = {
1200+
/* Search scopes in current and enclosing contexts for the definition of `symbol` */
1201+
def lookupScopeEntry(symbol: Symbol): ScopeEntry = {
1202+
var res: ScopeEntry = null
1203+
var ctx = this
1204+
while (res == null && ctx.outer != ctx) {
1205+
val s = ctx.scope lookupSymbolEntry symbol
1206+
if (s != null)
1207+
res = s
1208+
else
1209+
ctx = ctx.outer
1210+
}
1211+
res
12041212
}
1205-
}
12061213

1207-
/** Search scopes in current and enclosing contexts for the definition of `symbol` */
1208-
private def lookupScopeEntry(symbol: Symbol): ScopeEntry = {
1209-
var res: ScopeEntry = null
1210-
var ctx = this
1211-
while (res == null && ctx.outer != ctx) {
1212-
val s = ctx.scope lookupSymbolEntry symbol
1213-
if (s != null)
1214-
res = s
1215-
else
1216-
ctx = ctx.outer
1214+
// 1) Must be owned by the same Scope, to ensure that in
1215+
// `{ class C; { ...; object C } }`, the class is not seen as a companion of the object.
1216+
// 2) Must be a class and module symbol, so that `{ class C; def C }` or `{ type T; object T }` are not companions.
1217+
lookupScopeEntry(original) match {
1218+
case null => NoSymbol
1219+
case entry =>
1220+
def isCompanion(sym: Symbol): Boolean =
1221+
(original.isModule && sym.isClass || sym.isModule && original.isClass) && sym.isCoDefinedWith(original)
1222+
entry.owner.lookupNameInSameScopeAs(original, original.name.companionName).filter(isCompanion)
12171223
}
1218-
res
12191224
}
1225+
12201226
} //class Context
12211227

12221228
/** A `Context` focussed on an `Import` tree */

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,9 +1955,12 @@ trait Namers extends MethodSynthesis {
19551955
// Doing this generally would trigger cycles; that's what we also
19561956
// use the lower-level scan through the current Context as a fall back.
19571957
if (!currentRun.compiles(owner)) owner.initialize
1958-
original.companionSymbol orElse {
1959-
ctx.lookupCompanionOf(original)
1960-
}
1958+
1959+
if (original.isModuleClass) original.sourceModule
1960+
else if (!owner.isTerm && owner.hasCompleteInfo)
1961+
original.companionSymbol
1962+
else
1963+
ctx.lookupCompanionInIncompleteOwner(original)
19611964
}
19621965

19631966
/** A version of `Symbol#linkedClassOfClass` that works with local companions, ala `companionSymbolOf`. */

src/reflect/scala/reflect/internal/Scopes.scala

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -291,25 +291,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
291291
null
292292
}
293293

294-
final def lookupCompanion(original: Symbol): Symbol = {
295-
lookupSymbolEntry(original) match {
296-
case null =>
297-
case entry =>
298-
var e = lookupEntry(original.name.companionName)
299-
while (e != null) {
300-
// 1) Must be owned by the same Scope, to ensure that in
301-
// `{ class C; { ...; object C } }`, the class is not seen as a companion of the object.
302-
// 2) Must be a class and module symbol, so that `{ class C; def C }` or `{ type T; object T }` are not companions.
303-
def isClassAndModule(sym1: Symbol, sym2: Symbol) = sym1.isClass && sym2.isModule
304-
if ((e.owner eq entry.owner) && (isClassAndModule(original, e.sym) || isClassAndModule(e.sym, original))) {
305-
return if (e.sym.isCoDefinedWith(original)) e.sym else NoSymbol
306-
}
307-
e = lookupNextEntry(e)
308-
}
309-
}
310-
NoSymbol
311-
}
312-
313294
/** lookup a symbol entry matching given name.
314295
* @note from Martin: I believe this is a hotspot or will be one
315296
* in future versions of the type system. I have reverted the previous
@@ -345,6 +326,20 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
345326
e
346327
}
347328

329+
final def lookupNameInSameScopeAs(original: Symbol, companionName: Name): Symbol = {
330+
lookupSymbolEntry(original) match {
331+
case null =>
332+
case entry =>
333+
var e = lookupEntry(companionName)
334+
while (e != null) {
335+
if (e.owner eq entry.owner) return e.sym
336+
e = lookupNextEntry(e)
337+
}
338+
}
339+
NoSymbol
340+
}
341+
342+
348343
/** TODO - we can test this more efficiently than checking isSubScope
349344
* in both directions. However the size test might be enough to quickly
350345
* rule out most failures.

0 commit comments

Comments
 (0)