From cad41d293610ce06bfc2e6f0077080ba43264a8c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 2 Jan 2018 19:41:31 +0100 Subject: [PATCH 1/2] Fix #3339: Disallow accesses to private package members from nested pkgs Change of the accessibility rules: Disallow accesses to private package members from nested packages. Such accesses were causing an access error at runtime before. --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 17390f830ecf..128f884d53aa 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -674,10 +674,7 @@ object SymDenotations { final def isAccessibleFrom(pre: Type, superAccess: Boolean = false, whyNot: StringBuffer = null)(implicit ctx: Context): Boolean = { /** Are we inside definition of `boundary`? */ - def accessWithin(boundary: Symbol) = - ctx.owner.isContainedIn(boundary) && - (!(this is JavaDefined) || // disregard package nesting for Java - ctx.owner.enclosingPackageClass == boundary.enclosingPackageClass) + def accessWithin(boundary: Symbol) = ctx.owner.isContainedIn(boundary) /** Are we within definition of linked class of `boundary`? */ def accessWithinLinked(boundary: Symbol) = { @@ -733,7 +730,9 @@ object SymDenotations { ( !(this is Local) || (owner is ImplClass) // allow private local accesses to impl class members || isCorrectThisType(pre) - ) + ) && + (!(this.is(Private) && owner.is(Package)) || + owner == ctx.owner.enclosingPackageClass) || (this is Protected) && ( superAccess || pre.isInstanceOf[ThisType] From 894d77964d4563dafa357b3952eb54cb1c5a2102 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 2 Jan 2018 19:42:46 +0100 Subject: [PATCH 2/2] Improve access error messages + test case --- .../dotty/tools/dotc/typer/TypeAssigner.scala | 21 ++++++++++++++----- tests/neg/i3339.scala | 11 ++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 tests/neg/i3339.scala diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 59210fde2ea7..483140e3069a 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -195,19 +195,30 @@ trait TypeAssigner { TryDynamicCallType } else { val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists) + var packageAccess = false val what = alts match { case Nil => - name.toString + i"$name cannot be accessed as a member of $pre" case sym :: Nil => - if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated + if (sym.owner.is(Package)) { + packageAccess = true + i"${sym.showLocated} cannot be accessed" + } + else { + val symStr = if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated + i"$symStr cannot be accessed as a member of $pre" + } case _ => - em"none of the overloaded alternatives named $name" + em"none of the overloaded alternatives named $name can be accessed as members of $pre" } - val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else "" + val where = + if (!ctx.owner.exists) "" + else if (packageAccess) i" from nested ${ctx.owner.enclosingPackageClass}" + else i" from ${ctx.owner.enclosingClass}" val whyNot = new StringBuffer alts foreach (_.isAccessibleFrom(pre, superAccess, whyNot)) if (tpe.isError) tpe - else errorType(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos) + else errorType(ex"$what$where.$whyNot", pos) } } else ctx.makePackageObjPrefixExplicit(tpe withDenot d) diff --git a/tests/neg/i3339.scala b/tests/neg/i3339.scala new file mode 100644 index 000000000000..7494df2b6f99 --- /dev/null +++ b/tests/neg/i3339.scala @@ -0,0 +1,11 @@ +package outer { + private class A + + package inner { + object Test { + def main(args: Array[String]): Unit = { + println(new A) // error: cannot access + } + } + } +}