diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 48 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 9 | ||||
-rw-r--r-- | test/files/neg/t3663.check | 4 | ||||
-rw-r--r-- | test/files/neg/t3663/PackageProtected.java | 5 | ||||
-rw-r--r-- | test/files/neg/t3663/main.scala | 14 |
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 |