-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Labels
area:metaprogramming:compiletimeThe scala.compiletime packageThe scala.compiletime packagearea:metaprogramming:reflectionIssues related to the quotes reflection APIIssues related to the quotes reflection APIitype:bug
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.
Metadata
Metadata
Assignees
Labels
area:metaprogramming:compiletimeThe scala.compiletime packageThe scala.compiletime packagearea:metaprogramming:reflectionIssues related to the quotes reflection APIIssues related to the quotes reflection APIitype:bug