Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

gzm0
Copy link
Contributor

@gzm0 gzm0 commented Sep 9, 2025

The key insight here is that we need an intermediate loading state in which the infos are loaded but the class' parent chain is not linked yet.

We must wait for all the infos of an inheritance cycle to be loaded to detect the cycle reliably. However, we must not wait for the linking to be completed, otherwise we end up with a future-cycle.

The key insight here is that we need an intermediate loading state
in which the infos are loaded but the class' parent chain is not
linked yet.

We must wait for all the infos of an inheritance cycle to be loaded to
detect the cycle reliably. However, we must not wait for the linking
to be completed, otherwise we end up with a future-cycle.
@@ -71,6 +71,14 @@ class AnalyzerTest {
}
}

/* Note about inheritance cycles:
* We do not have a guarantee about the starting point of the cycle that is
* detected. In fact, we don't even have a guarantee that only cycle is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* detected. In fact, we don't even have a guarantee that only cycle is
* detected. In fact, we don't even have a guarantee that only one cycle is

Comment on lines +489 to +490
def checkParentChain(): Future[Option[List[ClassName]]] =
checkParentChain(Set()).map(_.map(_.cycle))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method deserves a comment about its result. What does the result mean?

@@ -495,7 +535,7 @@ private class AnalyzerRun(config: CommonPhaseConfig, initial: Boolean,
unvalidatedInterfaces: List[ClassInfo],
val syntheticKind: Option[SyntheticClassKind],
val nonExistent: Boolean)
extends Analysis.ClassInfo with ClassLoadingState with LoadingResult with ModuleUnit {
extends Analysis.ClassInfo with LoadingResult with InfoLoadedState with ModuleUnit {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems redundant. IIUC LoadingResult extends InfoLoadedState, so:

Suggested change
extends Analysis.ClassInfo with LoadingResult with InfoLoadedState with ModuleUnit {
extends Analysis.ClassInfo with LoadingResult with ModuleUnit {

?

Comment on lines +380 to 384
var loading: LoadingInfos = null
val state = _classInfos.getOrElseUpdate(className, {
loading = new LoadingClass(className)
loading = new LoadingInfos
loading
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this, I wonder if we need to mark loading as @volatile, to ensure safe publication of the assignment across threads? Or perhaps an AtomicReference?

Comment on lines +414 to +415
val parentsFuture = Future.traverse(parentNames) {
ensureLoading(_, syntheticKind = None) match {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider naming the lambda argument here; it's a bit non-obvious:

Suggested change
val parentsFuture = Future.traverse(parentNames) {
ensureLoading(_, syntheticKind = None) match {
val parentsFuture = Future.traverse(parentNames) { parentName =>
ensureLoading(parentName, syntheticKind = None) match {

Comment on lines 461 to +463
private sealed trait ClassLoadingState
private sealed trait InfoLoadedState extends ClassLoadingState
private sealed trait LoadingResult extends InfoLoadedState
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps consider adding methods on these types to resolve them to the possible tiers. IIUC the tiers we need are

  private sealed trait ClassLoadingState {
    def resolveToInfoLoadedState: Future[InfoLoadedState]
    def resolveToLoadingResult: Future[LoadingResult]
  }

This would lighten the notation inside the traverse calls. More importantly, IMO it would ease understanding that all cases are really covered.

(They could be implemented either in an OO fashion or with pattern matching.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants