Skip to content

Commit 7fc5deb

Browse files
committed
Fix #6603: Make privateWithin force less
At this point, ModuleCompleters and SymbolLoaders are the only two kinds of completers which need to set privateWithin, this is now enforced by the setter (which is therefore renamed to `setPrivateWithin` to make it clearer that it doesn't just set a field) and taken advantage of by the getter to avoid forcing unless necessary. This is the last piece needed to finally fix #6603. Unfortunately, the cumulative changes to completions done so far have caused cyclic reference errors to pop up in new situations, including bootstrapping Dotty itself. This is fixed by the remaining commits in this PR.
1 parent 1e8860a commit 7fc5deb

File tree

10 files changed

+56
-27
lines changed

10 files changed

+56
-27
lines changed

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,31 @@ object SymDenotations {
277277

278278
/** The privateWithin boundary, NoSymbol if no boundary is given.
279279
*/
280-
final def privateWithin(implicit ctx: Context): Symbol = { ensureCompleted(); myPrivateWithin }
280+
@tailrec
281+
final def privateWithin(implicit ctx: Context): Symbol = myInfo match {
282+
case myInfo: ModuleCompleter =>
283+
// Instead of completing the ModuleCompleter, we can get `privateWithin`
284+
// directly from the module class, which might require less completions.
285+
myInfo.moduleClass.privateWithin
286+
case _: SymbolLoader =>
287+
// Completing a SymbolLoader might call `setPrivateWithin()`
288+
completeOnce()
289+
privateWithin
290+
case _ =>
291+
// Otherwise, no completion is necessary, see the preconditions of `markAbsent()`.
292+
myPrivateWithin
293+
}
281294

282-
/** Set privateWithin. */
283-
protected[dotc] final def privateWithin_=(sym: Symbol): Unit =
284-
myPrivateWithin = sym
295+
/** Set privateWithin, prefer setting it at symbol-creation time instead if
296+
* possible.
297+
* @pre `isCompleting` is false, or this is a ModuleCompleter or SymbolLoader
298+
*/
299+
protected[dotc] final def setPrivateWithin(pw: Symbol)(implicit ctx: Context): Unit = {
300+
if (isCompleting)
301+
assert(myInfo.isInstanceOf[ModuleCompleter | SymbolLoader],
302+
s"Illegal call to `setPrivateWithin($pw)` while completing $this using completer $myInfo")
303+
myPrivateWithin = pw
304+
}
285305

286306
/** The annotations of this denotation */
287307
final def annotations(implicit ctx: Context): List[Annotation] = {
@@ -2227,7 +2247,7 @@ object SymDenotations {
22272247
// is to have the module class completer set the annotations of both the
22282248
// class and the module.
22292249
denot.info = moduleClass.typeRef
2230-
denot.privateWithin = from.privateWithin
2250+
denot.setPrivateWithin(from.privateWithin)
22312251
}
22322252
}
22332253

@@ -2241,7 +2261,7 @@ object SymDenotations {
22412261
case _ =>
22422262
ErrorType(errMsg)
22432263
}
2244-
denot.privateWithin = NoSymbol
2264+
denot.setPrivateWithin(NoSymbol)
22452265
}
22462266

22472267
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ class ClassfileParser(
159159

160160
val privateWithin = getPrivateWithin(jflags)
161161

162-
classRoot.privateWithin = privateWithin
163-
moduleRoot.privateWithin = privateWithin
164-
moduleRoot.sourceModule.privateWithin = privateWithin
162+
classRoot.setPrivateWithin(privateWithin)
163+
moduleRoot.setPrivateWithin(privateWithin)
164+
moduleRoot.sourceModule.setPrivateWithin(privateWithin)
165165

166166
for (i <- 0 until in.nextChar) parseMember(method = false)
167167
for (i <- 0 until in.nextChar) parseMember(method = true)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ class TreeUnpickler(reader: TastyReader,
546546
rootd.info = adjustIfModule(
547547
new Completer(subReader(start, end)) with SymbolLoaders.SecondCompleter)
548548
rootd.flags = flags &~ Touched // allow one more completion
549-
rootd.privateWithin = privateWithin
549+
rootd.setPrivateWithin(privateWithin)
550550
seenRoots += rootd.symbol
551551
rootd.symbol
552552
case _ =>

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
479479
if (owner == defn.ScalaPackageClass && ((name eq tpnme.Serializable) || (name eq tpnme.Product)))
480480
denot.setFlag(NoInits)
481481

482-
denot.privateWithin = privateWithin
482+
denot.setPrivateWithin(privateWithin)
483483
denot.info = completer
484484
denot.symbol
485485
}

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ class Namer { typer: Typer =>
332332
if (prev.exists) {
333333
prev.flags = flags1
334334
prev.info = infoFn(prev.asInstanceOf[S])
335-
prev.privateWithin = privateWithin
335+
prev.setPrivateWithin(privateWithin)
336336
prev
337337
}
338338
else symFn(flags1, infoFn, privateWithin)

compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
5757
),
5858
withCompilerOptions
5959
),
60+
compileList(
61+
"testIssue6603",
62+
List(
63+
"compiler/src/dotty/tools/dotc/ast/Desugar.scala",
64+
"compiler/src/dotty/tools/dotc/ast/Trees.scala",
65+
"compiler/src/dotty/tools/dotc/core/Types.scala"
66+
),
67+
withCompilerOptions
68+
),
6069
).checkCompile()
6170
}
6271

tests/neg/exports.check

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@
4141
| ^^^
4242
| no eligible member foo at this.foo
4343
| this.foo.foo cannot be exported because it is already a member of class Foo
44-
-- [E046] Cyclic Error: tests/neg/exports.scala:45:11 ------------------------------------------------------------------
45-
45 | val bar: Bar = new Bar // error: cyclic reference
46-
| ^
47-
| Cyclic reference involving value bar
48-
49-
longer explanation available when compiling with `-explain`
44+
-- [E120] Duplicate Symbol Error: tests/neg/exports.scala:46:13 --------------------------------------------------------
45+
46 | export bar._ // error: double definition
46+
| ^
47+
| Double definition:
48+
| val bar: Bar in class Baz at line 45 and
49+
| final def bar: => => Bar(Baz.this.bar.baz.bar)(Baz.this.bar.bar) in class Baz at line 46

tests/neg/exports.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ class Foo {
4242
}
4343

4444
class Baz {
45-
val bar: Bar = new Bar // error: cyclic reference
46-
export bar._
45+
val bar: Bar = new Bar
46+
export bar._ // error: double definition
4747
}
4848
class Bar {
4949
val baz: Baz = new Baz

tests/neg/i4368.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,13 @@ object Test9 {
149149
object i4369 {
150150
trait X { self =>
151151
type R <: Z
152-
type Z >: X { type R = self.R; type Z = self.R }
152+
type Z >: X { type R = self.R; type Z = self.R } // error: cyclic // error: cyclic // error: cyclic
153153
}
154-
class Foo extends X { type R = Foo; type Z = Foo } // error: too deep
154+
class Foo extends X { type R = Foo; type Z = Foo }
155155
}
156156
object i4370 {
157-
class Foo { type R = A } // error: cyclic
158-
type A = List[Foo#R]
157+
class Foo { type R = A }
158+
type A = List[Foo#R] // error: cyclic
159159
}
160160
object i4371 {
161161
class Foo { type A = Boo#B } // error: cyclic
@@ -170,4 +170,4 @@ object i318 {
170170
val y: Y = ???
171171
val a: y.A = ??? // error: too deep
172172
val b: y.B = a // error: too deep
173-
}
173+
}

tests/neg/i4370.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
object App {
2-
class Foo { type R = A } // error
3-
type A = List[Foo#R]
2+
class Foo { type R = A }
3+
type A = List[Foo#R] // error
44
}

0 commit comments

Comments
 (0)