Skip to content

Fix macros with array parameters #4567

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

Merged
merged 2 commits into from
May 23, 2018
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
10 changes: 5 additions & 5 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,7 @@ class Definitions {

// private val unboxedTypeRef = mutable.Map[TypeName, TypeRef]()
// private val javaTypeToValueTypeRef = mutable.Map[Class[_], TypeRef]()
private val valueTypeNamesToJavaType = mutable.Map[TypeName, Class[_]]()
// private val valueTypeNamesToJavaType = mutable.Map[TypeName, Class[_]]()

private def valueTypeRef(name: String, boxed: TypeRef, jtype: Class[_], enc: Int, tag: Name): TypeRef = {
val vcls = ctx.requiredClassRef(name)
Expand All @@ -1146,7 +1146,7 @@ class Definitions {
typeTags(vcls.name) = tag
// unboxedTypeRef(boxed.name) = vcls
// javaTypeToValueTypeRef(jtype) = vcls
valueTypeNamesToJavaType(vcls.name) = jtype
// valueTypeNamesToJavaType(vcls.name) = jtype
vcls
}

Expand All @@ -1156,9 +1156,9 @@ class Definitions {
/** The JVM tag for `tp` if it's a primitive, `java.lang.Object` otherwise. */
def typeTag(tp: Type)(implicit ctx: Context): Name = typeTags(scalaClassName(tp))

/** The `Class[_]` of a primitive value type name */
def valueTypeNameToJavaType(name: TypeName)(implicit ctx: Context): Option[Class[_]] =
valueTypeNamesToJavaType.get(if (name.firstPart eq nme.scala_) name.lastPart.toTypeName else name)
// /** The `Class[_]` of a primitive value type name */
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess this should remain commented-out and not removed, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, in case we need it for something else again. It was really useful the first time.

// def valueTypeNameToJavaType(name: TypeName)(implicit ctx: Context): Option[Class[_]] =
// valueTypeNamesToJavaType.get(if (name.firstPart eq nme.scala_) name.lastPart.toTypeName else name)

type PrimitiveClassEnc = Int

Expand Down
50 changes: 44 additions & 6 deletions compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package transform

import java.io.{PrintWriter, StringWriter}
import java.lang.reflect.Method
import java.net.URLClassLoader

import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts._
Expand All @@ -14,6 +13,7 @@ import dotty.tools.dotc.core.Names.Name
import dotty.tools.dotc.core.quoted._
import dotty.tools.dotc.core.Types._
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.TypeErasure

import scala.util.control.NonFatal
import dotty.tools.dotc.util.Positions.Position
Expand Down Expand Up @@ -170,11 +170,49 @@ object Splicer {

/** List of classes of the parameters of the signature of `sym` */
private def paramsSig(sym: Symbol): List[Class[_]] = {
sym.signature.paramsSig.map { param =>
defn.valueTypeNameToJavaType(param) match {
case Some(clazz) => clazz
case None => classLoader.loadClass(param.toString)
}
TypeErasure.erasure(sym.info) match {
case meth: MethodType =>
meth.paramInfos.map { param =>
def arrayDepth(tpe: Type, depth: Int): (Type, Int) = tpe match {
case JavaArrayType(elemType) => arrayDepth(elemType, depth + 1)
case _ => (tpe, depth)
}
def javaArraySig(tpe: Type): String = {
val (elemType, depth) = arrayDepth(tpe, 0)
val sym = elemType.classSymbol
val suffix =
if (sym == defn.BooleanClass) "Z"
else if (sym == defn.ByteClass) "B"
else if (sym == defn.ShortClass) "S"
else if (sym == defn.IntClass) "I"
else if (sym == defn.LongClass) "J"
else if (sym == defn.FloatClass) "F"
else if (sym == defn.DoubleClass) "D"
else if (sym == defn.CharClass) "C"
else "L" + javaSig(elemType) + ";"
("[" * depth) + suffix
}
def javaSig(tpe: Type): String = tpe match {
case tpe: JavaArrayType => javaArraySig(tpe)
case _ =>
// Take the flatten name of the class and the full package name
val pack = tpe.classSymbol.topLevelClass.owner
val packageName = if (pack == defn.EmptyPackageClass) "" else pack.fullName + "."
packageName + tpe.classSymbol.fullNameSeparated(FlatName).toString
}

val sym = param.classSymbol
if (sym == defn.BooleanClass) classOf[Boolean]
else if (sym == defn.ByteClass) classOf[Byte]
else if (sym == defn.CharClass) classOf[Char]
else if (sym == defn.ShortClass) classOf[Short]
else if (sym == defn.IntClass) classOf[Int]
else if (sym == defn.LongClass) classOf[Long]
else if (sym == defn.FloatClass) classOf[Float]
else if (sym == defn.DoubleClass) classOf[Double]
else java.lang.Class.forName(javaSig(param), false, classLoader)
}
case _ => Nil
}
}

Expand Down
34 changes: 34 additions & 0 deletions tests/pos/macro-with-array/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

object Macro {

inline def foo0(i: Int): Unit = ~{ '() }
inline def foo1(arr: Array[Boolean]): Unit = ~{ '() }
inline def foo2(arr: Array[Byte]): Unit = ~{ '() }
inline def foo3(arr: Array[Short]): Unit = ~{ '() }
inline def foo4(arr: Array[Int]): Unit = ~{ '() }
inline def foo5(arr: Array[Long]): Unit = ~{ '() }
inline def foo6(arr: Array[Float]): Unit = ~{ '() }
inline def foo7(arr: Array[Double]): Unit = ~{ '() }
inline def foo8(arr: Array[Char]): Unit = ~{ '() }
inline def foo9(arr: Array[Object]): Unit = ~{ '() }
inline def foo10(arr: Array[String]): Unit = ~{ '() }
inline def foo11[T](arr: Array[T]): Unit = ~{ '() }
inline def foo12(arr: Array[Array[Int]]): Unit = ~{ '() }
inline def foo13(arr: Array[Array[String]]): Unit = ~{ '() }
inline def foo14(arr: Array[Array[Array[Int]]]): Unit = ~{ '() }
inline def foo15(arr: Array[Any]): Unit = ~{ '() }
inline def foo16(arr: Array[AnyVal]): Unit = ~{ '() }
inline def foo17(arr: Array[AnyRef]): Unit = ~{ '() }
inline def foo18(arr: Array[Foo]): Unit = ~{ '() }
inline def foo19(arr: Array[Macro.type]): Unit = ~{ '() }
inline def foo20(arr: Array[Bar]): Unit = ~{ '() }
inline def foo21(arr: Array[Baz.type]): Unit = ~{ '() }
inline def foo22(arr: Array[Foo#A]): Unit = ~{ '() }

class Bar
object Baz
}

class Foo {
class A
}
25 changes: 25 additions & 0 deletions tests/pos/macro-with-array/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
object PowerInlined1 {
Macro.foo0(2)
Macro.foo1(Array.empty)
Macro.foo2(Array.empty)
Macro.foo3(Array.empty)
Macro.foo4(Array.empty)
Macro.foo5(Array.empty)
Macro.foo6(Array.empty)
Macro.foo7(Array.empty)
Macro.foo8(Array.empty)
Macro.foo9(Array.empty)
Macro.foo10(Array.empty)
Macro.foo11[String](Array.empty)
Macro.foo12(Array.empty)
Macro.foo13(Array.empty)
Macro.foo14(Array.empty)
Macro.foo15(Array.empty)
Macro.foo16(Array.empty)
Macro.foo17(Array.empty)
Macro.foo18(Array.empty)
Macro.foo19(Array.empty)
Macro.foo20(Array.empty)
Macro.foo21(Array.empty)
Macro.foo22(Array.empty)
}