aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala12
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala3
-rw-r--r--src/dotty/tools/dotc/core/Types.scala8
-rw-r--r--src/dotty/tools/dotc/printing/Disambiguation.scala4
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala3
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala10
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala40
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala4
-rw-r--r--src/dotty/tools/dotc/typer/VarianceChecker.scala2
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/neg/i997.scala47
-rw-r--r--tests/neg/i997a.scala19
13 files changed, 140 insertions, 16 deletions
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index 340b4e671..31ebc4a7d 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -232,6 +232,7 @@ object desugar {
def classDef(cdef: TypeDef)(implicit ctx: Context): Tree = {
val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef
val mods = cdef.mods
+ val accessFlags = (mods.flags & AccessFlags).toCommonFlags
val (constr1, defaultGetters) = defDef(constr0, isPrimaryConstructor = true) match {
case meth: DefDef => (meth, Nil)
@@ -312,6 +313,7 @@ object desugar {
case ValDef(_, tpt, _) => isRepeated(tpt)
case _ => false
})
+
val copyMeths =
if (mods.is(Abstract) || hasRepeatedParam) Nil // cannot have default arguments for repeated parameters, hence copy method is not issued
else {
@@ -346,7 +348,7 @@ object desugar {
moduleDef(
ModuleDef(
name.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs))
- .withMods(synthetic))
+ .withFlags(Synthetic | accessFlags))
.withPos(cdef.pos).toList
// The companion object definitions, if a companion is needed, Nil otherwise.
@@ -371,7 +373,7 @@ object desugar {
if (mods is Abstract) Nil
else
DefDef(nme.apply, derivedTparams, derivedVparamss, TypeTree(), creatorExpr)
- .withMods(synthetic | (constr1.mods.flags & DefaultParameterized)) :: Nil
+ .withFlags(Synthetic | (constr1.mods.flags & DefaultParameterized)) :: Nil
val unapplyMeth = {
val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
val unapplyRHS = if (arity == 0) Literal(Constant(true)) else Ident(unapplyParam.name)
@@ -403,7 +405,7 @@ object desugar {
// implicit wrapper is typechecked in same scope as constructor, so
// we can reuse the constructor parameters; no derived params are needed.
DefDef(name.toTermName, constrTparams, constrVparamss, classTypeRef, creatorExpr)
- .withFlags(Synthetic | Implicit)
+ .withFlags(Synthetic | Implicit | accessFlags)
.withPos(cdef.pos) :: Nil
@@ -453,7 +455,7 @@ object desugar {
val clsName = name.moduleClassName
val clsRef = Ident(clsName)
val modul = ValDef(name, clsRef, New(clsRef, Nil))
- .withMods(mods | ModuleCreationFlags)
+ .withMods(mods | ModuleCreationFlags | mods.flags & AccessFlags)
.withPos(mdef.pos)
val ValDef(selfName, selfTpt, _) = tmpl.self
val selfMods = tmpl.self.mods
@@ -515,7 +517,7 @@ object desugar {
derivedValDef(named, tpt, matchExpr, mods)
case _ =>
val tmpName = ctx.freshName().toTermName
- val patFlags = PrivateLocal | Synthetic | (mods.flags & Lazy)
+ val patFlags = mods.flags & AccessFlags | Synthetic | (mods.flags & Lazy)
val firstDef = ValDef(tmpName, TypeTree(), matchExpr).withFlags(patFlags)
def selector(n: Int) = Select(Ident(tmpName), nme.selectorName(n))
val restDefs =
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index a16901fa1..b6f4924ed 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -543,6 +543,9 @@ object Flags {
/** A lazy or deferred value */
final val LazyOrDeferred = Lazy | Deferred
+ /** A synthetic or private definition */
+ final val SyntheticOrPrivate = Synthetic | Private
+
/** A type parameter or type parameter accessor */
final val TypeParamOrAccessor = TypeParam | TypeParamAccessor
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 887b69712..da3b76c57 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -1018,6 +1018,12 @@ object Types {
case _ => List()
}
+ /** The full parent types, including all type arguments */
+ def parentsWithArgs(implicit ctx: Context): List[Type] = this match {
+ case tp: TypeProxy => tp.underlying.parentsWithArgs
+ case _ => List()
+ }
+
/** The first parent of this type, AnyRef if list of parents is empty */
def firstParent(implicit ctx: Context): TypeRef = parents match {
case p :: _ => p
@@ -2785,7 +2791,7 @@ object Types {
}
/** The parent types with all type arguments */
- def instantiatedParents(implicit ctx: Context): List[Type] =
+ override def parentsWithArgs(implicit ctx: Context): List[Type] =
parents mapConserve { pref =>
((pref: Type) /: pref.classSymbol.typeParams) { (parent, tparam) =>
val targSym = decls.lookup(tparam.name)
diff --git a/src/dotty/tools/dotc/printing/Disambiguation.scala b/src/dotty/tools/dotc/printing/Disambiguation.scala
index 29b290f03..aa3fae2de 100644
--- a/src/dotty/tools/dotc/printing/Disambiguation.scala
+++ b/src/dotty/tools/dotc/printing/Disambiguation.scala
@@ -14,12 +14,12 @@ object Disambiguation {
val variants = new mutable.HashMap[String, mutable.ListBuffer[Symbol]]
}
- def newPrinter: Context => Printer = {
+ def newPrinter: Context => RefinedPrinter = {
val state = new State
new Printer(state)(_)
}
- class Printer(state: State)(_ctx: Context) extends RefinedPrinter(_ctx) {
+ private class Printer(state: State)(_ctx: Context) extends RefinedPrinter(_ctx) {
import state._
override def simpleNameString(sym: Symbol): String = {
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 204fc95f0..068ed4daa 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -160,7 +160,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case ErasedValueType(clazz, underlying) =>
return "ErasedValueType(" ~ toText(clazz.typeRef) ~ ", " ~ toText(underlying) ~ ")"
case tp: ClassInfo =>
- return toTextParents(tp.instantiatedParents) ~ "{...}"
+ return toTextParents(tp.parentsWithArgs) ~ "{...}"
case JavaArrayType(elemtp) =>
return toText(elemtp) ~ "[]"
case tp: SelectionProto =>
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index d6e8199d8..272b1880f 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -106,6 +106,9 @@ trait Reporting { this: Context =>
reporter.report(new Error(msg, pos))
}
+ def errorOrMigrationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
+ if (ctx.scala2Mode) migrationWarning(msg, pos) else error(msg, pos)
+
def restrictionError(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
error(s"Implementation restriction: $msg", pos)
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index d552c16f7..ea5c28fb1 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -130,8 +130,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
private def transformAnnot(annot: Annotation)(implicit ctx: Context): Annotation =
annot.derivedAnnotation(transformAnnot(annot.tree))
- private def transformAnnots(tree: MemberDef)(implicit ctx: Context): Unit =
+ private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
tree.symbol.transformAnnotations(transformAnnot)
+ Checking.checkNoPrivateLeaks(tree)
+ }
private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
val qual = tree.qualifier
@@ -211,10 +213,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
}
finally parentNews = saved
case tree: DefDef =>
- transformAnnots(tree)
+ transformMemberDef(tree)
superAcc.wrapDefDef(tree)(super.transform(tree).asInstanceOf[DefDef])
case tree: TypeDef =>
- transformAnnots(tree)
+ transformMemberDef(tree)
val sym = tree.symbol
val tree1 =
if (sym.isClass) tree
@@ -224,7 +226,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
}
super.transform(tree1)
case tree: MemberDef =>
- transformAnnots(tree)
+ transformMemberDef(tree)
super.transform(tree)
case tree: New if !inJavaAnnot && !parentNews.contains(tree) =>
Checking.checkInstantiable(tree.tpe, tree.pos)
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 414d8952d..b71a3ab2a 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -322,6 +322,46 @@ object Checking {
checkNoConflict(Private, Protected)
checkNoConflict(Abstract, Override)
}
+
+ /** Check the type signature of the symbol `M` defined by `tree` does not refer
+ * to a private type or value which is invisible at a point where `M` is still
+ * visible. As an exception, we allow references to type aliases if the underlying
+ * type of the alias is not a leak. So type aliases are transparent as far as
+ * leak testing is concerned. See 997.scala for tests.
+ */
+ def checkNoPrivateLeaks(tree: MemberDef)(implicit ctx: Context): Unit = {
+ type Errors = List[(String, Position)]
+ val sym = tree.symbol
+ val notPrivate = new TypeAccumulator[Errors] {
+ def accessBoundary(sym: Symbol): Symbol =
+ if (sym.is(Private)) sym.owner
+ else if (sym.privateWithin.exists) sym.privateWithin
+ else if (sym.is(Package)) sym
+ else accessBoundary(sym.owner)
+ def apply(errors: Errors, tp: Type): Errors = tp match {
+ case tp: NamedType =>
+ val errors1 =
+ if (tp.symbol.is(Private) &&
+ !accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
+ (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", tree.pos) :: errors
+ } else foldOver(errors, tp)
+ if ((errors1 ne errors) && tp.info.isAlias) {
+ // try to dealias to avoid a leak error
+ val errors2 = apply(errors, tp.info.bounds.hi)
+ if (errors2 eq errors) errors2
+ else errors1
+ } else errors1
+ case tp: ClassInfo =>
+ (apply(errors, tp.prefix) /: tp.parentsWithArgs)(apply)
+ case _ =>
+ foldOver(errors, tp)
+ }
+ }
+ if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
+ val errors = notPrivate(Nil, sym.info)
+ errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
+ }
+ }
}
trait Checking {
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index fd4f0011c..476839ab3 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -71,7 +71,7 @@ trait TypeAssigner {
if (tp1.typeSymbol.exists)
return tp1
}
- val parentType = info.instantiatedParents.reduceLeft(ctx.typeComparer.andType(_, _))
+ val parentType = info.parentsWithArgs.reduceLeft(ctx.typeComparer.andType(_, _))
def addRefinement(parent: Type, decl: Symbol) = {
val inherited =
parentType.findMember(decl.name, info.cls.thisType, Private)
@@ -292,7 +292,7 @@ trait TypeAssigner {
else if (!mix.isEmpty) findMixinSuper(cls.info)
else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent
else {
- val ps = cls.classInfo.instantiatedParents
+ val ps = cls.classInfo.parentsWithArgs
if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y)
}
tree.withType(SuperType(cls.thisType, owntype))
diff --git a/src/dotty/tools/dotc/typer/VarianceChecker.scala b/src/dotty/tools/dotc/typer/VarianceChecker.scala
index bbe391726..b257ee192 100644
--- a/src/dotty/tools/dotc/typer/VarianceChecker.scala
+++ b/src/dotty/tools/dotc/typer/VarianceChecker.scala
@@ -13,7 +13,7 @@ import config.Printers.variances
* The method should be invoked once for each Template.
*/
object VarianceChecker {
- private case class VarianceError(tvar: Symbol, required: Variance)
+ case class VarianceError(tvar: Symbol, required: Variance)
def check(tree: tpd.Tree)(implicit ctx: Context) =
new VarianceChecker()(ctx).Traverser.traverse(tree)
}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 6a61ec62a..819526ce4 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -166,6 +166,8 @@ class tests extends CompilerTest {
@Test def neg_i803 = compileFile(negDir, "i803", xerrors = 2)
@Test def neg_i866 = compileFile(negDir, "i866", xerrors = 2)
@Test def neg_i974 = compileFile(negDir, "i974", xerrors = 2)
+ @Test def neg_i997 = compileFile(negDir, "i997", xerrors = 15)
+ @Test def neg_i997a = compileFile(negDir, "i997a", xerrors = 2)
@Test def neg_i1050 = compileFile(negDir, "i1050", List("-strict"), xerrors = 11)
@Test def neg_i1050a = compileFile(negDir, "i1050a", xerrors = 2)
@Test def neg_i1050c = compileFile(negDir, "i1050c", xerrors = 8)
diff --git a/tests/neg/i997.scala b/tests/neg/i997.scala
new file mode 100644
index 000000000..8a21661fb
--- /dev/null
+++ b/tests/neg/i997.scala
@@ -0,0 +1,47 @@
+class C {
+
+ private type T = E
+ private type Tok = D
+ private val p: C = new C
+
+ def f1(x: T): Unit = () // error
+ def f1(x: Tok): Unit = () // ok
+ def f2(x: p.D): Unit = () // error
+
+ val v1: T = ??? // error
+ val v2: p.D = ??? // error
+
+ type U1[X <: T] // error
+ type U2 = T // error
+
+ private class E {
+ def f1ok(x: T): Unit = () // ok
+ def f2ok(x: p.D): Unit = () // ok
+
+ val v1ok: T = ??? // ok
+ val v2ok: p.D = ??? // ok
+
+ type U1ok[X <: T] //ok
+ type U2ok = T //ok
+ }
+
+ class D extends E { // error
+ def f1(x: T): Unit = () // error
+ def f2(x: p.D): Unit = () // error
+
+ val v1: T = ??? // error
+ val v2: p.D = ??? // error
+
+ type U1[X <: T] // error
+ type U2 = T // error
+ }
+
+ class F(x: T) // error
+
+ class G private (x: T) // ok
+
+ private trait U
+
+ class H extends U // error
+
+}
diff --git a/tests/neg/i997a.scala b/tests/neg/i997a.scala
new file mode 100644
index 000000000..eae56400f
--- /dev/null
+++ b/tests/neg/i997a.scala
@@ -0,0 +1,19 @@
+class C {
+
+ class Super
+
+ object O {
+
+ private case class CC(x: Int)
+
+ private implicit class D(x: Int) extends Super
+ }
+
+ import O._
+
+ println(O.CC(1)) // error: CC cannot be accessed
+
+ val s: Super = 1 // error: type mismatch
+
+
+}