8000 Merge pull request #5550 from retronym/ticket/3772 · scala/scala@d34e44e · GitHub
[go: up one dir, main page]

Skip to content

Commit d34e44e

Browse files
authored
Merge pull request #5550 from retronym/ticket/3772
SI-3772 Fix detection of term-owned companions
2 parents 623f0a7 + 9502a06 commit d34e44e

File tree

9 files changed

+102
-25
lines changed

9 files changed

+102
-25
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,27 @@ trait Contexts { self: Analyzer =>
11921192
}
11931193
res
11941194
}
1195+
1196+
final def lookupCompanionOf(original: Symbol): Symbol = {
1197+
lookupScopeEntry(original) match {
1198+
case null => NoSymbol
1199+
case entry => entry.owner.lookupCompanion(original)
1200+
}
1201+
}
1202+
1203+
/** Search scopes in current and enclosing contexts for the definition of `symbol` */
1204+
private def lookupScopeEntry(symbol: Symbol): ScopeEntry = {
1205+
var res: ScopeEntry = null
1206+
var ctx = this
1207+
while (res == null && ctx.outer != ctx) {
1208+
val s = ctx.scope lookupSymbolEntry symbol
1209+
if (s != null)
1210+
res = s
1211+
else
1212+
ctx = ctx.outer
1213+
}
1214+
res
1215+
}
11951216
} //class Context
11961217

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

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ trait Namers extends MethodSynthesis {
220220

221221
private def inCurrentScope(m: Symbol): Boolean = {
222222
if (owner.isClass) owner == m.owner
223-
else m.owner.isClass && context.scope == m.owner.info.decls
223+
else context.scope.lookupSymbolEntry(m) match {
224+
case null => false
225+
case entry => entry.owner eq context.scope
226+
}
224227
}
225228

226229
/** Enter symbol into context's scope and return symbol itself */
@@ -1953,10 +1956,7 @@ trait Namers extends MethodSynthesis {
19531956
// use the lower-level scan through the current Context as a fall back.
19541957
if (!currentRun.compiles(owner)) owner.initialize
19551958
original.companionSymbol orElse {
1956-
ctx.lookup(original.name.companionName, owner).suchThat(sym =>
1957-
(original.isTerm || sym.hasModuleFlag) &&
1958-
(sym isCoDefinedWith original)
1959-
)
1959+
ctx.lookupCompanionOf(original)
19601960
}
19611961
}
19621962

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,34 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
282282
}
283283
}
284284

285+
final def lookupSymbolEntry(sym: Symbol): ScopeEntry = {
286+
var e = lookupEntry(sym.name)
287+
while (e ne null) {
288+
if (e.sym == sym) return e
289+
e = lookupNextEntry(e)
290+
}
291+
null
292+
}
293+
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 comaniopn 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+
285313
/** lookup a symbol entry matching given name.
286314
* @note from Martin: I believe this is a hotspot or will be one
287315
* in future versions of the type system. I have reverted the previous

test/files/neg/t3772.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
t3772.scala:7: error: value inner is not a member of object CC
2+
CC.inner
3+
^
4+
t3772.scala:14: error: value outer is not a member of object CC
5+
CC.outer
6+
^
7+
two errors found

test/files/neg/t3772.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Test {
2+
def m = {
3+
case class CC(c: Int)
4+
if ("".isEmpty) {
5+
object CC { def inner = 42}
6+
}
7+
CC.inner
8+
}
9+
def n = {
10+
object CC { val outer = 42 }
11+
if ("".isEmpty) {
12+
case class CC(c: Int)
13+
CC(0).c
14+
CC.outer
15+
}
16+
}
17+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
t8002-nested-scope.scala:8: error: method x in class C cannot be accessed in C
2+
new C().x
3+
^
4+
one error found
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class C {
2+
def foo = {
3+
class C { private def x = 0 }
4+
5+
{
6+
val a = 0
7+
object C {
8+
new C().x
9+
}
10+
}
11+
}
12+
}

test/files/pos/t3772.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class Test {
2+
def m = {
3+
case class C(c: Int)
4+
object C { def xxx = true}
5+
C(42).c
6+
C.xxx
7+
}
8+
}

test/files/pos/t8002-nested-scope.scala

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)
0