From the context of a Scala 3 Macro:
def aMacroImpl[T](using Type[T], Quotes): Expr[SpecialMap[_, _, _]] = {
import quotes.reflect._
val TRepr: TypeRepr = TypeRepr.of[T]
val TSym: Symbol = TRepr.typeSymbol
val SrtdMapSym: Symbol = TypeRepr.of[scala.collection.SortedMap].typeSymbol
TSym.declaredFields.map{ f => TRepr.memberType(f) }.collect {
case fieldTyepRepr if fieldTyepRepr.derivesFrom(SrtdMapSym) =>
val fieldType = Inferred(fieldTyepRepr).tpe.asType
fieldType match {
////////////////////////////////////////////////////////////
case ... => // <-- This line is the subject of the question.
////////////////////////////////////////////////////////////
'{SpecialMap.apply[k, v, sm](/* omitted for brevity*/)}
}
}
}
// More context.
object SpecialMap {
import scala.collection.mutable.Builder
def apply[K, V, SM <: SortedMap[K, V]](bldr: Builder[(K, V), SM]): SpecialMap[K, V, SM] = {
SpecialMap[K, V, SM](bldr.result)
}
}
case class SpecialMap[K, V, SM <: SortedMap[K, V]](wrapedMap: SM)
What kind of syntax can replace "..." in the code snippet above, that can match on the given SortedMap type such that it can retrieve all three type parameters: k, v, and sm?
The enquirer has already tried the following:
- Incomplete Solutions:
/*a*/ case '[sm] => // provides sm, but not k or v
/*b*/ case '[SortedMap[k, v]] => // provides k and v but not sm
- Direct Compiler errors:
/*a*/ case '[sm[k, v]] => // sm$given1.Underlying does not take type parameters
/*b*/ case '[_[k, v]] => // ']' expected, but '[' found
/*c*/ case 'sm[k, v] => /* symbol literal 'sm is no longer supported, use a string literal
"sm" or an application Symbol("sm") instead, or enclose in braces '{sm} if you want a
quoted expression. For now, you can also `import language.deprecated.symbolLiterals` to
accept the idiom, but this possibility might no longer be available in the future. */
/*d*/
import language.deprecated.symbolLiterals
fieldType match {
case 'sm[k, v] => // '=>' expected, but '[' found
/*e*/
type SM[k, v] = fieldType match { // Not found: type fieldType
case '[sm] => Type[sm]
case _ => quotes.reflect.report.errorAndAbort("uh oh")
}
/*h*/
case '[sm] =>
type SM[k1, v1] <: SortedMap[k1, v1] = Type[sm] // cannot combine bound and alias
/*f*/
case '[sm] =>
type SM = Type[sm]
fieldType match {
case '[SM[k, v]] => // SM does not take type parameters
- Subtle Compiler Errors:
// Examples in this snippet lose the association between k, v, sm, and SortedMap[k,v].
// All yield the following error:
// Type argument sm does not conform to upper bound collection.SortedMap[k, v]
/*a*/
case '[SortedMap[k, v]] =>
fieldType match {
case '[sm] if TypeRepr.of[sm].derivesFrom((TypeRepr.of[SortedMap[k, v]]).typeSymbol) =>
'{SpecialMap.apply[k, v, sm](/***/)} // ... sm does not conform ...
/*b*/
fieldType match {
case '[sm] =>
fieldType match {
case '[SortedMap[k, v]] if TypeRepr.of[sm].derivesFrom((TypeRepr.of[SortedMap[k, v]]).typeSymbol) =>
'{SpecialMap.apply[k, v, sm](/***/)} // ... sm does not conform ...
/*c*/
(fieldType, fieldType) match {
case ('[sm], '[SortedMap[k, v]]) =>
'{SpecialMap.apply[k, v, sm](/***/)} // ... sm does not conform ...
/*d*/
fieldType match {
case '[sm1] =>
type SM[k1,v1] = Type[sm1]
fieldType match {
case '[SM[k, v]] =>
'{SpecialMap.apply[k, v, SM[k, v]](/***/)} // ... SM does not conform ...
/*e*/
fieldType match {
case '[sm1] =>
fieldType match {
case '[SortedMap[k, v]] =>
type SM[k,v] = Type[sm1]
'{SpecialMap.apply[k, v, SM[k, v]](/***/)} // ... SM does not conform ...
Of course, explicitly writing every known concrete class derived from SortedMap works for any specific project, but libraries should accommodate unknown inheritors of the SortedMap trait.
Is there any way to capture all three type parameters along with their interdependent relationships?
Thank you for your consideration.