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

Avoid name check when loading repl products #10253

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/repl/scala/tools/nsc/interpreter/IMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,23 @@ class IMain(val settings: Settings, parentClassLoaderOverride: Option[ClassLoade
override def translateEnclosingClass(n: String): Option[String] = symbolOfTerm(n).enclClass.toOption map flatPath

/** If unable to find a resource foo.class, try taking foo as a symbol in scope
* and use its java class name as a resource to load.
*
* \$intp.classLoader classBytes "Bippy" or \$intp.classLoader getResource "Bippy.class" just work.
*/
* and use its java class name as a resource to load.
*
* \$intp.classLoader classBytes "Bippy" or \$intp.classLoader getResource "Bippy.class" just work.
*/
private class TranslatingClassLoader(parent: ClassLoader) extends AbstractFileClassLoader(replOutput.dir, parent) {
override protected def findAbstractFile(name: String): AbstractFile = super.findAbstractFile(name) match {
case null if _initializeComplete => translateSimpleResource(name).map(super.findAbstractFile).orNull
case file => file
}
// if the name was mapped by findAbstractFile, supply null name to avoid name check in defineClass
override protected def findClass(name: String): Class[_] = {
Copy link
Member

Choose a reason for hiding this comment

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

do super.findClass first and use the new code below only as a fallback?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered doing something fancy, but the class loader API is so complex already, plus ScalaClassLoader and AbstractFileClassLoader, and also throws, that I wasn't "up" for it.

I could imagine a boolean member called verifyDefiningName for AbstractFileClassLoader to consult.

Copy link
Member

Choose a reason for hiding this comment

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

A complex mix of complex ingredients, so I'm just generally worried about breaking stuff... I just saw now the AbstractFileClassLoader.findClass code that's overridden. In that light, LGTM.

val bytes = classBytes(name)
if (bytes.length == 0)
throw new ClassNotFoundException(name)
else
defineClass(/*name=*/null, bytes, 0, bytes.length, protectionDomain)
}
}
private def makeClassLoader(): AbstractFileClassLoader =
new TranslatingClassLoader({
Expand Down
11 changes: 11 additions & 0 deletions test/files/run/t12705.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

scala> case class Person(name: String)
class Person

scala> $intp.classLoader.getResource("Person.class")
val res0: java.net.URL = memory:(memory)/Person.class

scala> $intp.classLoader.loadClass("Person")
val res1: Class[_] = class Person

scala> :quit
20 changes: 20 additions & 0 deletions test/files/run/t12705.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

import scala.tools.partest.ReplTest

object Test extends ReplTest {
def code =
"""|case class Person(name: String)
|$intp.classLoader.getResource("Person.class")
|$intp.classLoader.loadClass("Person")""".stripMargin
//|classOf[Person].getClassLoader.loadClass("Person")""".stripMargin
}

/*
java.lang.NoClassDefFoundError: Person (wrong name: Person)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1013)
at scala.reflect.internal.util.AbstractFileClassLoader.findClass(AbstractFileClassLoader.scala:77)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 76 elided
*/