summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Cunei <antonio.cunei@epfl.ch>2010-09-02 11:59:38 +0000
committerAntonio Cunei <antonio.cunei@epfl.ch>2010-09-02 11:59:38 +0000
commitc51f9f392fa1603e4d2b692bdcca9ffac3710539 (patch)
tree465b73d07033ac6e21bd6f73b233dc41c12d7205
parent918fb944b611ee08b5f5596c2fbc5123d2f09917 (diff)
downloadscala-c51f9f392fa1603e4d2b692bdcca9ffac3710539.tar.gz
scala-c51f9f392fa1603e4d2b692bdcca9ffac3710539.tar.bz2
scala-c51f9f392fa1603e4d2b692bdcca9ffac3710539.zip
Merged revisions 22802-22803 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk ........ r22802 | moors | 2010-08-20 12:01:09 +0200 (Fri, 20 Aug 2010) | 6 lines closes #3575. stricter override checking for java members with default access: can only override such a member from the same package cloneSymbol now preserves privateWithin -- need to reset it explicitly now when before it was assumed to be not to be carried over rewrote accessibility in overriding checks so they're more readable, but hopefully with same semantics review by odersky ........ r22803 | moors | 2010-08-20 13:32:45 +0200 (Fri, 20 Aug 2010) | 2 lines closes #3757. got paren wrong during refactoring. no review ........
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala5
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala44
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala1
-rw-r--r--test/files/neg/t3757.check4
-rw-r--r--test/files/neg/t3757/A.java5
-rw-r--r--test/files/neg/t3757/B.scala5
9 files changed, 62 insertions, 30 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index 9470078507..28aadda14d 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -196,10 +196,7 @@ abstract class ClosureElimination extends SubComponent {
/** is field 'f' accessible from method 'm'? */
def accessible(f: Symbol, m: Symbol): Boolean =
- f.isPublic || (f.hasFlag(Flags.PROTECTED) && (enclPackage(f) == enclPackage(m)))
-
- private def enclPackage(sym: Symbol): Symbol =
- if ((sym == NoSymbol) || sym.isPackageClass) sym else enclPackage(sym.owner)
+ f.isPublic || (f.hasFlag(Flags.PROTECTED) && (f.enclosingPackageClass == m.enclosingPackageClass))
} /* class ClosureElim */
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index e16612ae49..8d02a120d3 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -1064,7 +1064,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.privateWithin = privateWithin
newSym.setInfo(info.cloneInfo(newSym))
.setFlag(this.rawflags).setAnnotations(this.annotations)
}
@@ -1184,19 +1184,25 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
*/
def ancestors: List[Symbol] = info.baseClasses drop 1
- /** The package containing this symbol, or NoSymbol if there
+ /** The package class containing this symbol, or NoSymbol if there
* is not one. */
- def enclosingPackage: Symbol =
+ def enclosingPackageClass: Symbol =
if (this == NoSymbol) this else {
var packSym = this.owner
while ((packSym != NoSymbol)
&& !packSym.isPackageClass)
packSym = packSym.owner
- if (packSym != NoSymbol)
- packSym = packSym.companionModule
packSym
}
+ /** The package containing this symbol, or NoSymbol if there
+ * is not one. */
+ def enclosingPackage: Symbol = {
+ val packSym = enclosingPackageClass
+ if (packSym != NoSymbol) packSym.companionModule
+ else packSym
+ }
+
/** The top-level class containing this symbol */
def toplevelClass: Symbol =
if (owner.isPackageClass) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 7f68876327..235f067c95 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -377,7 +377,7 @@ trait Namers { self: Analyzer =>
context.unit.isJava) &&
!mods.isLazy) {
val vsym = owner.newValue(tree.pos, name).setFlag(mods.flags);
- if(context.unit.isJava) setPrivateWithin(tree, vsym, mods) // #3663
+ if(context.unit.isJava) setPrivateWithin(tree, vsym, mods) // #3663 -- for Scala fields we assume private[this]
tree.symbol = enterInScope(vsym)
finish
} else {
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index c91bac3d7f..3a989a6549 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -266,12 +266,12 @@ abstract class RefChecks extends InfoTransform {
}
}
+ def accessFlagsToString(sym: Symbol)
+ = flagsToString(sym getFlag (PRIVATE | PROTECTED), if (sym.privateWithin eq NoSymbol) "" else sym.privateWithin.name.toString)
+
def overrideAccessError() {
- val pwString = if (other.privateWithin == NoSymbol) ""
- else other.privateWithin.name.toString
- val otherAccess = flagsToString(other getFlag (PRIVATE | PROTECTED), pwString)
- overrideError("has weaker access privileges; it should be "+
- (if (otherAccess == "") "public" else "at least "+otherAccess))
+ val otherAccess = accessFlagsToString(other)
+ overrideError("has weaker access privileges; it should be "+ (if (otherAccess == "") "public" else "at least "+otherAccess))
}
//Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG
@@ -302,14 +302,24 @@ abstract class RefChecks extends InfoTransform {
if (typesOnly) checkOverrideTypes()
else {
- if (member hasFlag PRIVATE) { // (1.1)
+ // o: public | protected | package-protected (aka java's default access)
+ // ^-may be overridden by member with access privileges-v
+ // m: public | public/protected | public/protected/package-protected-in-same-package-as-o
+
+ if (member hasFlag PRIVATE) // (1.1)
overrideError("has weaker access privileges; it should not be private")
- }
- val mb = member.accessBoundary(member.owner)
+
+ @inline def definedIn(sym: Symbol, in: Symbol) = sym != RootClass && sym != NoSymbol && sym.hasTransOwner(in)
+
val ob = other.accessBoundary(member.owner)
- if (mb != RootClass && mb != NoSymbol && // todo: change
- (ob == RootClass || ob == NoSymbol || !ob.hasTransOwner(mb) ||
- (other hasFlag PROTECTED) && !(member hasFlag PROTECTED))) {
+ val mb = member.accessBoundary(member.owner)
+ // println("checking override in "+ clazz +"\n other: "+ infoString(other) +" ab: "+ ob.ownerChain +" flags: "+ accessFlagsToString(other))
+ // println(" overriding member: "+ infoString(member) +" ab: "+ mb.ownerChain +" flags: "+ accessFlagsToString(member))
+ // todo: align accessibility implication checking with isAccessible in Contexts
+ if (!( mb == RootClass // m is public, definitely relaxes o's access restrictions (unless o.isJavaDefined, see below)
+ || mb == NoSymbol // AM: what does this check?? accessBoundary does not ever seem to return NoSymbol (unless member.owner were NoSymbol)
+ || ((!(other hasFlag PROTECTED) || (member hasFlag PROTECTED)) && definedIn(ob, mb)) // (if o isProtected, so is m) and m relaxes o's access boundary
+ )) {
overrideAccessError()
}
else if (other.isClass || other.isModule) {
@@ -379,7 +389,7 @@ abstract class RefChecks extends InfoTransform {
// this overlaps somewhat with validateVariance
if(member.isAliasType) {
val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.normalize), self, member.owner)
-2
+
if(!kindErrors.isEmpty)
unit.error(member.pos,
"The kind of the right-hand side "+memberTp.normalize+" of "+member.keyString+" "+
@@ -534,11 +544,19 @@ abstract class RefChecks extends InfoTransform {
*/
def hasMatchingSym(inclazz: Symbol, member: Symbol): Boolean =
inclazz != clazz && {
+ lazy val memberEnclPackageCls = member.enclosingPackageClass
+
val isVarargs = hasRepeatedParam(member.tpe)
inclazz.info.nonPrivateDecl(member.name).filter { sym =>
- !sym.isTerm || {
+ (!sym.isTerm || {
val symtpe = clazz.thisType.memberType(sym)
(member.tpe matches symtpe) || isVarargs && (toJavaRepeatedParam(member.tpe) matches symtpe)
+ }) && {
+ // http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.5:
+ // If a public class has a [member] with default access, then this [member] is not accessible to,
+ // or inherited by a subclass declared outside this package.
+ // (sym is a java member with default access in pkg P) implies (member's enclosing package == P)
+ !(inclazz.isJavaDefined && sym.privateWithin == sym.enclosingPackageClass) || memberEnclPackageCls == sym.privateWithin
}
} != NoSymbol
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 541ef35b4b..5711117fea 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -422,8 +422,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
&& sym.hasFlag(JAVA)
&& !sym.owner.isPackageClass
&& !accessibleThroughSubclassing
- && (enclPackage(sym.owner) != enclPackage(currentOwner))
- && (enclPackage(sym.owner) == enclPackage(sym.accessBoundary(sym.owner))))
+ && (sym.owner.enclosingPackageClass != currentOwner.enclosingPackageClass)
+ && (sym.owner.enclosingPackageClass == sym.accessBoundary(sym.owner).enclosingPackageClass))
if (res) {
val host = hostForAccessorOf(sym, currentOwner.enclClass)
@@ -441,10 +441,6 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
} else res
}
- /** Return the enclosing package of the given symbol. */
- private def enclPackage(sym: Symbol): Symbol =
- if ((sym == NoSymbol) || sym.isPackageClass) sym else enclPackage(sym.owner)
-
/** Return the innermost enclosing class C of referencingClass for which either
* of the following holds:
* - C is a subclass of sym.owner or
@@ -453,7 +449,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
private def hostForAccessorOf(sym: Symbol, referencingClass: Symbol): Symbol = {
if (referencingClass.isSubClass(sym.owner.enclClass)
|| referencingClass.thisSym.isSubClass(sym.owner.enclClass)
- || enclPackage(referencingClass) == enclPackage(sym.owner)) {
+ || referencingClass.enclosingPackageClass == sym.owner.enclosingPackageClass) {
assert(referencingClass.isClass)
referencingClass
} else if(referencingClass.owner.enclClass != NoSymbol)
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 0da00f5b83..60374b3a55 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -227,6 +227,7 @@ trait SyntheticMethods extends ast.TreeDSL {
var newAcc = tree.symbol.cloneSymbol
newAcc.name = context.unit.fresh.newName(tree.symbol.pos.focus, tree.symbol.name + "$")
newAcc setFlag SYNTHETIC resetFlag (ACCESSOR | PARAMACCESSOR | PRIVATE)
+ newAcc.privateWithin = NoSymbol
newAcc = newAcc.owner.info.decls enter newAcc
val result = typer typed { DEF(newAcc) === rhs.duplicate }
log("new accessor method " + result)
diff --git a/test/files/neg/t3757.check b/test/files/neg/t3757.check
new file mode 100644
index 0000000000..1507df8c4f
--- /dev/null
+++ b/test/files/neg/t3757.check
@@ -0,0 +1,4 @@
+B.scala:4: error: method foo overrides nothing
+ override def foo = "B"
+ ^
+one error found
diff --git a/test/files/neg/t3757/A.java b/test/files/neg/t3757/A.java
new file mode 100644
index 0000000000..37da86fe15
--- /dev/null
+++ b/test/files/neg/t3757/A.java
@@ -0,0 +1,5 @@
+package a;
+
+public abstract class A {
+ abstract String foo(); // package protected!
+} \ No newline at end of file
diff --git a/test/files/neg/t3757/B.scala b/test/files/neg/t3757/B.scala
new file mode 100644
index 0000000000..7c78fb634e
--- /dev/null
+++ b/test/files/neg/t3757/B.scala
@@ -0,0 +1,5 @@
+package b
+
+class B extends a.A {
+ override def foo = "B"
+} \ No newline at end of file