diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index 6f5c3c7ac5e2..fc76e70178cc 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -185,23 +185,20 @@ trait Dynamic { val vargss = termArgss(tree) def handleRepeated(base: untpd.Tree, possiblyCurried: List[List[Tree]], isReflectSelectable: Boolean) = { - val handled = possiblyCurried.map { args => - val isRepeated = args.exists(_.tpe.widen.isRepeatedParam) - if isRepeated && isReflectSelectable then - List(untpd.TypedSplice(tpd.repeatedSeq(args, TypeTree(defn.AnyType)))) - else args.map { t => - val clzSym = t.tpe.resultType.classSymbol.asClass - if ValueClasses.isDerivedValueClass(clzSym) && isReflectSelectable then - val underlying = ValueClasses.valueClassUnbox(clzSym).asTerm - tpd.Select(t, underlying.name) - else - t - }.map(untpd.TypedSplice(_)) + val args = possiblyCurried.flatten.map { t => + val clzSym = t.tpe.resultType.classSymbol.asClass + if clzSym.isDerivedValueClass && isReflectSelectable then + val underlying = ValueClasses.valueClassUnbox(clzSym).asTerm + tpd.Select(t, underlying.name) + else + t } + val handledFlat = + if isReflectSelectable then List(untpd.TypedSplice(tpd.repeatedSeq(args, TypeTree(defn.AnyType)))) + else if args.isEmpty then List() + else List(untpd.TypedSplice(tpd.repeatedSeq(args, TypeTree(args.map(_.tpe).reduce(_ | _))))) - if isReflectSelectable - then untpd.Apply(base, handled.flatten) - else handled.foldLeft(base)((base, args) => untpd.Apply(base, args)) + untpd.Apply(base, handledFlat) } def structuralCall(selectorName: TermName, classOfs: => List[Tree]) = { @@ -265,7 +262,7 @@ trait Dynamic { */ def maybeBoxingCast(tpe: Type) = val maybeBoxed = - if tpe.classSymbol.isDerivedValueClass && qual.tpe <:< defn.ReflectSelectableTypeRef then + if tpe.classSymbol.isDerivedValueClass && qual.tpe.isReflectSelectableTypeRef then val genericUnderlying = ValueClasses.valueClassUnbox(tpe.classSymbol.asClass) val underlying = tpe.select(genericUnderlying).widen.resultType New(tpe.widen, tree.cast(underlying) :: Nil) @@ -295,7 +292,7 @@ trait Dynamic { fail(i"has a parameter type with an unstable erasure") :: Nil else TypeErasure.erasure(tpe).asInstanceOf[MethodType].paramInfos.map { tpe => - if ValueClasses.isDerivedValueClass(tpe.widen.classSymbol) then + if tpe.widen.classSymbol.isDerivedValueClass then clsOf(ValueClasses.valueClassUnbox(tpe.classSymbol.asClass).info) else clsOf(tpe) diff --git a/tests/pos/i17100.scala b/tests/pos/i17100.scala index 1858e0383f8d..5d63f6d1a794 100644 --- a/tests/pos/i17100.scala +++ b/tests/pos/i17100.scala @@ -2,7 +2,7 @@ trait Sel extends Selectable extension (s: Sel) def selectDynamic(name: String) = ??? - def applyDynamic(name: String)(x: Int) = ??? + def applyDynamic(name: String)(x: Int*) = ??? def applyDynamic(name: String)() = ??? val sel = (new Sel {}).asInstanceOf[Sel{ def foo: String; def bar(x: Int): Int; def baz(): Int }] diff --git a/tests/run/i14340.scala b/tests/run/i14340.scala index 0670c7e471ac..230e08d53428 100644 --- a/tests/run/i14340.scala +++ b/tests/run/i14340.scala @@ -1,8 +1,8 @@ class Container1 extends reflect.Selectable -class Container2(values: Map[String, Any], methods: Map[String, Int => Any]) extends Selectable: +class Container2(values: Map[String, Any], methods: Map[String, Seq[Int] => Any]) extends Selectable: def selectDynamic(name: String) = values(name) - def applyDynamic(name: String)(arg: Int) = methods(name)(arg) + def applyDynamic(name: String)(arg: Int*) = methods(name)(arg) class Foo(val value: Int) extends AnyVal class Bar[A](val value: A) extends AnyVal @@ -29,7 +29,7 @@ object Helpers: ) val cont2methods = Map( - "fooFromInt" -> { (i: Int) => Foo(i) } + "fooFromInt" -> { (i: Seq[Int]) => Foo(i.head) } ) val cont2 = Container2(cont2values, cont2methods).asInstanceOf[Container2 { @@ -39,7 +39,7 @@ object Helpers: def qux2: Bar[Container2 { def foo: Foo }] def fooFromInt(i: Int): Foo }] - + println(cont1.foo.value) println(cont2.foo.value) @@ -49,7 +49,7 @@ object Helpers: println(cont1.qux1.value.foo.value) println(cont2.qux1.value.foo.value) - + println(cont1.qux2.value.foo.value) println(cont2.qux2.value.foo.value) diff --git a/tests/run/i16995.check b/tests/run/i16995.check index ade44fc1ed36..45aa0643ce08 100644 --- a/tests/run/i16995.check +++ b/tests/run/i16995.check @@ -1,10 +1,62 @@ -1 -check -6 -7 -5 -3 -3 -3 -7 -3 \ No newline at end of file +foo +foo0 +fooI 1 +fooN 1 +fooII 1 2 +fooNN 1 2 +fooIvarargs 1 2 +fooNvarargs 1 2 +fooIseq 1 2 +fooNseq 1 2 +fooIIvarargs 1 2 +fooNNvarargs 1 2 +fooI_I 1 2 +fooN_N 1 2 +foo0_II 1 2 +foo0_NN 1 2 +foo0_Ivarargs 1 2 +foo0_Nvarargs 1 2 +foo0_I_I 1 2 +foo0_N_N 1 2 + +foo +foo0 +fooI 1 +fooN 1 +fooII 1 2 +fooNN 1 2 +fooIvarargs 1 2 +fooNvarargs 1 2 +fooIseq 1 2 +fooNseq 1 2 +fooIIvarargs 1 2 3 +fooNNvarargs 1 2 +fooI_I 1 2 +fooN_N 1 2 +foo0_II 1 2 +foo0_NN 1 2 +foo0_Ivarargs 1 2 +foo0_Nvarargs 1 2 +foo0_I_I 1 2 +foo0_N_N 1 2 + +foo +foo0 +fooI 1 +fooN 1 +fooII 1 2 +fooNN 1 2 +fooIvarargs 1 2 +fooNvarargs 1 2 +fooIseq 1 2 +fooNseq 1 2 +fooIIvarargs 1 2 +fooNNvarargs 1 2 +fooI_I 1 2 +fooN_N 1 2 +foo0_II 1 2 +foo0_NN 1 2 +foo0_Ivarargs 1 2 +foo0_Nvarargs 1 2 +foo0_I_I 1 2 +foo0_N_N 1 2 diff --git a/tests/run/i16995.scala b/tests/run/i16995.scala index 163a5b070de3..d23e9b0f0d8d 100644 --- a/tests/run/i16995.scala +++ b/tests/run/i16995.scala @@ -1,83 +1,154 @@ -class Foo(val i: Int) extends AnyVal -class Argument(val x: String) extends AnyVal -class Reflective extends reflect.Selectable - -type ReflectiveType = { - def reflectiveCall(arg1: Int)(arg2: Int): Int -} - -class ClassWithReflectiveCall { - def reflectiveCall(x: Int)(y: Int): Int = x + y -} - -class ScalaSelectable(values: Map[String, Any], methods: Map[String, (Int, Seq[Foo]) => Int]) extends Selectable { - def selectDynamic(name: String): Any = values(name) - - def applyDynamic(name: String)(i: Int, foos: Foo*): Int = methods(name)(i, foos) - - def applyDynamic(name: String)(foo: Foo)(argument: Argument)(someInt: Int): Int = foo.i + argument.x.length + someInt -} - -@main def Test: Unit = - val reflective = new Reflective { - def bar(foo: Foo) = foo.i - def fun(argument: Argument) = argument - def manyArgs(argument: Argument, foo: Foo, someInt: Int) = foo.i + someInt + argument.x.length - def varargs(x: Int, foo: Foo*) = foo.map(_.i).sum + x - def letsHaveSeq(args: Seq[Argument]) = args.map(_.x.length).sum - def curried(foo: Foo)(arg1: Argument)(someInt: Int): Int = foo.i + arg1.x.length + someInt +import scala.language.dynamics +import scala.reflect.Selectable.reflectiveSelectable + +object Test { + class Num(val i: Int) extends AnyVal + + def show(x: Int | Num | Seq[Int | Num]): String = x match + case i: Int => i.toString + case num: Num => num.i.toString + case seq: Seq[Int | Num] => seq.map(show).mkString(" ") + + trait Nonreflective extends Selectable: + def selectDynamic(name: String): String = name + def applyDynamic(name: String)(args: (Int | Num | Seq[Int | Num])*): String = + val argsString = args.map(show).mkString(" ", " ", "") + s"${name}${argsString}" + + trait Dynamic0 extends Dynamic: + def selectDynamic(name: String): String = name + + trait Dynamic1 extends Dynamic: + def applyDynamic(name: String)(args1: (Int | Num | Seq[Int | Num])*): String = + val argsString = args1.map(show).mkString(" ", " ", "") + s"${name}${argsString}" + + trait Dynamic2 extends Dynamic: + def applyDynamic(name: String)(args1: (Int | Num)*)(args2: (Int | Num)*): String = + val argsString = (args1 ++ args2).map(show).mkString(" ", " ", "") + s"${name}${argsString}" + + trait Dynamic3 extends Dynamic: + def applyDynamic(name: String)(args1: (Int | Num)*)(args2: (Int | Num)*)(args3: (Int | Num)*): String = + val argsString = (args1 ++ args2 ++ args3).map(show).mkString(" ", " ", "") + s"${name}${argsString}" + + type Api = { + def foo: String + def foo0(): String + def fooI(i: Int): String + def fooN(n: Num): String + def fooII(i1: Int, i2: Int): String + def fooNN(n1: Num, n2: Num): String + def fooIvarargs(is: Int*): String + def fooNvarargs(ns: Num*): String + def fooIseq(is: Seq[Int]): String + def fooNseq(ns: Seq[Num]): String + def fooIIvarargs(i1: Int, is: Int*): String + def fooNNvarargs(n1: Num, ns: Num*): String + def fooI_I(i1: Int)(i2: Int): String + def fooN_N(n1: Num)(n2: Num): String + def foo0_II()(i1: Int, i2: Int): String + def foo0_NN()(n1: Num, n2: Num): String + def foo0_Ivarargs()(is: Int*): String + def foo0_Nvarargs()(ns: Num*): String + def foo0_I_I()(i1: Int)(i2: Int): String + def foo0_N_N()(n1: Num)(n2: Num): String } - - val i = reflective.bar(Foo(1)) - println(i) - - val arg = Argument("check") - val k = reflective.fun(arg).x - println(k) - - val length4 = Argument("four") - val foo = Foo(1) - val x = 1 - val j = reflective.manyArgs(length4, foo, x) - println(j) - - val varargs = List(Foo(1), Foo(2), Foo(3)) - val m = reflective.varargs(1, varargs:_*) - println(m) - - val foo1 = Foo(1) - val foo2 = Foo(2) - val foo3 = Foo(3) - val n = reflective.varargs(2, foo1, foo2) - println(n) - val arg1 = Argument("1") - val seq = Seq(arg1, arg1, arg1) - val p = reflective.letsHaveSeq(seq) - println(p) - - println(reflective.curried(foo1)(arg1)(1)) - - val cont2values = Map.empty[String, Any] - - val cont2methods = Map[String, (Int, Seq[Foo]) => Int]( - "varargs" -> { (i: Int, foos: Seq[Foo]) => foos.map(_.i).sum + i } - ) - - val cont2 = ScalaSelectable(cont2values, cont2methods).asInstanceOf[ScalaSelectable { - def varargs(i: Int, foos: Foo*): Int - def curried(foo: Foo)(argument: Argument)(someInt: Int): Int - }] - - println(cont2.varargs(1, Foo(1), Foo(1))) - - println(cont2.curried(Foo(1))(Argument("123"))(3)) + class ClassImpl { + def foo: String = "foo" + def foo0(): String = "foo0" + def fooI(i: Int): String = s"fooI ${i}" + def fooN(n: Num): String = s"fooN ${n.i}" + def fooII(i1: Int, i2: Int): String = s"fooII ${i1} ${i2}" + def fooNN(n1: Num, n2: Num): String = s"fooNN ${n1.i} ${n2.i}" + def fooIvarargs(is: Int*): String = s"fooIvarargs${is.mkString(" ", " ", "")}" + def fooNvarargs(ns: Num*): String = s"fooNvarargs${ns.map(_.i).mkString(" ", " ", "")}" + def fooIseq(is: Seq[Int]): String = s"fooIseq${is.mkString(" ", " ", "")}" + def fooNseq(ns: Seq[Num]): String = s"fooNseq${ns.map(_.i).mkString(" ", " ", "")}" + def fooIIvarargs(i1: Int, is: Int*): String = s"fooIIvarargs ${i1}${is.mkString(" ", " ", "")}" + def fooNNvarargs(n1: Num, ns: Num*): String = s"fooNNvarargs ${n1.i}${ns.map(_.i).mkString(" ", " ", "")}" + def fooI_I(i1: Int)(i2: Int): String = s"fooI_I ${i1} ${i2}" + def fooN_N(n1: Num)(n2: Num): String = s"fooN_N ${n1.i} ${n2.i}" + def foo0_II()(i1: Int, i2: Int): String = s"foo0_II ${i1} ${i2}" + def foo0_NN()(n1: Num, n2: Num): String = s"foo0_NN ${n1.i} ${n2.i}" + def foo0_Ivarargs()(is: Int*): String = s"foo0_Ivarargs${is.mkString(" ", " ", "")}" + def foo0_Nvarargs()(ns: Num*): String = s"foo0_Nvarargs${ns.map(_.i).mkString(" ", " ", "")}" + def foo0_I_I()(i1: Int)(i2: Int): String = s"foo0_I_I ${i1} ${i2}" + def foo0_N_N()(n1: Num)(n2: Num): String = s"foo0_N_N ${n1.i} ${n2.i}" + } - { - import scala.reflect.Selectable.reflectiveSelectable - val obj = new ClassWithReflectiveCall() - def instantiate(): ReflectiveType = obj - val rtype = instantiate() - println(rtype.reflectiveCall(1)(2)) - } \ No newline at end of file + def main(args: Array[String]): Unit = { + val reflective: Api = new ClassImpl() + val nonreflective: Nonreflective & Api = (new Nonreflective {}).asInstanceOf[Nonreflective & Api] + val dynamic0 = new Dynamic0 {} + val dynamic1 = new Dynamic1 {} + val dynamic2 = new Dynamic2 {} + val dynamic3 = new Dynamic3 {} + + println(reflective.foo) + println(reflective.foo0()) + println(reflective.fooI(1)) + println(reflective.fooN(new Num(1))) + println(reflective.fooII(1, 2)) + println(reflective.fooNN(new Num(1), new Num(2))) + println(reflective.fooIvarargs(1, 2)) + println(reflective.fooNvarargs(new Num(1), new Num(2))) + println(reflective.fooIseq(Seq(1, 2))) + println(reflective.fooNseq(Seq(new Num(1), new Num(2)))) + println(reflective.fooIIvarargs(1, 2)) + println(reflective.fooNNvarargs(new Num(1), new Num(2))) + println(reflective.fooI_I(1)(2)) + println(reflective.fooN_N(new Num(1))(new Num(2))) + println(reflective.foo0_II()(1, 2)) + println(reflective.foo0_NN()(new Num(1), new Num(2))) + println(reflective.foo0_Ivarargs()(1, 2)) + println(reflective.foo0_Nvarargs()(new Num(1), new Num(2))) + println(reflective.foo0_I_I()(1)(2)) + println(reflective.foo0_N_N()(new Num(1))(new Num(2))) + println() + println(nonreflective.foo) + println(nonreflective.foo0()) + println(nonreflective.fooI(1)) + println(nonreflective.fooN(new Num(1))) + println(nonreflective.fooII(1, 2)) + println(nonreflective.fooNN(new Num(1), new Num(2))) + println(nonreflective.fooIvarargs(1, 2)) + println(nonreflective.fooNvarargs(new Num(1), new Num(2))) + println(nonreflective.fooIseq(Seq(1, 2))) + println(nonreflective.fooNseq(Seq(new Num(1), new Num(2)))) + println(nonreflective.fooIIvarargs(1, 2, 3)) + println(nonreflective.fooNNvarargs(new Num(1), new Num(2))) + println(nonreflective.fooI_I(1)(2)) + println(nonreflective.fooN_N(new Num(1))(new Num(2))) + println(nonreflective.foo0_II()(1, 2)) + println(nonreflective.foo0_NN()(new Num(1), new Num(2))) + println(nonreflective.foo0_Ivarargs()(1, 2)) + println(nonreflective.foo0_Nvarargs()(new Num(1), new Num(2))) + println(nonreflective.foo0_I_I()(1)(2)) + println(nonreflective.foo0_N_N()(new Num(1))(new Num(2))) + println() + println(dynamic0.foo) + println(dynamic1.foo0()) + println(dynamic1.fooI(1)) + println(dynamic1.fooN(new Num(1))) + println(dynamic1.fooII(1, 2)) + println(dynamic1.fooNN(new Num(1), new Num(2))) + println(dynamic1.fooIvarargs(1, 2)) + println(dynamic1.fooNvarargs(new Num(1), new Num(2))) + println(dynamic1.fooIseq(Seq(1, 2))) + println(dynamic1.fooNseq(Seq(new Num(1), new Num(2)))) + println(dynamic1.fooIIvarargs(1, 2)) + println(dynamic1.fooNNvarargs(new Num(1), new Num(2))) + println(dynamic2.fooI_I(1)(2)) + println(dynamic2.fooN_N(new Num(1))(new Num(2))) + println(dynamic2.foo0_II()(1, 2)) + println(dynamic2.foo0_NN()(new Num(1), new Num(2))) + println(dynamic2.foo0_Ivarargs()(1, 2)) + println(dynamic2.foo0_Nvarargs()(new Num(1), new Num(2))) + println(dynamic3.foo0_I_I()(1)(2)) + println(dynamic3.foo0_N_N()(new Num(1))(new Num(2))) + } +} \ No newline at end of file diff --git a/tests/sjs-junit/test/org/scalajs/testsuite/compiler/CustomReflectSelectableTestScala3.scala b/tests/sjs-junit/test/org/scalajs/testsuite/compiler/CustomReflectSelectableTestScala3.scala index 19740a31f48a..43de05d4b784 100644 --- a/tests/sjs-junit/test/org/scalajs/testsuite/compiler/CustomReflectSelectableTestScala3.scala +++ b/tests/sjs-junit/test/org/scalajs/testsuite/compiler/CustomReflectSelectableTestScala3.scala @@ -34,8 +34,11 @@ class CustomReflectSelectableTestScala3 { @Test def callSelectableWithVarargs(): Unit = { val cont2values = Map.empty[String, Any] - val cont2methods = Map[String, (Int, Seq[Bar]) => Int]( - "varargs" -> { (i: Int, bars: Seq[Bar]) => bars.map(_.x).sum + i } + val cont2methods = Map[String, Seq[(Int | Bar | Seq[Bar])] => Int]( + "varargs" -> { (args: Seq[(Int | Bar | Seq[Bar])]) => args.map { + case x: Int => x + case b: Bar => b.x + } .sum } ) val cont = ScalaSelectable(cont2values, cont2methods).asInstanceOf[ScalaSelectable { def varargs(i: Int, foos: Bar*): Int @@ -45,8 +48,13 @@ class CustomReflectSelectableTestScala3 { @Test def callSelectableWithVarargsExpansion(): Unit = { val cont2values = Map.empty[String, Any] - val cont2methods = Map[String, (Int, Seq[Bar]) => Int]( - "varargs" -> { (i: Int, bars: Seq[Bar]) => bars.map(_.x).sum + i } + val cont2methods = Map[String, Seq[(Int | Bar | Seq[Bar])] => Int]( + "varargs" -> { + (args: Seq[(Int | Bar | Seq[Bar])]) => args.map { + case x: Int => x + case b: Bar => b.x + }.sum + } ) val cont = ScalaSelectable(cont2values, cont2methods).asInstanceOf[ScalaSelectable { def varargs(i: Int, foos: Bar*): Int @@ -68,9 +76,9 @@ object CustomReflectSelectableTestScala3 { def varargs(x: Int, args: Bar*) = args.map(_.x).sum + x } - class ScalaSelectable(values: Map[String, Any], methods: Map[String, (Int, Seq[Bar]) => Int]) extends Selectable { + class ScalaSelectable(values: Map[String, Any], methods: Map[String, Seq[(Int | Bar | Seq[Bar])] => Int]) extends Selectable { def selectDynamic(name: String): Any = values(name) - def applyDynamic(name: String)(i: Int, bars: Bar*): Int = methods(name)(i, bars) + def applyDynamic(name: String)(args: (Int | Bar | Seq[Bar])*): Int = methods(name)(args) } }