From c9b807f3f957ebf796ae3657aded8841d1d6255e Mon Sep 17 00:00:00 2001 From: Antonio Salazar Cardozo Date: Mon, 23 Sep 2019 13:03:46 -0400 Subject: [PATCH] Add workaround for scalap 2.13 parameter behavior In Scala 2.13, scalap started no longer reporting method parameters under `MethodSymbol.children`. This broke the ability of lift-json to compare method parameter types for class constructors, and therefore broke the ability to find constructors that matched an extracting JSON structure. This commit introduces a separate method, `paramSymbolsFor`, to manage method parameter lookup explicitly, without referencing `MethodSymbol.children`. Relevant calls are replaced with calls to `paramSymbolsFor`. --- .../scala/net/liftweb/json/ScalaSig.scala | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/core/json/src/main/scala/net/liftweb/json/ScalaSig.scala b/core/json/src/main/scala/net/liftweb/json/ScalaSig.scala index 0208625dd9..4b640e17e8 100644 --- a/core/json/src/main/scala/net/liftweb/json/ScalaSig.scala +++ b/core/json/src/main/scala/net/liftweb/json/ScalaSig.scala @@ -19,7 +19,27 @@ package json import scala.tools.scalap.scalax.rules.scalasig._ +import java.util.concurrent.ConcurrentHashMap + +import scala.collection.JavaConverters._ +import scala.collection.concurrent.{Map=>ConcurrentScalaMap} + private[json] object ScalaSigReader { + // Originally, we used `method.children` and expected all children of a + // MethodSymbol to be parameters. In Scala 2.13, a change was made that never + // returns parameters in `children`. To get around this, we look up parameter + // symbols separately here. + // + // This works across Scala versions, so we don't scope it to 2.13 + // specifically. See Scala bug 11747, currently at + // https://github.com/scala/bug/issues/11747 , for more. + private def paramSymbolsFor(method: MethodSymbol): Seq[Symbol] = { + method + .applyScalaSigRule(ScalaSigParsers.symbols) + .filter(symbol => symbol.parent == Some(method) && symbol.isParam) + } + + def readConstructor(argName: String, clazz: Class[_], typeArgIndex: Int, argNames: List[String]): Class[_] = { val cl = findClass(clazz) val cstr = findConstructor(cl, argNames).getOrElse(Meta.fail("Can't find constructor for " + clazz)) @@ -54,7 +74,7 @@ private[json] object ScalaSigReader { private def findConstructor(c: ClassSymbol, argNames: List[String]): Option[MethodSymbol] = { val ms = c.children collect { case m: MethodSymbol if m.name == "" => m } - ms.find(m => m.children.map(_.name) == argNames) + ms.find(m => paramSymbolsFor(m).map(_.name) == argNames) } private def findField(c: ClassSymbol, name: String): Option[MethodSymbol] = @@ -73,7 +93,7 @@ private[json] object ScalaSigReader { } case x => Meta.fail("Unexpected type info " + x) } - toClass(findPrimitive(s.children(argIdx).asInstanceOf[SymbolInfoSymbol].infoType)) + toClass(findPrimitive(paramSymbolsFor(s)(argIdx).asInstanceOf[SymbolInfoSymbol].infoType)) } private def findArgTypeForField(s: MethodSymbol, typeArgIdx: Int): Class[_] = {