Skip to content

Commit 6082984

Browse files
committed
Handle usage of proxy dependencies
1 parent dcc0e64 commit 6082984

File tree

3 files changed

+79
-13
lines changed

3 files changed

+79
-13
lines changed

compiler/src/dotty/tools/dotc/transform/init/Checker.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class Checker extends Phase {
4444
tree match {
4545
case tdef: TypeDef if tdef.isClassDef =>
4646
checkClassDef(tdef)
47+
cycleChecker.classesInCurrentRun += tdef.symbol
4748
traverseChildren(tree)
4849
case _ =>
4950
traverseChildren(tree)

compiler/src/dotty/tools/dotc/transform/init/Checking.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,22 @@ object Checking {
329329
state.dependencies += InstanceUsage(hot.classSymbol)(pot.source)
330330
Errors.empty
331331

332+
case MethodReturn(hot: Hot, sym) =>
333+
state.dependencies += ProxyUsage(hot.classSymbol, sym)(pot.source)
334+
Errors.empty
335+
336+
case MethodReturn(obj: Global, sym) =>
337+
state.dependencies += ProxyUsage(obj.moduleClass, sym)(pot.source)
338+
Errors.empty
339+
340+
case FieldReturn(hot: Hot, sym) =>
341+
state.dependencies += ProxyUsage(hot.classSymbol, sym)(pot.source)
342+
Errors.empty
343+
344+
case FieldReturn(obj: Global, sym) =>
345+
state.dependencies += ProxyUsage(obj.moduleClass, sym)(pot.source)
346+
Errors.empty
347+
332348
case Fun(pots, effs) =>
333349
val errs1 = state.test {
334350
effs.toList.flatMap(check(_))

compiler/src/dotty/tools/dotc/transform/init/CycleChecker.scala

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ case class StaticCall(cls: ClassSymbol, symbol: Symbol)(val source: Tree) extend
7070
def show(using Context): String = "StaticCall(" + cls.show + ", " + symbol.show + ")"
7171
}
7272

73+
/** A static method call result is used */
74+
case class ProxyUsage(cls: ClassSymbol, symbol: Symbol)(val source: Tree) extends Dependency {
75+
def show(using Context): String = "ProxyUsage(" + cls.show + ", " + symbol.show + ")"
76+
}
77+
7378
/** A class is used
7479
*
7580
* This is a coarse-grained abstraction
@@ -81,9 +86,10 @@ case class ClassUsage(symbol: Symbol)(val source: Tree) extends Dependency {
8186

8287
class CycleChecker(cache: Cache) {
8388
private val summaryCache = mutable.Map.empty[Symbol, List[Dependency]]
89+
private val proxyCache = mutable.Map.empty[Symbol, List[Dependency]]
8490

85-
private val classesInCurrentRun = mutable.Set.empty[Symbol]
86-
private val objectsInCurrentRun = mutable.Set.empty[Symbol]
91+
val classesInCurrentRun = mutable.Set.empty[Symbol]
92+
val objectsInCurrentRun = mutable.Set.empty[Symbol]
8793

8894
/** Checking state */
8995
case class State(visited: mutable.Set[Dependency], path: Vector[Symbol], trace: Vector[Dependency]) {
@@ -122,6 +128,7 @@ class CycleChecker(cache: Cache) {
122128
dep match
123129
case dep: InstanceUsage => checkInstanceUsage(dep)
124130
case dep: StaticCall => checkStaticCall(dep)
131+
case dep: ProxyUsage => checkProxyUsage(dep)
125132
case dep: ClassUsage => checkClassUsage(dep)
126133
}
127134
}
@@ -167,6 +174,15 @@ class CycleChecker(cache: Cache) {
167174
deps.flatMap(check(_))
168175
}
169176

177+
private def checkProxyUsage(dep: ProxyUsage)(using Context, State): List[Error] =
178+
if !classesInCurrentRun.contains(dep.cls) then
179+
Util.traceIndented("skip " + dep.cls.show + " which is not in current run ", init)
180+
Nil
181+
else {
182+
val deps = proxyDependencies(dep)
183+
deps.flatMap(check(_))
184+
}
185+
170186
private def checkClassUsage(dep: ClassUsage)(using Context, State): List[Error] =
171187
if !classesInCurrentRun.contains(dep.symbol) then
172188
Util.traceIndented("skip " + dep.symbol.show + " which is not in current run ", init)
@@ -184,7 +200,6 @@ class CycleChecker(cache: Cache) {
184200
summaryCache(constr) = deps
185201
val cls = constr.owner
186202

187-
classesInCurrentRun += cls
188203
if cls.is(Flags.Module) && cls.isStatic then
189204
objectsInCurrentRun += cls.sourceModule
190205

@@ -206,14 +221,44 @@ class CycleChecker(cache: Cache) {
206221
}
207222
}
208223

224+
private def proxyDependencies(dep: ProxyUsage)(using Context): List[Dependency] = trace("dependencies of " + dep.symbol.show, init, _.asInstanceOf[List[Dependency]].map(_.show).toString) {
225+
if (proxyCache.contains(dep.symbol)) summaryCache(dep.symbol)
226+
else trace("summary for " + dep.symbol.show) {
227+
val env = Env(ctx.withOwner(dep.cls), cache)
228+
val state = new Checking.State(
229+
visited = Set.empty,
230+
path = Vector.empty,
231+
thisClass = dep.cls,
232+
fieldsInited = mutable.Set.empty,
233+
parentsInited = mutable.Set.empty,
234+
safePromoted = mutable.Set(ThisRef()(dep.cls.defTree)),
235+
dependencies = mutable.Set.empty,
236+
env = env
237+
) {
238+
override def isFieldInitialized(field: Symbol): Boolean = true
239+
}
240+
241+
val pot = Hot(dep.cls)(dep.source)
242+
val target = Util.resolve(dep.cls, dep.symbol)
243+
val effs = pot.potentialsOf(target)(using env).promote(dep.source)
244+
245+
val errs = effs.flatMap(Checking.check(_)(using state))
246+
assert(errs.isEmpty, "unexpected errors: " + Errors.show(errs.toList))
247+
248+
val deps = state.dependencies.toList
249+
proxyCache(dep.symbol) = deps
250+
deps
251+
}
252+
}
253+
209254
def isStaticObjectRef(sym: Symbol)(using Context) =
210255
sym.isTerm && !sym.is(Flags.Package) && sym.is(Flags.Module) && sym.isStatic
211256

212257
private def analyzeClass(cls: ClassSymbol, excludeInit: Boolean)(using Context): List[Dependency] = {
213258
val cdef = cls.defTree.asInstanceOf[TypeDef]
214259
val tpl = cdef.rhs.asInstanceOf[Template]
215260

216-
var deps: List[Dependency] = Nil
261+
var deps = new mutable.ListBuffer[Dependency]
217262

218263
val traverser = new TreeTraverser {
219264
override def traverse(tree: Tree)(using Context): Unit =
@@ -222,7 +267,7 @@ class CycleChecker(cache: Cache) {
222267
if !excludeInit then
223268
parents.foreach(traverse(_))
224269
tree.body.foreach {
225-
case ddef: DefDef if ddef.symbol.isConstructor =>
270+
case ddef: DefDef if !ddef.symbol.isConstructor =>
226271
traverse(ddef)
227272
case vdef: ValDef if vdef.symbol.is(Flags.Lazy) =>
228273
traverse(vdef)
@@ -231,10 +276,10 @@ class CycleChecker(cache: Cache) {
231276
}
232277

233278
case tree: RefTree if tree.isTerm =>
234-
analyzeType(tree.tpe, tree, exclude = cls)
279+
deps ++= analyzeType(tree.tpe, tree, exclude = cls)
235280

236281
case tree: This =>
237-
analyzeType(tree.tpe, tree, exclude = cls)
282+
deps ++= analyzeType(tree.tpe, tree, exclude = cls)
238283

239284
case tree: ValOrDefDef =>
240285
traverseChildren(tree.rhs)
@@ -243,7 +288,7 @@ class CycleChecker(cache: Cache) {
243288
// don't go into nested classes
244289

245290
case tree: New =>
246-
deps = ClassUsage(tree.tpe.classSymbol)(tree) :: deps
291+
deps += ClassUsage(tree.tpe.classSymbol)(tree)
247292

248293
case _ =>
249294
traverseChildren(tree)
@@ -257,15 +302,15 @@ class CycleChecker(cache: Cache) {
257302
if excludeInit then InstanceUsage(tp.classSymbol)(tree)
258303
else ClassUsage(tp.classSymbol)(tree)
259304

260-
deps = dep :: deps
305+
deps += dep
261306
}
262307

263308
traverser.traverse(tpl)
264-
deps
309+
deps.toList
265310
}
266311

267-
private def analyzeType(tp: Type, source: Tree, exclude: Symbol)(using Context): Unit = tp match {
268-
case (_: ConstantType) | NoPrefix =>
312+
private def analyzeType(tp: Type, source: Tree, exclude: Symbol)(using Context): List[Dependency] = tp match {
313+
case (_: ConstantType) | NoPrefix => Nil
269314

270315
case tmref: TermRef if isStaticObjectRef(tmref.symbol) =>
271316
val obj = tmref.symbol
@@ -280,12 +325,15 @@ class CycleChecker(cache: Cache) {
280325
val cls = tref.symbol
281326
val obj = cls.sourceModule
282327
ObjectAccess(obj)(source) :: InstanceUsage(cls)(source) :: Nil
328+
else
329+
Nil
283330

284331
case SuperType(thisTp, _) =>
285332
analyzeType(thisTp, source, exclude)
286333

287334
case _: TypeRef | _: AppliedType =>
288335
// possible from parent list
336+
Nil
289337

290338
case _ =>
291339
throw new Exception("unexpected type: " + tp)
@@ -307,7 +355,8 @@ class CycleChecker(cache: Cache) {
307355
}
308356

309357
val pot = Hot(dep.cls)(dep.source)
310-
val effs = pot.effectsOf(dep.symbol)(using env)
358+
val target = Util.resolve(dep.cls, dep.symbol)
359+
val effs = pot.effectsOf(target)(using env)
311360

312361
val errs = effs.flatMap(Checking.check(_)(using state))
313362
assert(errs.isEmpty, "unexpected errors: " + Errors.show(errs.toList))

0 commit comments

Comments
 (0)