Skip to content

Commit fc043bf

Browse files
committed
Add checking for leaking private definitions
First version. Fixes #997.
1 parent eb1908a commit fc043bf

File tree

5 files changed

+98
-5
lines changed

5 files changed

+98
-5
lines changed

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,9 @@ object Flags {
543543
/** A lazy or deferred value */
544544
final val LazyOrDeferred = Lazy | Deferred
545545

546+
/** A synthetic or private definition */
547+
final val SyntheticOrPrivate = Synthetic | Private
548+
546549
/** A type parameter or type parameter accessor */
547550
final val TypeParamOrAccessor = TypeParam | TypeParamAccessor
548551

src/dotty/tools/dotc/core/Types.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,12 @@ object Types {
10141014
case _ => List()
10151015
}
10161016

1017+
/** The full parent types, including all type arguments */
1018+
def parentsWithArgs(implicit ctx: Context): List[Type] = this match {
1019+
case tp: TypeProxy => tp.underlying.parents
1020+
case _ => List()
1021+
}
1022+
10171023
/** The first parent of this type, AnyRef if list of parents is empty */
10181024
def firstParent(implicit ctx: Context): TypeRef = parents match {
10191025
case p :: _ => p
@@ -2780,6 +2786,9 @@ object Types {
27802786
parentsCache
27812787
}
27822788

2789+
override def parentsWithArgs(implicit ctx: Context): List[Type] =
2790+
parents.map(p => typeRef.baseTypeWithArgs(p.symbol))
2791+
27832792
/** The parent types with all type arguments */
27842793
def instantiatedParents(implicit ctx: Context): List[Type] =
27852794
parents mapConserve { pref =>

src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,42 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
127127
private def transformAnnot(annot: Annotation)(implicit ctx: Context): Annotation =
128128
annot.derivedAnnotation(transformAnnot(annot.tree))
129129

130-
private def transformAnnots(tree: MemberDef)(implicit ctx: Context): Unit =
131-
tree.symbol.transformAnnotations(transformAnnot)
130+
private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
131+
val sym = tree.symbol
132+
sym.transformAnnotations(transformAnnot)
133+
type Errors = List[(String, Position)]
134+
val notPrivate = new TypeAccumulator[Errors] {
135+
def boundary(sym: Symbol): Symbol =
136+
if (sym.is(Private)) sym.owner
137+
else if (sym.privateWithin.exists) sym.privateWithin
138+
else if (sym.is(Package)) sym
139+
else boundary(sym.owner)
140+
def apply(errors: Errors, tp: Type): Errors = tp match {
141+
case tp: NamedType =>
142+
val errors1 =
143+
if (tp.symbol.is(Private) &&
144+
!boundary(sym).isContainedIn(boundary(tp.symbol))) {
145+
//println(i"sym = $sym, ref = ${tp.symbol}, symb = ${boundary(sym)}, refb = ${boundary(tp.symbol)}")
146+
(d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", tree.pos) :: errors
147+
}
148+
else foldOver(errors, tp)
149+
if ((errors1 ne errors) && tp.info.isAlias) {
150+
val errors2 = apply(errors, tp.info.bounds.hi)
151+
if (errors2 eq errors) errors2
152+
else errors1
153+
}
154+
else errors1
155+
case tp: ClassInfo =>
156+
(apply(errors, tp.prefix) /: tp.typeRef.parentsWithArgs)(apply)
157+
case _ =>
158+
foldOver(errors, tp)
159+
}
160+
}
161+
if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
162+
val errors = notPrivate(Nil, sym.info)
163+
errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
164+
}
165+
}
132166

133167
private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
134168
val qual = tree.qualifier
@@ -172,10 +206,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
172206
}
173207
finally parentNews = saved
174208
case tree: DefDef =>
175-
transformAnnots(tree)
209+
transformMemberDef(tree)
176210
superAcc.wrapDefDef(tree)(super.transform(tree).asInstanceOf[DefDef])
177211
case tree: TypeDef =>
178-
transformAnnots(tree)
212+
transformMemberDef(tree)
179213
val sym = tree.symbol
180214
val tree1 =
181215
if (sym.isClass) tree
@@ -185,7 +219,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
185219
}
186220
super.transform(tree1)
187221
case tree: MemberDef =>
188-
transformAnnots(tree)
222+
transformMemberDef(tree)
189223
super.transform(tree)
190224
case tree: New if !inJavaAnnot && !parentNews.contains(tree) =>
191225
Checking.checkInstantiable(tree.tpe, tree.pos)

test/dotc/tests.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ class tests extends CompilerTest {
165165
@Test def neg_i803 = compileFile(negDir, "i803", xerrors = 2)
166166
@Test def neg_i866 = compileFile(negDir, "i866", xerrors = 2)
167167
@Test def neg_i974 = compileFile(negDir, "i974", xerrors = 2)
168+
@Test def neg_i997 = compileFile(negDir, "i997a", xerrors = 15)
169+
@Test def neg_i997a = compileFile(negDir, "i997a", xerrors = 2)
168170
@Test def neg_i1050 = compileFile(negDir, "i1050", List("-strict"), xerrors = 11)
169171
@Test def neg_i1050a = compileFile(negDir, "i1050a", xerrors = 2)
170172
@Test def neg_i1050c = compileFile(negDir, "i1050c", xerrors = 8)

tests/neg/i997.scala

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
class C {
2+
3+
private type T = E
4+
private val p: C = new C
5+
6+
def f1(x: T): Unit = () // error
7+
def f2(x: p.D): Unit = () // error
8+
9+
val v1: T = ??? // error
10+
val v2: p.D = ??? // error
11+
12+
type U1[X <: T] // error
13+
type U2 = T // error
14+
15+
private class E {
16+
def f1ok(x: T): Unit = () // ok
17+
def f2ok(x: p.D): Unit = () // ok
18+
19+
val v1ok: T = ??? // ok
20+
val v2ok: p.D = ??? // ok
21+
22+
type U1ok[X <: T] //ok
23+
type U2ok = T //ok
24+
}
25+
26+
class D extends E { // error
27+
def f1(x: T): Unit = () // error
28+
def f2(x: p.D): Unit = () // error
29+
30+
val v1: T = ??? // error
31+
val v2: p.D = ??? // error
32+
33+
type U1[X <: T] // error
34+
type U2 = T // error
35+
}
36+
37+
class F(x: T) // error
38+
39+
class G private (x: T) // ok
40+
41+
private trait U
42+
43+
class H extends U // error
44+
45+
}

0 commit comments

Comments
 (0)