diff --git a/compiler/src/dotty/tools/dotc/transform/Splicer.scala b/compiler/src/dotty/tools/dotc/transform/Splicer.scala index 704c44f41a1c..87b238ad4e78 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splicer.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splicer.scala @@ -46,7 +46,14 @@ object Splicer { } catch { case ex: scala.quoted.QuoteError => - ctx.error(ex.getMessage, pos) + val pos1 = ex.from match { + case None => pos + case Some(expr) => + val reflect: scala.tasty.Reflection = ReflectionImpl(ctx) + import reflect._ + expr.unseal.underlyingArgument.pos.asInstanceOf[SourcePosition] + } + ctx.error(ex.getMessage, pos1) EmptyTree case NonFatal(ex) => val msg = diff --git a/docs/docs/reference/other-new-features/tasty-reflect.md b/docs/docs/reference/other-new-features/tasty-reflect.md index 8f631b640f47..e7ea8cbdb4ef 100644 --- a/docs/docs/reference/other-new-features/tasty-reflect.md +++ b/docs/docs/reference/other-new-features/tasty-reflect.md @@ -42,10 +42,10 @@ def natConstImpl(x: Expr[Int])(implicit reflection: Reflection): Expr[Int] = { xTree match { case Term.Literal(Constant.Int(n)) => if (n <= 0) - throw new QuoteError("Parameter must be natural number") + QuoteError("Parameter must be natural number") n.toExpr case _ => - throw new QuoteError("Parameter must be a known constant") + QuoteError("Parameter must be a known constant") } } ``` diff --git a/library/src-bootstrapped/scala/Tuple.scala b/library/src-bootstrapped/scala/Tuple.scala index 6afa9635959b..622656ab8259 100644 --- a/library/src-bootstrapped/scala/Tuple.scala +++ b/library/src-bootstrapped/scala/Tuple.scala @@ -1,16 +1,16 @@ package scala import annotation.showAsInfix import compiletime._ -import scala.StagedTuple +import internal._ sealed trait Tuple extends Any { import Tuple._ inline def toArray: Array[Object] = - if (stageIt) stagedToArray + if (stageIt) toArrayStaged else inline constValueOpt[BoundedSize[this.type]] match { case Some(0) => - empty$Array + scala.runtime.DynamicTuple.empty$Array case Some(1) => val t = asInstanceOf[Tuple1[Object]] Array(t._1) @@ -23,19 +23,19 @@ sealed trait Tuple extends Any { case Some(4) => val t = asInstanceOf[Tuple4[Object, Object, Object, Object]] Array(t._1, t._2, t._3, t._4) - case Some(n) if n <= MaxSpecialized => + case Some(n) if n <= scala.runtime.DynamicTuple.MaxSpecialized => to$Array(this, n) case Some(n) => asInstanceOf[TupleXXL].elems case None => - dynamicToArray(this) + runtime.DynamicTuple.dynamicToArray(this) } - inline def stagedToArray: Array[Object] = + inline def toArrayStaged: Array[Object] = ${ StagedTuple.toArrayStaged('this, constValueOpt[BoundedSize[this.type]]) } inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This = - if (stageIt) stagedCons[H](x) + if (stageIt) consStaged[H](x) else { type Result = H *: This inline constValueOpt[BoundedSize[this.type]] match { @@ -55,15 +55,15 @@ sealed trait Tuple extends Any { case Some(n) => fromArray[H *: this.type](cons$Array(x, toArray)) case _ => - dynamic_*:[This, H](this, x) + runtime.DynamicTuple.dynamic_*:[This, H](this, x) } } - inline def stagedCons[H] (x: H): H *: this.type = - ${ StagedTuple.stagedCons('this, 'x, constValueOpt[BoundedSize[this.type]]) } + inline def consStaged[H] (x: H): H *: this.type = + ${ StagedTuple.consStaged('this, 'x, constValueOpt[BoundedSize[this.type]]) } inline def ++ [This >: this.type <: Tuple](that: Tuple): Concat[This, that.type] = - if (stageIt) stagedConcat(that).asInstanceOf + if (stageIt) concatStaged(that).asInstanceOf else { type Result = Concat[This, that.type] inline constValueOpt[BoundedSize[this.type]] match { @@ -99,35 +99,32 @@ sealed trait Tuple extends Any { if (constValue[BoundedSize[that.type]] == 0) this.asInstanceOf[Result] else genericConcat[Result](this, that).asInstanceOf[Result] case None => - dynamic_++[This, that.type](this, that) + runtime.DynamicTuple.dynamic_++[This, that.type](this, that) } } - inline def stagedConcat(that: Tuple): Concat[this.type, that.type] = - ${ StagedTuple.stagedConcat('this, constValueOpt[BoundedSize[this.type]], + inline def concatStaged(that: Tuple): Concat[this.type, that.type] = + ${ StagedTuple.concatStaged('this, constValueOpt[BoundedSize[this.type]], 'that, constValueOpt[BoundedSize[that.type]]) } inline def genericConcat[T <: Tuple](xs: Tuple, ys: Tuple): Tuple = fromArray[T](xs.toArray ++ ys.toArray) inline def size[This >: this.type <: Tuple]: Size[This] = - if (stageIt) stagedSize.asInstanceOf + if (stageIt) sizeStaged.asInstanceOf else { type Result = Size[This] inline constValueOpt[BoundedSize[this.type]] match { case Some(n) => n.asInstanceOf[Result] - case _ => dynamicSize(this) + case _ => runtime.DynamicTuple.dynamicSize(this) } } - inline def stagedSize: Size[this.type] = + inline def sizeStaged: Size[this.type] = ${ StagedTuple.sizeStaged[Size[this.type]]('this, constValueOpt[BoundedSize[this.type]]) } } object Tuple { - inline val MaxSpecialized = 22 - inline private val XXL = MaxSpecialized + 1 - final val stageIt = false type Head[X <: NonEmptyTuple] = X match { @@ -167,7 +164,7 @@ object Tuple { private[scala] type BoundedSize[X] = BoundedSizeRecur[X, 23] - val empty$Array = Array[Object]() + val $emptyArray = Array[Object]() def to$Array(xs: Tuple, n: Int) = { val arr = new Array[Object](n) @@ -188,7 +185,7 @@ object Tuple { } inline def fromArray[T <: Tuple](xs: Array[Object]): T = - if (stageIt) stagedFromArray[T](xs) + if (stageIt) fromArrayStaged[T](xs) else inline constValue[BoundedSize[T]] match { case 0 => ().asInstanceOf[T] case 1 => Tuple1(xs(0)).asInstanceOf[T] @@ -216,103 +213,15 @@ object Tuple { case _ => TupleXXL(xs).asInstanceOf[T] } - inline def stagedFromArray[T <: Tuple](xs: Array[Object]): T = - ${ StagedTuple.fromArrayStaged[T]('xs, constValueOpt[BoundedSize[this.type]]) } - - def dynamicFromArray[T <: Tuple](xs: Array[Object]): T = xs.length match { - case 0 => ().asInstanceOf[T] - case 1 => Tuple1(xs(0)).asInstanceOf[T] - case 2 => Tuple2(xs(0), xs(1)).asInstanceOf[T] - case 3 => Tuple3(xs(0), xs(1), xs(2)).asInstanceOf[T] - case 4 => Tuple4(xs(0), xs(1), xs(2), xs(3)).asInstanceOf[T] - case 5 => Tuple5(xs(0), xs(1), xs(2), xs(3), xs(4)).asInstanceOf[T] - case 6 => Tuple6(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5)).asInstanceOf[T] - case 7 => Tuple7(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6)).asInstanceOf[T] - case 8 => Tuple8(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7)).asInstanceOf[T] - case 9 => Tuple9(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8)).asInstanceOf[T] - case 10 => Tuple10(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9)).asInstanceOf[T] - case 11 => Tuple11(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10)).asInstanceOf[T] - case 12 => Tuple12(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11)).asInstanceOf[T] - case 13 => Tuple13(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12)).asInstanceOf[T] - case 14 => Tuple14(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13)).asInstanceOf[T] - case 15 => Tuple15(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14)).asInstanceOf[T] - case 16 => Tuple16(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15)).asInstanceOf[T] - case 17 => Tuple17(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16)).asInstanceOf[T] - case 18 => Tuple18(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17)).asInstanceOf[T] - case 19 => Tuple19(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18)).asInstanceOf[T] - case 20 => Tuple20(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19)).asInstanceOf[T] - case 21 => Tuple21(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20)).asInstanceOf[T] - case 22 => Tuple22(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20), xs(21)).asInstanceOf[T] - case _ => TupleXXL(xs).asInstanceOf[T] - } - - def dynamicToArray(self: Tuple): Array[Object] = (self: Any) match { - case self: Unit => - empty$Array - case self: Tuple1[_] => - val t = self.asInstanceOf[Tuple1[Object]] - Array(t._1) - case self: Tuple2[_, _] => - val t = self.asInstanceOf[Tuple2[Object, Object]] - Array(t._1, t._2) - case self: Tuple3[_, _, _] => - val t = self.asInstanceOf[Tuple3[Object, Object, Object]] - Array(t._1, t._2, t._3) - case self: Tuple4[_, _, _, _] => - val t = self.asInstanceOf[Tuple4[Object, Object, Object, Object]] - Array(t._1, t._2, t._3, t._4) - case self: TupleXXL => - self.elems - case self: Product => - val arr = new Array[Object](self.productArity) - for (i <- 0 until arr.length) arr(i) = self.productElement(i).asInstanceOf[Object] - arr - } - - def dynamic_*: [This <: Tuple, H] (self: Tuple, x: H): H *: This = { - type Result = H *: This - (self: Any) match { - case Unit => - Tuple1(x).asInstanceOf[Result] - case self: Tuple1[_] => - Tuple2(x, self._1).asInstanceOf[Result] - case self: Tuple2[_, _] => - Tuple3(x, self._1, self._2).asInstanceOf[Result] - case self: Tuple3[_, _, _] => - Tuple4(x, self._1, self._2, self._3).asInstanceOf[Result] - case self: Tuple4[_, _, _, _] => - Tuple5(x, self._1, self._2, self._3, self._4).asInstanceOf[Result] - case _ => - dynamicFromArray[Result](cons$Array(x, dynamicToArray(self))) - } - } - - def dynamic_++[This <: Tuple, That <: Tuple](self: This, that: That): Concat[This, That] = { - type Result = Concat[This, That] - (this: Any) match { - case self: Unit => return self.asInstanceOf[Result] - case _ => - } - (that: Any) match { - case that: Unit => return self.asInstanceOf[Result] - case _ => - } - dynamicFromArray[Result](dynamicToArray(self) ++ dynamicToArray(that)) - } - - def dynamicSize[This <: Tuple](self: This): Size[This] = (self: Any) match { - case self: Unit => 0.asInstanceOf[Size[This]] - case self: TupleXXL => self.elems.length.asInstanceOf[Size[This]] - case self: Product => self.productArity.asInstanceOf[Size[This]] - } + inline def fromArrayStaged[T <: Tuple](xs: Array[Object]): T = + ${StagedTuple.fromArrayStaged[T]('xs, constValueOpt[BoundedSize[this.type]])} } sealed trait NonEmptyTuple extends Tuple { import Tuple._ - import NonEmptyTuple._ inline def head[This >: this.type <: NonEmptyTuple]: Head[This] = - if (stageIt) stagedHead.asInstanceOf + if (stageIt) headStaged.asInstanceOf else { type Result = Head[This] val resVal = inline constValueOpt[BoundedSize[this.type]] match { @@ -328,22 +237,22 @@ sealed trait NonEmptyTuple extends Tuple { case Some(4) => val t = asInstanceOf[Tuple4[_, _, _, _]] t._1 - case Some(n) if n > 4 && n <= MaxSpecialized => + case Some(n) if n > 4 && n <= scala.runtime.DynamicTuple.MaxSpecialized => asInstanceOf[Product].productElement(0) - case Some(n) if n > MaxSpecialized => + case Some(n) if n > scala.runtime.DynamicTuple.MaxSpecialized => val t = asInstanceOf[TupleXXL] t.elems(0) case None => - dynamicHead[this.type](this) + scala.runtime.DynamicTuple.dynamicHead[this.type](this) } resVal.asInstanceOf[Result] } - inline def stagedHead: Head[this.type] = + inline def headStaged: Head[this.type] = ${ StagedTuple.headStaged[this.type]('this, constValueOpt[BoundedSize[this.type]]) } inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] = - if (stageIt) stagedTail.asInstanceOf + if (stageIt) tailStaged.asInstanceOf else { type Result = Tail[This] inline constValueOpt[BoundedSize[this.type]] match { @@ -364,21 +273,21 @@ sealed trait NonEmptyTuple extends Tuple { case Some(n) if n > 5 => fromArray[Result](toArray.tail) case None => - dynamicTail[This](this) + runtime.DynamicTuple.dynamicTail[This](this) } } - inline def stagedTail: Tail[this.type] = + inline def tailStaged: Tail[this.type] = ${ StagedTuple.tailStaged[this.type]('this, constValueOpt[BoundedSize[this.type]]) } inline def fallbackApply(n: Int) = inline constValueOpt[n.type] match { case Some(n: Int) => error("index out of bounds: ", n) - case None => dynamicApply[this.type, n.type](this, n) + case None => runtime.DynamicTuple.dynamicApply[this.type, n.type](this, n) } inline def apply[This >: this.type <: NonEmptyTuple](n: Int): Elem[This, n.type] = - if (stageIt) stagedApply(n).asInstanceOf + if (stageIt) applyStaged(n).asInstanceOf else { type Result = Elem[This, n.type] inline constValueOpt[Size[this.type]] match { @@ -412,13 +321,13 @@ sealed trait NonEmptyTuple extends Tuple { case Some(3) => t._4.asInstanceOf[Result] case _ => fallbackApply(n).asInstanceOf[Result] } - case Some(s) if s > 4 && s <= MaxSpecialized => + case Some(s) if s > 4 && s <= scala.runtime.DynamicTuple.MaxSpecialized => val t = asInstanceOf[Product] inline constValueOpt[n.type] match { case Some(n) if n >= 0 && n < s => t.productElement(n).asInstanceOf[Result] case _ => fallbackApply(n).asInstanceOf[Result] } - case Some(s) if s > MaxSpecialized => + case Some(s) if s > scala.runtime.DynamicTuple.MaxSpecialized => val t = asInstanceOf[TupleXXL] inline constValueOpt[n.type] match { case Some(n) if n >= 0 && n < s => t.elems(n).asInstanceOf[Result] @@ -428,53 +337,17 @@ sealed trait NonEmptyTuple extends Tuple { } } - inline def stagedApply(n: Int): Elem[this.type, n.type] = - ${ StagedTuple.applyStaged[this.type, n.type]( - 'this, constValueOpt[Size[this.type]], - 'n, constValueOpt[n.type]) } -} - -object NonEmptyTuple { - import Tuple._ - - def dynamicHead[This <: NonEmptyTuple] (self: This): Head[This] = { - type Result = Head[This] - val res = (self: Any) match { - case self: Tuple1[_] => self._1 - case self: Tuple2[_, _] => self._1 - case self: Tuple3[_, _, _] => self._1 - case self: Tuple4[_, _, _, _] => self._1 - case self: TupleXXL => self.elems(0) - case self: Product => self.productElement(0) - } - res.asInstanceOf[Result] - } - - def dynamicTail[This <: NonEmptyTuple] (self: This): Tail[This] = { - type Result = Tail[This] - val res = (self: Any) match { - case self: Tuple1[_] => () - case self: Tuple2[_, _] => Tuple1(self._2) - case self: Tuple3[_, _, _] => Tuple2(self._2, self._3) - case self: Tuple4[_, _, _, _] => Tuple3(self._2, self._3, self._4) - case _ => dynamicFromArray[Result](dynamicToArray(self).tail) - } - res.asInstanceOf[Result] - } - - def dynamicApply[This <: NonEmptyTuple, N <: Int] (self: This, n: N): Elem[This, N] = { - type Result = Elem[This, N] - val res = (self: Any) match { - case self: TupleXXL => self.elems(n) - case self: Product => self.productElement(n) - } - res.asInstanceOf[Result] - } + inline def applyStaged(n: Int): Elem[this.type, n.type] = + ${StagedTuple.applyStaged[this.type, n.type]( + 'this, constValueOpt[Size[this.type]], 'n, constValueOpt[n.type])} } @showAsInfix sealed class *:[+H, +T <: Tuple] extends NonEmptyTuple object *: { - inline def unapply[H, T <: Tuple](x: H *: T) = (x.head, x.tail) + inline def unapply[H, T <: Tuple](x: H *: T) = + // With stageIt on we cannot expand x.head in the same run and fails + if (Tuple.stageIt) (scala.runtime.DynamicTuple.dynamicHead(x), scala.runtime.DynamicTuple.dynamicTail(x)) + else (x.head, x.tail) } diff --git a/library/src-bootstrapped/scala/StagedTuple.scala b/library/src-bootstrapped/scala/internal/StagedTuple.scala similarity index 94% rename from library/src-bootstrapped/scala/StagedTuple.scala rename to library/src-bootstrapped/scala/internal/StagedTuple.scala index 30c167871ada..e18487cef27d 100644 --- a/library/src-bootstrapped/scala/StagedTuple.scala +++ b/library/src-bootstrapped/scala/internal/StagedTuple.scala @@ -1,10 +1,14 @@ -package scala +package scala.internal import scala.quoted._ object StagedTuple { - import Tuple._ - import NonEmptyTuple._ + import Tuple.Concat + import Tuple.Head + import Tuple.Tail + import Tuple.Size + import Tuple.Elem + import scala.runtime.DynamicTuple._ private final val specialize = true @@ -12,7 +16,7 @@ object StagedTuple { if (!specialize) '{dynamicToArray($tup)} else size match { case Some(0) => - '{empty$Array} + '{scala.runtime.DynamicTuple.empty$Array} case Some(1) => tup.as[Tuple1[Object]].bind(t => '{Array($t._1)}) case Some(2) => @@ -113,7 +117,7 @@ object StagedTuple { tup.as[Tuple5[_, _, _, _, _]].bind(t => '{Tuple4($t._2, $t._3, $t._4, $t._5)}) case Some(n) if n > 5 => val arr = toArrayStaged(tup, size) - fromArrayStaged('{ $arr.tail }, Some(n - 1)) + fromArrayStaged[Tail[Tup]]('{ $arr.tail }, Some(n - 1)) case None => '{dynamicTail($tup)} } @@ -121,11 +125,13 @@ object StagedTuple { } } - def applyStaged[Tup <: NonEmptyTuple : Type, N <: Int : Type](tup: Expr[Tup], size: Option[Int], n: Expr[N], nValue: Option[Int]): Expr[Elem[Tup, N]] = { + def applyStaged[Tup <: NonEmptyTuple : Type, N <: Int : Type](tup: Expr[Tup], size: Option[Int], n: Expr[N], nValue: Option[Int])(implicit reflect: tasty.Reflection): Expr[Elem[Tup, N]] = { + import reflect._ + if (!specialize) '{dynamicApply($tup, $n)} else { def fallbackApply(): Expr[Elem[Tup, N]] = nValue match { - case Some(n) => quoted.QuoteError("index out of bounds: " + n) + case Some(n) => QuoteError("index out of bounds: " + n, tup) case None => '{dynamicApply($tup, $n)} } val res = size match { @@ -177,7 +183,7 @@ object StagedTuple { } } - def stagedCons[T <: Tuple & Singleton : Type, H : Type](self: Expr[T], x: Expr[H], tailSize: Option[Int]): Expr[H *: T] = + def consStaged[T <: Tuple & Singleton : Type, H : Type](self: Expr[T], x: Expr[H], tailSize: Option[Int]): Expr[H *: T] = if (!specialize) '{dynamic_*:[T, H]($self, $x)} else { val res = tailSize match { @@ -199,7 +205,7 @@ object StagedTuple { res.as[H *: T] } - def stagedConcat[Self <: Tuple & Singleton : Type, That <: Tuple & Singleton : Type](self: Expr[Self], selfSize: Option[Int], that: Expr[That], thatSize: Option[Int]): Expr[Concat[Self, That]] = { + def concatStaged[Self <: Tuple & Singleton : Type, That <: Tuple & Singleton : Type](self: Expr[Self], selfSize: Option[Int], that: Expr[That], thatSize: Option[Int]): Expr[Concat[Self, That]] = { if (!specialize) '{dynamic_++[Self, That]($self, $that)} else { def genericConcat(xs: Expr[Tuple], ys: Expr[Tuple]): Expr[Tuple] = @@ -211,7 +217,7 @@ object StagedTuple { that case Some(1) => if (thatSize.contains(0)) self - else stagedCons(that, '{$self.asInstanceOf[Tuple1[_]]._1}, thatSize) + else consStaged(that, '{$self.asInstanceOf[Tuple1[_]]._1}, thatSize) case Some(2) => val self2 = self.as[Tuple2[_, _]] thatSize match { @@ -256,7 +262,5 @@ object StagedTuple { val t: U = $expr ${in('t)} } - } - } diff --git a/library/src-bootstrapped/scala/runtime/DynamicTuple.scala b/library/src-bootstrapped/scala/runtime/DynamicTuple.scala new file mode 100644 index 000000000000..6560de1cf410 --- /dev/null +++ b/library/src-bootstrapped/scala/runtime/DynamicTuple.scala @@ -0,0 +1,153 @@ +package scala.runtime + +import scala.Tuple.Concat +import scala.Tuple.Size +import scala.Tuple.Head +import scala.Tuple.Tail +import scala.Tuple.Elem + +object DynamicTuple { + inline val MaxSpecialized = 22 + inline private val XXL = MaxSpecialized + 1 + + val empty$Array = Array[Object]() + + def to$Array(xs: Tuple, n: Int) = { + val arr = new Array[Object](n) + var i = 0 + var it = xs.asInstanceOf[Product].productIterator + while (i < n) { + arr(i) = it.next().asInstanceOf[Object] + i += 1 + } + arr + } + + def cons$Array[H](x: H, elems: Array[Object]): Array[Object] = { + val elems1 = new Array[Object](elems.length + 1) + elems1(0) = x.asInstanceOf[Object] + System.arraycopy(elems, 0, elems1, 1, elems.length) + elems1 + } + + def dynamicFromArray[T <: Tuple](xs: Array[Object]): T = xs.length match { + case 0 => ().asInstanceOf[T] + case 1 => Tuple1(xs(0)).asInstanceOf[T] + case 2 => Tuple2(xs(0), xs(1)).asInstanceOf[T] + case 3 => Tuple3(xs(0), xs(1), xs(2)).asInstanceOf[T] + case 4 => Tuple4(xs(0), xs(1), xs(2), xs(3)).asInstanceOf[T] + case 5 => Tuple5(xs(0), xs(1), xs(2), xs(3), xs(4)).asInstanceOf[T] + case 6 => Tuple6(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5)).asInstanceOf[T] + case 7 => Tuple7(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6)).asInstanceOf[T] + case 8 => Tuple8(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7)).asInstanceOf[T] + case 9 => Tuple9(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8)).asInstanceOf[T] + case 10 => Tuple10(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9)).asInstanceOf[T] + case 11 => Tuple11(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10)).asInstanceOf[T] + case 12 => Tuple12(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11)).asInstanceOf[T] + case 13 => Tuple13(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12)).asInstanceOf[T] + case 14 => Tuple14(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13)).asInstanceOf[T] + case 15 => Tuple15(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14)).asInstanceOf[T] + case 16 => Tuple16(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15)).asInstanceOf[T] + case 17 => Tuple17(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16)).asInstanceOf[T] + case 18 => Tuple18(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17)).asInstanceOf[T] + case 19 => Tuple19(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18)).asInstanceOf[T] + case 20 => Tuple20(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19)).asInstanceOf[T] + case 21 => Tuple21(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20)).asInstanceOf[T] + case 22 => Tuple22(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20), xs(21)).asInstanceOf[T] + case _ => TupleXXL(xs).asInstanceOf[T] + } + + def dynamicToArray(self: Tuple): Array[Object] = (self: Any) match { + case self: Unit => + scala.runtime.DynamicTuple.empty$Array + case self: Tuple1[_] => + val t = self.asInstanceOf[Tuple1[Object]] + Array(t._1) + case self: Tuple2[_, _] => + val t = self.asInstanceOf[Tuple2[Object, Object]] + Array(t._1, t._2) + case self: Tuple3[_, _, _] => + val t = self.asInstanceOf[Tuple3[Object, Object, Object]] + Array(t._1, t._2, t._3) + case self: Tuple4[_, _, _, _] => + val t = self.asInstanceOf[Tuple4[Object, Object, Object, Object]] + Array(t._1, t._2, t._3, t._4) + case self: TupleXXL => + self.elems + case self: Product => + val arr = new Array[Object](self.productArity) + for (i <- 0 until arr.length) arr(i) = self.productElement(i).asInstanceOf[Object] + arr + } + + def dynamic_*: [This <: Tuple, H] (self: Tuple, x: H): H *: This = { + type Result = H *: This + (self: Any) match { + case Unit => + Tuple1(x).asInstanceOf[Result] + case self: Tuple1[_] => + Tuple2(x, self._1).asInstanceOf[Result] + case self: Tuple2[_, _] => + Tuple3(x, self._1, self._2).asInstanceOf[Result] + case self: Tuple3[_, _, _] => + Tuple4(x, self._1, self._2, self._3).asInstanceOf[Result] + case self: Tuple4[_, _, _, _] => + Tuple5(x, self._1, self._2, self._3, self._4).asInstanceOf[Result] + case _ => + dynamicFromArray[Result](cons$Array(x, dynamicToArray(self))) + } + } + + def dynamic_++[This <: Tuple, That <: Tuple](self: This, that: That): Concat[This, That] = { + type Result = Concat[This, That] + (this: Any) match { + case self: Unit => return self.asInstanceOf[Result] + case _ => + } + (that: Any) match { + case that: Unit => return self.asInstanceOf[Result] + case _ => + } + dynamicFromArray[Result](dynamicToArray(self) ++ dynamicToArray(that)) + } + + def dynamicSize[This <: Tuple](self: This): Size[This] = (self: Any) match { + case self: Unit => 0.asInstanceOf[Size[This]] + case self: TupleXXL => self.elems.length.asInstanceOf[Size[This]] + case self: Product => self.productArity.asInstanceOf[Size[This]] + } + + def dynamicHead[This <: NonEmptyTuple] (self: This): Head[This] = { + type Result = Head[This] + val res = (self: Any) match { + case self: Tuple1[_] => self._1 + case self: Tuple2[_, _] => self._1 + case self: Tuple3[_, _, _] => self._1 + case self: Tuple4[_, _, _, _] => self._1 + case self: TupleXXL => self.elems(0) + case self: Product => self.productElement(0) + } + res.asInstanceOf[Result] + } + + def dynamicTail[This <: NonEmptyTuple] (self: This): Tail[This] = { + type Result = Tail[This] + val res = (self: Any) match { + case self: Tuple1[_] => () + case self: Tuple2[_, _] => Tuple1(self._2) + case self: Tuple3[_, _, _] => Tuple2(self._2, self._3) + case self: Tuple4[_, _, _, _] => Tuple3(self._2, self._3, self._4) + case _ => dynamicFromArray[Result](dynamicToArray(self).tail) + } + res.asInstanceOf[Result] + } + + def dynamicApply[This <: NonEmptyTuple, N <: Int] (self: This, n: Int): Elem[This, N] = { + type Result = Elem[This, N] + val res = (self: Any) match { + case self: TupleXXL => self.elems(n) + case self: Product => self.productElement(n) + } + res.asInstanceOf[Result] + } +} diff --git a/library/src/scala/quoted/QuoteError.scala b/library/src/scala/quoted/QuoteError.scala index fbd85e51411d..bd11a02caf1c 100644 --- a/library/src/scala/quoted/QuoteError.scala +++ b/library/src/scala/quoted/QuoteError.scala @@ -3,9 +3,12 @@ package scala.quoted /** Throwing this error in the implementation of a macro * will result in a compilation error with the given message. */ -class QuoteError(message: String) extends Throwable(message) +class QuoteError(message: String, val from: Option[Expr[_]]) extends Throwable(message) object QuoteError { /** Throws a QuoteError with the given message */ - def apply(message: => String): Nothing = throw new QuoteError(message) + def apply(message: => String): Nothing = throw new QuoteError(message, None) + + /** Throws a QuoteError with the given message at the position of the `from` expression */ + def apply(message: => String, from: Expr[_]): Nothing = throw new QuoteError(message, Some(from)) } diff --git a/tests/neg-with-compiler/i5941/macro_1.scala b/tests/neg-with-compiler/i5941/macro_1.scala index a5d59254b973..e5f7ca7c2768 100644 --- a/tests/neg-with-compiler/i5941/macro_1.scala +++ b/tests/neg-with-compiler/i5941/macro_1.scala @@ -34,7 +34,7 @@ object Lens { apply($getter)(setter) } case _ => - throw new QuoteError("Unsupported syntax. Example: `GenLens[Address](_.streetNumber)`") + QuoteError("Unsupported syntax. Example: `GenLens[Address](_.streetNumber)`") } } } diff --git a/tests/run-with-compiler/i5941/macro_1.scala b/tests/run-with-compiler/i5941/macro_1.scala index f2069d1bff89..15a9c87db863 100644 --- a/tests/run-with-compiler/i5941/macro_1.scala +++ b/tests/run-with-compiler/i5941/macro_1.scala @@ -60,7 +60,7 @@ object Lens { apply($getter)(setter) } case _ => - throw new QuoteError("Unsupported syntax. Example: `GenLens[Address](_.streetNumber)`") + QuoteError("Unsupported syntax. Example: `GenLens[Address](_.streetNumber)`") } } } @@ -101,7 +101,7 @@ object Iso { // 2. A must be a tuple // 3. The parameters of S must match A if (tpS.classSymbol.flatMap(cls => if (cls.flags.is(Flags.Case)) Some(true) else None).isEmpty) - throw new QuoteError("Only support generation for case classes") + QuoteError("Only support generation for case classes") val cls = tpS.classSymbol.get @@ -111,11 +111,11 @@ object Iso { } if (cls.caseFields.size != 1) - throw new QuoteError("Use GenIso.fields for case classes more than one parameter") + QuoteError("Use GenIso.fields for case classes more than one parameter") val fieldTp = tpS.memberType(cls.caseFields.head) if (!(fieldTp =:= tpA)) - throw new QuoteError(s"The type of case class field $fieldTp does not match $tpA") + QuoteError(s"The type of case class field $fieldTp does not match $tpA") '{ // (p: S) => p._1 @@ -142,7 +142,7 @@ object Iso { val cls = tpS.classSymbol.get if (cls.caseFields.size != 0) - throw new QuoteError("Use GenIso.fields for case classes more than one parameter") + QuoteError("Use GenIso.fields for case classes more than one parameter") val companion = tpS match { case Type.SymRef(sym, prefix) => Type.TermRef(prefix, sym.name) @@ -156,7 +156,7 @@ object Iso { } } else { - throw new QuoteError("Only support generation for case classes or singleton types") + QuoteError("Only support generation for case classes or singleton types") } } diff --git a/tests/run/f-interpolation-1/FQuote_1.scala b/tests/run/f-interpolation-1/FQuote_1.scala index 159b22606ab1..9ddf1a189f65 100644 --- a/tests/run/f-interpolation-1/FQuote_1.scala +++ b/tests/run/f-interpolation-1/FQuote_1.scala @@ -40,7 +40,7 @@ object FQuote { values.forall(isStringConstant) => values.collect { case Literal(Constant.String(value)) => value } case tree => - throw new QuoteError(s"String literal expected, but ${tree.showExtractors} found") + QuoteError(s"String literal expected, but ${tree.showExtractors} found") } // [a0, ...]: Any* diff --git a/tests/run/tasty-interpolation-1/Macro.scala b/tests/run/tasty-interpolation-1/Macro.scala index c8c83914aeb3..334fb9cfa77d 100644 --- a/tests/run/tasty-interpolation-1/Macro.scala +++ b/tests/run/tasty-interpolation-1/Macro.scala @@ -38,13 +38,13 @@ abstract class MacroStringInterpolator[T] { catch { case ex: NotStaticlyKnownError => // TODO use ex.expr to recover the position - throw new QuoteError(ex.getMessage) + QuoteError(ex.getMessage) case ex: StringContextError => // TODO use ex.idx to recover the position - throw new QuoteError(ex.getMessage) + QuoteError(ex.getMessage) case ex: ArgumentError => // TODO use ex.idx to recover the position - throw new QuoteError(ex.getMessage) + QuoteError(ex.getMessage) } } diff --git a/tests/run/tasty-macro-const/quoted_1.scala b/tests/run/tasty-macro-const/quoted_1.scala index b627a21360cd..51f7bc31af81 100644 --- a/tests/run/tasty-macro-const/quoted_1.scala +++ b/tests/run/tasty-macro-const/quoted_1.scala @@ -11,10 +11,10 @@ object Macros { xTree match { case Inlined(_, _, Literal(Constant.Int(n))) => if (n <= 0) - throw new QuoteError("Parameter must be natural number") + QuoteError("Parameter must be natural number") xTree.seal.cast[Int] case _ => - throw new QuoteError("Parameter must be a known constant") + QuoteError("Parameter must be a known constant") } } diff --git a/tests/run/tuples1b.check b/tests/run/tuples1b.check new file mode 100644 index 000000000000..0ceda1af9e45 --- /dev/null +++ b/tests/run/tuples1b.check @@ -0,0 +1,4 @@ +0 +(1) +0 +() \ No newline at end of file diff --git a/tests/run/tuples1b.scala b/tests/run/tuples1b.scala new file mode 100644 index 000000000000..f90f7c00e3bd --- /dev/null +++ b/tests/run/tuples1b.scala @@ -0,0 +1,12 @@ +object Test extends App { + def x[T](xs: (T, T)): T = xs.head + def x1[T](xs: (T, T)): Tuple1[T] = xs.tail + def x2[T](xs: (T, T)): T = xs(0) + def x3[T](xs: (T, T)): Unit = xs(0) + + println(x((0,1))) + println(x1((0,1))) + println(x2((0,1))) + println(x3((0,1))) + +} diff --git a/tests/run/xml-interpolation-1/XmlQuote_1.scala b/tests/run/xml-interpolation-1/XmlQuote_1.scala index 38506222fb0c..e11108cb0d4d 100644 --- a/tests/run/xml-interpolation-1/XmlQuote_1.scala +++ b/tests/run/xml-interpolation-1/XmlQuote_1.scala @@ -18,7 +18,7 @@ object XmlQuote { import reflect._ def abort(msg: String): Nothing = - throw new QuoteError(msg) + QuoteError(msg) // for debugging purpose def pp(tree: Tree): Unit = {