Skip to content

Commit afb083a

Browse files
authored
Merge pull request #512 from scala/backport-lts-3.3-23515
Backport "Support cleanup actions in class completers" to 3.3 LTS
2 parents 3118ed8 + d796579 commit afb083a

File tree

5 files changed

+43
-3
lines changed

5 files changed

+43
-3
lines changed

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,25 @@ import TypeApplications.EtaExpansion
99
/** Operations that are shared between Namer and TreeUnpickler */
1010
object NamerOps:
1111

12+
/** A completer supporting cleanup actions.
13+
* Needed to break the loop between completion of class and companion object.
14+
* If we try to complete the class first, and completion needs the companion
15+
* object (for instance for processing an import) then the companion object
16+
* completion would consult the companion class info for constructor that
17+
* need a constructor proxy in the object. This can lead to a cyclic reference.
18+
* We break the cycle by delaying adding constructor proxies to be a cleanuo
19+
* action instead.
20+
*/
21+
trait CompleterWithCleanup extends LazyType:
22+
private var cleanupActions: List[() => Unit] = Nil
23+
def addCleanupAction(op: () => Unit): Unit =
24+
cleanupActions = op :: cleanupActions
25+
def cleanup(): Unit =
26+
if cleanupActions.nonEmpty then
27+
cleanupActions.reverse.foreach(_())
28+
cleanupActions = Nil
29+
end CompleterWithCleanup
30+
1231
/** The type of the constructed instance is returned
1332
*
1433
* @param ctor the constructor
@@ -118,8 +137,14 @@ object NamerOps:
118137
ApplyProxyCompleter(constr),
119138
cls.privateWithin,
120139
constr.coord)
121-
for dcl <- cls.info.decls do
140+
def doAdd() = for dcl <- cls.info.decls do
122141
if dcl.isConstructor then scope.enter(proxy(dcl))
142+
cls.infoOrCompleter match
143+
case completer: CompleterWithCleanup if cls.is(Touched) =>
144+
// Taking the info would lead to a cyclic reference here - delay instead until cleanup of `cls`
145+
completer.addCleanupAction(doAdd)
146+
case _ =>
147+
doAdd()
123148
scope
124149
end addConstructorApplies
125150

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ class TreeUnpickler(reader: TastyReader,
127127
}
128128
}
129129

130-
class Completer(reader: TastyReader)(using @constructorOnly _ctx: Context) extends LazyType {
130+
class Completer(reader: TastyReader)(using @constructorOnly _ctx: Context)
131+
extends LazyType, CompleterWithCleanup {
131132
import reader.*
132133
val owner = ctx.owner
133134
val mode = ctx.mode
@@ -147,6 +148,8 @@ class TreeUnpickler(reader: TastyReader,
147148
case ex: CyclicReference => throw ex
148149
case ex: AssertionError => fail(ex)
149150
case ex: Exception => fail(ex)
151+
finally
152+
cleanup()
150153
}
151154

152155
class TreeReader(val reader: TastyReader) {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,8 @@ class Namer { typer: Typer =>
10891089
end typeSig
10901090
}
10911091

1092-
class ClassCompleter(cls: ClassSymbol, original: TypeDef)(ictx: Context) extends Completer(original)(ictx) {
1092+
class ClassCompleter(cls: ClassSymbol, original: TypeDef)(ictx: Context)
1093+
extends Completer(original)(ictx), CompleterWithCleanup {
10931094
withDecls(newScope(using ictx))
10941095

10951096
protected implicit val completerCtx: Context = localContext(cls)
@@ -1691,6 +1692,7 @@ class Namer { typer: Typer =>
16911692
processExports(using localCtx)
16921693
defn.patchStdLibClass(cls)
16931694
addConstructorProxies(cls)
1695+
cleanup()
16941696
}
16951697
}
16961698

tests/pos/i22436/atest.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Case1 {
2+
def myProps(transport: ProtocolTransport): Unit = ???
3+
}

tests/pos/i22436/defs.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object ProtocolTransport
2+
3+
import ProtocolTransport.*
4+
5+
@annotation.nowarn()
6+
class ProtocolTransport()
7+

0 commit comments

Comments
 (0)