summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala48
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala9
-rw-r--r--test/files/neg/t3663.check4
-rw-r--r--test/files/neg/t3663/PackageProtected.java5
-rw-r--r--test/files/neg/t3663/main.scala14
6 files changed, 63 insertions, 18 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 96b065ae61..c7d198b638 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1074,6 +1074,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
/** A clone of this symbol, but with given owner */
final def cloneSymbol(owner: Symbol): Symbol = {
val newSym = cloneSymbolImpl(owner)
+ // newSym.privateWithin = privateWithin // ?
newSym.setInfo(info.cloneInfo(newSym))
.setFlag(this.rawflags).setAnnotations(this.annotations)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 7469388a08..42c1329edf 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -8,6 +8,7 @@ package typechecker
import symtab.Flags._
import scala.collection.mutable.ListBuffer
+import annotation.tailrec
/** This trait ...
*
@@ -349,9 +350,26 @@ trait Contexts { self: Analyzer =>
* @return ...
*/
def isAccessible(sym: Symbol, pre: Type, superAccess: Boolean): Boolean = {
+ @inline def accessWithinLinked(ab: Symbol) = {
+ val linked = ab.linkedClassOfClass
+ // don't have access if there is no linked class
+ // (before adding the `ne NoSymbol` check, this was a no-op when linked eq NoSymbol,
+ // since `accessWithin(NoSymbol) == true` whatever the symbol)
+ (linked ne NoSymbol) && accessWithin(linked)
+ }
+
+ /** Are we inside definition of `ab'? */
+ def accessWithin(ab: Symbol) = {
+ // #3663: we must disregard package nesting if sym isJavaDefined
+ if(sym.isJavaDefined) {
+ // is `o` or one of its transitive owners equal to `ab`?
+ // stops at first package, since further owners can only be surrounding packages
+ @tailrec def abEnclosesStopAtPkg(o: Symbol): Boolean =
+ (o eq ab) || (!o.isPackageClass && (o ne NoSymbol) && abEnclosesStopAtPkg(o.owner))
+ abEnclosesStopAtPkg(owner)
+ } else (owner hasTransOwner ab)
+ }
- /** Are we inside definition of `sym'? */
- def accessWithin(sym: Symbol): Boolean = this.owner.ownersIterator contains sym
/*
var c = this
while (c != NoContext && c.owner != owner) {
@@ -373,18 +391,20 @@ trait Contexts { self: Analyzer =>
(pre == NoPrefix) || {
val ab = sym.accessBoundary(sym.owner)
- ((ab.isTerm || ab == definitions.RootClass)
- ||
- (accessWithin(ab) || accessWithin(ab.linkedClassOfClass)) &&
- (!sym.hasFlag(LOCAL) ||
- sym.owner.isImplClass || // allow private local accesses to impl classes
- (sym hasFlag PROTECTED) && isSubThisType(pre, sym.owner) ||
- pre =:= sym.owner.thisType)
- ||
- (sym hasFlag PROTECTED) &&
- (superAccess || sym.isConstructor ||
- (pre.widen.typeSymbol.isNonBottomSubClass(sym.owner) &&
- (isSubClassOfEnclosing(pre.widen.typeSymbol) || phase.erasedTypes))))
+ ( (ab.isTerm || ab == definitions.RootClass)
+ || (accessWithin(ab) || accessWithinLinked(ab)) &&
+ ( !sym.hasFlag(LOCAL)
+ || sym.owner.isImplClass // allow private local accesses to impl classes
+ || (sym hasFlag PROTECTED) && isSubThisType(pre, sym.owner)
+ || pre =:= sym.owner.thisType
+ )
+ || (sym hasFlag PROTECTED) &&
+ ( superAccess
+ || sym.isConstructor
+ || (pre.widen.typeSymbol.isNonBottomSubClass(sym.owner) &&
+ (isSubClassOfEnclosing(pre.widen.typeSymbol) || phase.erasedTypes))
+ )
+ )
// note: phase.erasedTypes disables last test, because after addinterfaces
// implementation classes are not in the superclass chain. If we enable the
// test, bug780 fails.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index b3ea178aaa..91d7b1d12c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -374,8 +374,9 @@ trait Namers { self: Analyzer =>
name.endsWith(nme.OUTER, nme.OUTER.length) ||
context.unit.isJava) &&
!mods.isLazy) {
- tree.symbol = enterInScope(owner.newValue(tree.pos, name)
- .setFlag(mods.flags))
+ val vsym = owner.newValue(tree.pos, name).setFlag(mods.flags);
+ if(context.unit.isJava) setPrivateWithin(tree, vsym, mods) // #3663
+ tree.symbol = enterInScope(vsym)
finish
} else {
val mods1 =
@@ -418,7 +419,7 @@ trait Namers { self: Analyzer =>
addBeanGetterSetter(vd, getter)
}
case DefDef(mods, nme.CONSTRUCTOR, tparams, _, _, _) =>
- var sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags))
+ val sym = owner.newConstructor(tree.pos).setFlag(mods.flags | owner.getFlag(ConstrFlags))
setPrivateWithin(tree, sym, mods)
tree.symbol = enterInScope(sym)
finishWith(tparams)
@@ -428,7 +429,7 @@ trait Namers { self: Analyzer =>
case TypeDef(mods, name, tparams, _) =>
var flags: Long = mods.flags
if ((flags & PARAM) != 0L) flags |= DEFERRED
- var sym = new TypeSymbol(owner, tree.pos, name).setFlag(flags)
+ val sym = new TypeSymbol(owner, tree.pos, name).setFlag(flags)
setPrivateWithin(tree, sym, mods)
tree.symbol = enterInScope(sym)
finishWith(tparams)
diff --git a/test/files/neg/t3663.check b/test/files/neg/t3663.check
new file mode 100644
index 0000000000..09ea25ad91
--- /dev/null
+++ b/test/files/neg/t3663.check
@@ -0,0 +1,4 @@
+main.scala:11: error: variable foo cannot be accessed in test.Test
+ println(t.foo)
+ ^
+one error found
diff --git a/test/files/neg/t3663/PackageProtected.java b/test/files/neg/t3663/PackageProtected.java
new file mode 100644
index 0000000000..f4535a55b4
--- /dev/null
+++ b/test/files/neg/t3663/PackageProtected.java
@@ -0,0 +1,5 @@
+package test;
+
+class PackageProtected {
+ int foo;
+}
diff --git a/test/files/neg/t3663/main.scala b/test/files/neg/t3663/main.scala
new file mode 100644
index 0000000000..29619550cc
--- /dev/null
+++ b/test/files/neg/t3663/main.scala
@@ -0,0 +1,14 @@
+package test
+
+final class Test extends PackageProtected {
+ def bar = foo
+}
+
+package another {
+ object Main {
+ def bug(t: Test) {
+ // Can always be replicated.
+ println(t.foo)
+ }
+ }
+} \ No newline at end of file