Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #413: Handle inner classes based on content, not names. #419

Merged
merged 2 commits into from
Dec 11, 2023

Conversation

sjrd
Copy link
Contributor

@sjrd sjrd commented Dec 7, 2023

Previously, we assumed that if there is a file Foo and a file Foo$Bar, that the latter must be an inner class (or companion) of Foo, and that it must therefore be ignored.

As #413 shows, and as the new JavaDefined$Evil test shows, this is not always valid.

The only true test of a class being top-level can only be found in its content, either through the Scala attribute or the InnerClasses attribute.

We completely rewrite Loaders. We now systematically try to load every file that is requested, except when we already know that it is a Java inner class. This means that we will read the contents of more files than before, but still each file at most once in the common case.

A file may be read multiple times if it is a Java non-top-level class that gets requested by its name as if it were a top-level class. The loading will fail but we have to keep the file in case it is loaded later on as an inner class.

When reading all the declarations of a package, we always try outer classes before potential inner classes so that no double reading happens.


The following TypeSuite test passes with this PR with the "org.scalaz" %% "scalaz-core" % "7.3.8" dependency:

  testWithContext("issue-413") {
    println(ctx.findTopLevelClass("scalaz.\\/"))
    println(ctx.findTopLevelClass("scalaz.\\/-"))
  }

Moreover, I re-tested locally the local test from PR #416.

@sjrd sjrd requested a review from adpi2 December 7, 2023 11:05
@sjrd sjrd force-pushed the fix-weird-toplevel-scala2-names branch from a4f9628 to c818a7f Compare December 7, 2023 11:14
@sjrd sjrd changed the title Fix #413: Rewrite Loaders to handle inner classes based on context, not names. Fix #413: Handle inner classes based on content, not names. Dec 7, 2023
true
else if doLoadClassFile(classData, loadedFiles) then true
else
// Oops, maybe we will need this one later; removing it from loadedFiles
Copy link
Member

Choose a reason for hiding this comment

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

Maybe you should explain in which situation we would need it again

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


if result == ClassKind.Java && innerClassesStream != null then
if containsSelfInnerClassDecl(structure.binaryName, innerClassesStream.nn) then ClassKind.JavaInnerOrArtifact
else ClassKind.Java
Copy link
Member

@adpi2 adpi2 Dec 11, 2023

Choose a reason for hiding this comment

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

Should we expect this else to happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is definitely expected. Top-level classes have InnerClasses data for their inner classes, and even for any other inner class of other classes that they happen to refer to.

Previously, we assumed that if there is a file `Foo` and a file
`Foo$Bar`, that the latter must be an inner class (or companion)
of `Foo`, and that it must therefore be ignored.

As scalacenter#413 shows, and as the new `JavaDefined$Evil` test shows, this
is not always valid.

The only true test of a class being top-level can only be found in
its content, either through the `Scala` attribute or the
`InnerClasses` attribute.

We completely rewrite `Loaders`. We now systematically try to load
every file that is requested, except when we *already* know that
it is a Java inner class. This means that we will read the contents
of more files than before, but still each file at most once in the
common case.

A file *may* be read multiple times if it is a Java non-top-level
class that gets requested by its name as if it were a top-level
class. The loading will fail but we have to keep the file in case
it is loaded later on as an inner class.

When reading *all* the declarations of a package, we always try
outer classes before potential inner classes so that no double
reading happens.
@sjrd sjrd force-pushed the fix-weird-toplevel-scala2-names branch from c818a7f to 648de54 Compare December 11, 2023 12:59
@sjrd sjrd merged commit 917d4d6 into scalacenter:main Dec 11, 2023
4 checks passed
@sjrd sjrd deleted the fix-weird-toplevel-scala2-names branch December 11, 2023 13:06
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