Closed
Description
Compiler version
3.4.0-RC1-bin-20240115-31f837e-NIGHTLY,
compiles successfully with 3.3.1
Minimized code
main.scala:
import scala.compiletime._
final class Greater[V]
final class Less[V]
// original codebase used non-transparent inlines in the defs below, but I think this would end up passing an abstract type parameter to the macro, so I don't think that should have worked (but transparent inlines should)
transparent inline given validatorForGreater[N: Numeric, NM <: N](using witness: ValueOf[NM]): ValidatorForPredicate[N, Greater[NM]] = ???
transparent inline given validatorForLess[N: Numeric, NM <: N](using witness: ValueOf[NM]): ValidatorForPredicate[N, Less[NM]] = ???
transparent inline def summonValidators[N, A <: Tuple]: List[ValidatorForPredicate[N, Any]] = {
inline erasedValue[A] match
case _: EmptyTuple => Nil
case _: (head *: tail) =>
summonInline[ValidatorForPredicate[N, head]]
.asInstanceOf[ValidatorForPredicate[N, Any]] :: summonValidators[N, tail]
}
transparent inline given validatorForAnd[N, Predicates](using mirror: IntersectionTypeMirror[Predicates]): ValidatorForPredicate[N, Predicates] =
new ValidatorForPredicate[N, Predicates] {
summonValidators[N, mirror.ElementTypes]
}
trait ValidatorForPredicate[Value, Predicate]
@main def main() = validatorForAnd[Int, Greater[1] & Less[3]]
macro.scala:
import scala.quoted.Quotes
import scala.annotation.implicitNotFound
import scala.quoted.*
import scala.collection.View.Empty
trait IntersectionTypeMirror[A] {
type ElementTypes <: Tuple
}
class IntersectionTypeMirrorImpl[A, T <: Tuple] extends IntersectionTypeMirror[A] {
override type ElementTypes = T
}
object IntersectionTypeMirror {
transparent inline given derived[A]: IntersectionTypeMirror[A] = ${ derivedImpl[A] }
private def derivedImpl[A](using Quotes, Type[A]): Expr[IntersectionTypeMirror[A]] = {
import quotes.reflect.*
val tplPrependType = TypeRepr.of[? *: ?]
val tplConcatType = TypeRepr.of[Tuple.Concat]
def prependTypes(head: TypeRepr, tail: TypeRepr): TypeRepr =
AppliedType(tplPrependType, List(head, tail))
def concatTypes(left: TypeRepr, right: TypeRepr): TypeRepr =
AppliedType(tplConcatType, List(left, right))
def rec(tpe: TypeRepr): TypeRepr = {
tpe.dealias match
case AndType(left, right) => concatTypes(rec(left), rec(right))
case t => prependTypes(t, TypeRepr.of[EmptyTuple])
}
val tupled =
TypeRepr.of[A].dealias match {
case and: AndType => rec(and).asType.asInstanceOf[Type[Elems]]
case tpe => report.errorAndAbort(s"${tpe.show} is not an intersection type")
}
type Elems
given Type[Elems] = tupled
Apply(
TypeApply(
Select.unique(
New(
Applied(
TypeTree.of[IntersectionTypeMirrorImpl],
List(
TypeTree.of[A],
TypeTree.of[Elems]
)
)
),
"<init>"
),
List(
TypeTree.of[A],
TypeTree.of[Elems]
)
),
Nil
).asExprOf[IntersectionTypeMirror[A]]
}
}
Output
[error] ./main.scala:22:20
[error] cannot reduce inline match with
[error] scrutinee: scala.compiletime.erasedValue[mirror$proxy1.ElementTypes] : mirror$proxy1.ElementTypes
[error] patterns : case _:EmptyTuple
[error] case _:*:[head @ _, tail @ _]
[error] @main def main() = validatorForAnd[Int, Greater[1] & Less[3]]
[error] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expectation
I think it should compile. The code used in tapir actually uses non-transparent inlines in code that calls transparent inlines, which I don't think should have worked, but did (probably because of the previous match types). But even after correcting that, the code errors with what seems to be an abstract type member.