Skip to content

Commit

Permalink
Find trait local static forwarder
Browse files Browse the repository at this point in the history
  • Loading branch information
adpi2 committed Dec 20, 2023
1 parent e3288d2 commit 4785cc4
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ object Patterns:
def unapply(method: binary.Method): Option[String] =
"""(.*)\$lzyINIT\d+""".r.unapplySeq(NameTransformer.decode(method.name)).map(xs => xs(0).stripSuffix("$"))

object TraitLocalStaticForwarder:
def unapply(method: binary.Method): Option[Seq[String]] =
if method.isTraitStaticForwarder then method.extractFromDecodedNames("(.+)\\$\\d+\\$".r)(_(0))
else None

object TraitStaticForwarder:
def unapply(method: binary.Method): Option[Seq[String]] =
if method.isTraitStaticForwarder then Some(method.unexpandedDecodedNames.map(_.stripSuffix("$")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import tastyquery.SourceLanguage
import tastyquery.Traversers.TreeTraverser
import scala.collection.mutable.Buffer
import ch.epfl.scala.debugadapter.internal.binary.Instruction
import ch.epfl.scala.debugadapter.internal.stacktrace.Patterns.TraitStaticForwarder

class Scala3Unpickler(
classpaths: Array[Path],
Expand Down Expand Up @@ -113,16 +114,8 @@ class Scala3Unpickler(
.orFind { case Patterns.ByNameArgProxy() => findByNameArgsProxy(binaryClass, method) }
.orFind { case Patterns.SuperArg() => requiresBinaryClass(findSuperArgs(_, method)) }
.orFind { case Patterns.LiftedTree() => findLiftedTry(binaryClass, method) }
.orFind { case Patterns.LocalMethod(names) =>
val localMethods = collectLocalMethods(binaryClass, method)(inlined => {
case term if names.contains(term.nameStr) && matchSignature(method, term, checkTypeErasure = !inlined) =>
BinaryMethod(binaryClass, term)
})
val anonTraitParamGetters =
if names.contains("x") then requiresBinaryClass(findInstanceMethods(_, method))
else Seq.empty
localMethods ++ anonTraitParamGetters
}
.orFind { case Patterns.TraitLocalStaticForwarder(names) => findTraitLocalStaticForwarder(method) }
.orFind { case Patterns.LocalMethod(names) => findLocalMethods(binaryClass, method, names) }
.orFind { case Patterns.LazyInit(name) => requiresBinaryClass(findLazyInit(_, name)) }
.orFind { case Patterns.Outer(_) => Seq(findOuter(binaryClass)) }
.orFind { case Patterns.TraitInitializer() => requiresBinaryClass(findTraitInitializer(_, method)) }
Expand Down Expand Up @@ -426,6 +419,30 @@ class Scala3Unpickler(
// figure out and split findMethodsFromTraits in 2
fromClass.orIfEmpty(findBridgesAndMixinForwarders(binaryClass, method))

private def findTraitLocalStaticForwarder(method: binary.Method): Seq[BinaryMethodSymbol] =
method.instructions
.collect {
case Instruction.Method(_, owner, name, descriptor, _) if method.declaringClass.name == owner =>
method.declaringClass.method(name, descriptor)
}
.flatten
.singleOpt
.toSeq
.map { binaryTarget =>
val target = findMethod(binaryTarget)
BinaryTraitStaticForwarder(target)
}

private def findLocalMethods(
binaryClass: BinaryClassSymbol,
method: binary.Method,
names: Seq[String]
): Seq[BinaryMethodSymbol] =
collectLocalMethods(binaryClass, method)(inlined => {
case term if names.contains(term.nameStr) && matchSignature(method, term, checkTypeErasure = !inlined) =>
BinaryMethod(binaryClass, term)
})

private def findLazyInit(binaryClass: BinaryClass, name: String): Seq[BinaryMethodSymbol] =
val matcher: PartialFunction[Symbol, TermSymbol] =
case sym: TermSymbol if sym.isModuleOrLazyVal && sym.nameStr == name => sym
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,22 @@ class Scala3UnpicklerStats extends munit.FunSuite:

for
cls <- loadClasses(jars, "scala3-compiler_3-3.3.0", binaryClassLoader)
// if cls.name == "dotty.tools.dotc.reporting.MissingImplicitArgument"
// if cls.name == "dotty.tools.dotc.core.Types$TermLambda"
clsSym <- cls match
case Patterns.LocalClass(_, _, _) => unpickler.tryFind(cls, localClassCounter)
case Patterns.AnonClass(_, _) => unpickler.tryFind(cls, anonClassCounter)
case Patterns.InnerClass(_) => unpickler.tryFind(cls, innerClassCounter)
case _ => unpickler.tryFind(cls, topLevelClassCounter)
method <- cls.declaredMethods
// if method.name == "dotty$tools$dotc$reporting$ShowMatchTrace$$super$msgPostscript"
// if method.name == "dotty$tools$dotc$core$Types$TermLambda$$_$compute$1$"
do
method match
case Patterns.AnonFun(_) => unpickler.tryFind(method, anonFunCounter)
case Patterns.AdaptedAnonFun(_) => unpickler.tryFind(method, adaptedAnonFunCounter)
case Patterns.LocalLazyInit(_) => unpickler.tryFind(method, localLazyInitCounter)
case Patterns.LocalMethod(_) => unpickler.tryFind(method, localMethodCounter)
case _ => unpickler.tryFind(method, methodCounter)
localMethodCounter.printNotFound()
methodCounter.printNotFound()
localClassCounter.printReport()
anonClassCounter.printReport()
Expand All @@ -84,7 +85,7 @@ class Scala3UnpicklerStats extends munit.FunSuite:
checkCounter(anonFunCounter, 6649, expectedAmbiguous = 331, expectedNotFound = 5)
checkCounter(adaptedAnonFunCounter, 288, expectedAmbiguous = 83)
checkCounter(localLazyInitCounter, 108)
checkCounter(methodCounter, 57743, expectedAmbiguous = 128, expectedNotFound = 1)
checkCounter(methodCounter, 57744, expectedAmbiguous = 128)

def checkCounter(
counter: Counter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1680,6 +1680,28 @@ abstract class Scala3UnpicklerTests(val scalaVersion: ScalaVersion) extends FunS
)
}

test("trait local static forwarder") {
val source =
"""|package example
|
|trait A:
| val x: String
| private def m1 =
| class B:
| def m2 = m3
| def m3: String = x + x
| ()
|""".stripMargin
val debuggee = TestingDebuggee.mainClass(source, "example", scalaVersion)
debuggee.assertFormat(
"example.A",
"java.lang.String example$A$$_$m3$1$(example.A $this)",
"A.m1.m3.<static forwarder>: String",
skip = true,
loadExtraInfo = true
)
}

extension (debuggee: TestingDebuggee)
private def loader(loadExtraInfo: Boolean): JavaReflectLoader =
new JavaReflectLoader(debuggee.classLoader, loadExtraInfo = loadExtraInfo)
Expand Down

0 comments on commit 4785cc4

Please sign in to comment.