Skip to content

asExprOf fails for tuples larger than 22 #17257

Closed
@Katrix

Description

@Katrix

Compiler version

3.2.2

Minimized code

// file a.scala
inline def summonAllOptimized[T <: Tuple]: T =
  ${ summonAllOptimizedImpl[T] }

private def summonAllOptimizedImpl[T <: Tuple: Type](using q: Quotes): Expr[T] = {
  import q.reflect.*

  Expr
    .ofTupleFromSeq(typesOfTuple(TypeRepr.of[T], Nil).map { tpe =>
      tpe.asType match {
        case '[t] =>
          Expr.summon[t].getOrElse(report.errorAndAbort(s"Unable to to find implicit instance for ${tpe.show}"))
      }
    })
    .asExprOf[T]
}

@tailrec
private[derivation] def typesOfTuple(
    using q: Quotes
)(tpe: q.reflect.TypeRepr, acc: List[q.reflect.TypeRepr]): List[q.reflect.TypeRepr] =
  import q.reflect.*
  val cons = Symbol.classSymbol("scala.*:")
  tpe.widenTermRefByName.dealias match
    case AppliedType(fn, tpes) if defn.isTupleClass(fn.typeSymbol) =>
      tpes.reverse_:::(acc)
    case AppliedType(tp, List(headType, tailType)) if tp.derivesFrom(cons) =>
      typesOfTuple(tailType, headType :: acc)
    case tpe =>
      if tpe.derivesFrom(Symbol.classSymbol("scala.EmptyTuple")) then acc.reverse
      else report.errorAndAbort(s"Unknown type encountered in tuple ${tpe.show}")

//file b.scala
val test = Helpers.summonAllOptimized[(
    ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"],
    ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"],
    ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"],
    ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"], ValueOf["a"],
    ValueOf["a"], ValueOf["a"], ValueOf["a"] //Commenting out the last one here fixes the compile error
  )]

Output

[error]     |Exception occurred while executing macro expansion.
[error]     |java.lang.Exception: Expr cast exception: scala.Tuple.fromIArray[scala.Any](scala.IArray$package.IArray.apply[scala.Any](new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"), new scala.ValueOf["a"]("a"))(scala.reflect.ClassTag.Any))
[error]     |of type: scala.Tuple
[error]     |did not conform to type: scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.*:[scala.ValueOf["a"], scala.Tuple$package.EmptyTuple]]]]]]]]]]]]]]]]]]]]]]]
[error]     |
[error]     |   at scala.quoted.runtime.impl.QuotesImpl.asExprOf(QuotesImpl.scala:73)
[error]     |   at perspective.derivation.Helpers$.summonAllOptimizedImpl(Helpers.scala:157)
[error]     |   at perspective.derivation.Helpers$.inline$summonAllOptimizedImpl(Helpers.scala:147)

Expectatio

I would expect the above to work just like it works for tuples of size 22 or less, or that this was at least better communicated.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions