summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-12-12 15:10:01 +0100
committerGitHub <noreply@github.com>2016-12-12 15:10:01 +0100
commitd34e44e99488e4f91a677ddbc2e8ae6232273456 (patch)
tree6fa403cdd85cf273072662894a52083c3b86bc81
parent623f0a72bad9513a154b4a6367c5e215adf769d0 (diff)
parent9502a061fa007ceb1d4e550fdb386a3645c67b1c (diff)
downloadscala-d34e44e99488e4f91a677ddbc2e8ae6232273456.tar.gz
scala-d34e44e99488e4f91a677ddbc2e8ae6232273456.tar.bz2
scala-d34e44e99488e4f91a677ddbc2e8ae6232273456.zip
Merge pull request #5550 from retronym/ticket/3772
SI-3772 Fix detection of term-owned companions
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala28
-rw-r--r--test/files/neg/t3772.check7
-rw-r--r--test/files/neg/t3772.scala17
-rw-r--r--test/files/neg/t8002-nested-scope.check4
-rw-r--r--test/files/neg/t8002-nested-scope.scala12
-rw-r--r--test/files/pos/t3772.scala8
-rw-r--r--test/files/pos/t8002-nested-scope.scala20
9 files changed, 102 insertions, 25 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 8f0625e58c..fde2f7bb03 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -1192,6 +1192,27 @@ trait Contexts { self: Analyzer =>
}
res
}
+
+ final def lookupCompanionOf(original: Symbol): Symbol = {
+ lookupScopeEntry(original) match {
+ case null => NoSymbol
+ case entry => entry.owner.lookupCompanion(original)
+ }
+ }
+
+ /** Search scopes in current and enclosing contexts for the definition of `symbol` */
+ private def lookupScopeEntry(symbol: Symbol): ScopeEntry = {
+ var res: ScopeEntry = null
+ var ctx = this
+ while (res == null && ctx.outer != ctx) {
+ val s = ctx.scope lookupSymbolEntry symbol
+ if (s != null)
+ res = s
+ else
+ ctx = ctx.outer
+ }
+ res
+ }
} //class Context
/** A `Context` focussed on an `Import` tree */
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index b445bc5837..395bda234b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -220,7 +220,10 @@ trait Namers extends MethodSynthesis {
private def inCurrentScope(m: Symbol): Boolean = {
if (owner.isClass) owner == m.owner
- else m.owner.isClass && context.scope == m.owner.info.decls
+ else context.scope.lookupSymbolEntry(m) match {
+ case null => false
+ case entry => entry.owner eq context.scope
+ }
}
/** Enter symbol into context's scope and return symbol itself */
@@ -1953,10 +1956,7 @@ trait Namers extends MethodSynthesis {
// use the lower-level scan through the current Context as a fall back.
if (!currentRun.compiles(owner)) owner.initialize
original.companionSymbol orElse {
- ctx.lookup(original.name.companionName, owner).suchThat(sym =>
- (original.isTerm || sym.hasModuleFlag) &&
- (sym isCoDefinedWith original)
- )
+ ctx.lookupCompanionOf(original)
}
}
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index a7bb127506..32ce02bdd6 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -282,6 +282,34 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
}
+ final def lookupSymbolEntry(sym: Symbol): ScopeEntry = {
+ var e = lookupEntry(sym.name)
+ while (e ne null) {
+ if (e.sym == sym) return e
+ e = lookupNextEntry(e)
+ }
+ null
+ }
+
+ final def lookupCompanion(original: Symbol): Symbol = {
+ lookupSymbolEntry(original) match {
+ case null =>
+ case entry =>
+ var e = lookupEntry(original.name.companionName)
+ while (e != null) {
+ // 1) Must be owned by the same Scope, to ensure that in
+ // `{ class C; { ...; object C } }`, the class is not seen as a comaniopn of the object.
+ // 2) Must be a class and module symbol, so that `{ class C; def C }` or `{ type T; object T }` are not companions.
+ def isClassAndModule(sym1: Symbol, sym2: Symbol) = sym1.isClass && sym2.isModule
+ if ((e.owner eq entry.owner) && (isClassAndModule(original, e.sym) || isClassAndModule(e.sym, original))) {
+ return if (e.sym.isCoDefinedWith(original)) e.sym else NoSymbol
+ }
+ e = lookupNextEntry(e)
+ }
+ }
+ NoSymbol
+ }
+
/** lookup a symbol entry matching given name.
* @note from Martin: I believe this is a hotspot or will be one
* in future versions of the type system. I have reverted the previous
diff --git a/test/files/neg/t3772.check b/test/files/neg/t3772.check
new file mode 100644
index 0000000000..d1ed39d8b6
--- /dev/null
+++ b/test/files/neg/t3772.check
@@ -0,0 +1,7 @@
+t3772.scala:7: error: value inner is not a member of object CC
+ CC.inner
+ ^
+t3772.scala:14: error: value outer is not a member of object CC
+ CC.outer
+ ^
+two errors found
diff --git a/test/files/neg/t3772.scala b/test/files/neg/t3772.scala
new file mode 100644
index 0000000000..cac4932d4a
--- /dev/null
+++ b/test/files/neg/t3772.scala
@@ -0,0 +1,17 @@
+class Test {
+ def m = {
+ case class CC(c: Int)
+ if ("".isEmpty) {
+ object CC { def inner = 42}
+ }
+ CC.inner
+ }
+ def n = {
+ object CC { val outer = 42 }
+ if ("".isEmpty) {
+ case class CC(c: Int)
+ CC(0).c
+ CC.outer
+ }
+ }
+}
diff --git a/test/files/neg/t8002-nested-scope.check b/test/files/neg/t8002-nested-scope.check
new file mode 100644
index 0000000000..f66249e432
--- /dev/null
+++ b/test/files/neg/t8002-nested-scope.check
@@ -0,0 +1,4 @@
+t8002-nested-scope.scala:8: error: method x in class C cannot be accessed in C
+ new C().x
+ ^
+one error found
diff --git a/test/files/neg/t8002-nested-scope.scala b/test/files/neg/t8002-nested-scope.scala
new file mode 100644
index 0000000000..44704a12b1
--- /dev/null
+++ b/test/files/neg/t8002-nested-scope.scala
@@ -0,0 +1,12 @@
+class C {
+ def foo = {
+ class C { private def x = 0 }
+
+ {
+ val a = 0
+ object C {
+ new C().x
+ }
+ }
+ }
+}
diff --git a/test/files/pos/t3772.scala b/test/files/pos/t3772.scala
new file mode 100644
index 0000000000..62c433ebd1
--- /dev/null
+++ b/test/files/pos/t3772.scala
@@ -0,0 +1,8 @@
+class Test {
+ def m = {
+ case class C(c: Int)
+ object C { def xxx = true}
+ C(42).c
+ C.xxx
+ }
+}
diff --git a/test/files/pos/t8002-nested-scope.scala b/test/files/pos/t8002-nested-scope.scala
deleted file mode 100644
index 8ce809e556..0000000000
--- a/test/files/pos/t8002-nested-scope.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-// This test serves to capture the status quo, but should really
-// emit an accessibility error.
-
-// `Namers#companionSymbolOf` seems too lenient, and currently doesn't
-// implement the same-scope checks mentioned:
-//
-// https://github.com/scala/scala/pull/2816#issuecomment-22555206
-//
-class C {
- def foo = {
- class C { private def x = 0 }
-
- {
- val a = 0
- object C {
- new C().x
- }
- }
- }
-}