Skip to content

quotes.reflect.memberType can return ClassInfo #15159

Open
@bishabosha

Description

@bishabosha

Discussed in #15157

in the example below, memberType returns a ClassInfo, which is not exposed in the quotes api, and seems unexpected when pattern matching on a type. It seems that memberType should escape this?

Originally posted by adamw May 10, 2022
I'm trying to summon a typeclass instance for each child class of a sealed trait. So far I've got the following code (here simplified):

import scala.quoted.*
object TestMacro:
  inline def test[T]: Unit = ${ testImpl[T] }
  def testImpl[T: Type](using Quotes): Expr[Unit] =
    import quotes.reflect.*
    val tpe = TypeRepr.of[T]
    tpe.typeSymbol.children.map { childSymbol =>
      val childTpe = tpe.memberType(childSymbol)
      println("Child TypeRepr: " + childTpe)
      childTpe.asType match
        case '[c] =>
          println("Got Type!")
    }
    '{ () }

The childTpe: TypeRepr is correct, however I get an exception when converting it to a Type and trying to get a handle to the type parameter c (so that later I can do Expr.summon[MyTypeClass[c]]). Using the following invocation:

sealed trait A
case class X(i: Int) extends A

object Test extends App {
  TestMacro.test[A]
}

The output is:

Child type: ClassInfo(ThisType(TypeRef(NoPrefix,module class newschema)), class X, List(TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class Object), TypeRef(ThisType(TypeRef(NoPrefix,module class newschema)),trait A), TypeRef(TermRef(TermRef(NoPrefix,object _root_),object scala),trait Product), TypeRef(ThisType(TypeRef(NoPrefix,module class io)),trait Serializable)))
[info] assertion failure for class X in package sttp.tapir.newschema <:< c, frozen = false
[error] -- Error: Test.scala:33:16
[error] 33 |  TestMacro.test[A]
[error]    |  ^^^^^^^^^^^^^^^^^
[error]    |Exception occurred while executing macro expansion.
[error]    |java.lang.AssertionError: assertion failed: ClassInfo(ThisType(TypeRef(NoPrefix,module class newschema)), class X, List(TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class Object), TypeRef(ThisType(TypeRef(NoPrefix,module class newschema)),trait A), TypeRef(TermRef(TermRef(NoPrefix,object _root_),object scala),trait Product), TypeRef(ThisType(TypeRef(NoPrefix,module class io)),trait Serializable)))
[error]    |	at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error]    |	at dotty.tools.dotc.core.Types$TypeBounds.<init>(Types.scala:5038)
[error]    |	at dotty.tools.dotc.core.Types$RealTypeBounds.<init>(Types.scala:5114)
[error]    |	at dotty.tools.dotc.core.Types$TypeBounds$.apply(Types.scala:5158)
[error]    |	at dotty.tools.dotc.core.Types$TypeBounds.derivedTypeBounds(Types.scala:5046)
[error]    |	at dotty.tools.dotc.core.ConstraintHandling.addOneBound(ConstraintHandling.scala:262)
[error]    |	at dotty.tools.dotc.core.ConstraintHandling.addOneBound$(ConstraintHandling.scala:29)
[error]    |	at dotty.tools.dotc.core.ProperGadtConstraint.addOneBound(GadtConstraint.scala:61)
[error]    |	at dotty.tools.dotc.core.ConstraintHandling.addBoundTransitively(ConstraintHandling.scala:316)
[error]    |	at dotty.tools.dotc.core.ConstraintHandling.addBoundTransitively$(ConstraintHandling.scala:29)
[error]    |	at dotty.tools.dotc.core.ProperGadtConstraint.addBoundTransitively(GadtConstraint.scala:61)
[error]    |	at dotty.tools.dotc.core.ProperGadtConstraint.addBound(GadtConstraint.scala:168)
[error]    |	at dotty.tools.dotc.core.TypeComparer.gadtAddLowerBound(TypeComparer.scala:116)
[error]    |	at dotty.tools.dotc.core.TypeComparer.narrowGADTBounds(TypeComparer.scala:1893)
[error]    |	at dotty.tools.dotc.core.TypeComparer.compareGADT$1(TypeComparer.scala:509)
[error]    |	at dotty.tools.dotc.core.TypeComparer.thirdTryNamed$1(TypeComparer.scala:512)
[error]    |	at dotty.tools.dotc.core.TypeComparer.thirdTry$1(TypeComparer.scala:561)
[error]    |	at dotty.tools.dotc.core.TypeComparer.secondTry$1(TypeComparer.scala:492)
[error]    |	at dotty.tools.dotc.core.TypeComparer.compareNamed$1(TypeComparer.scala:301)
[error]    |	at dotty.tools.dotc.core.TypeComparer.firstTry$1(TypeComparer.scala:307)
[error]    |	at dotty.tools.dotc.core.TypeComparer.recur(TypeComparer.scala:1309)
[error]    |	at dotty.tools.dotc.core.TypeComparer.isSubType(TypeComparer.scala:189)
[error]    |	at dotty.tools.dotc.core.TypeComparer.isSubType(TypeComparer.scala:199)
[error]    |	at dotty.tools.dotc.core.TypeComparer.topLevelSubType(TypeComparer.scala:126)
[error]    |	at dotty.tools.dotc.core.TypeComparer$.topLevelSubType(TypeComparer.scala:2709)
[error]    |	at dotty.tools.dotc.core.Types$Type.$less$colon$less(Types.scala:1040)
[error]    |	at scala.quoted.runtime.impl.QuoteMatcher$.$eq$qmark$eq(QuoteMatcher.scala:336)
[error]    |	at scala.quoted.runtime.impl.QuoteMatcher$.treeMatch(QuoteMatcher.scala:129)
[error]    |	at scala.quoted.runtime.impl.QuotesImpl.scala$quoted$runtime$impl$QuotesImpl$$treeMatch(QuotesImpl.scala:3051)
[error]    |	at scala.quoted.runtime.impl.QuotesImpl$TypeMatch$.unapply(QuotesImpl.scala:3021)

Is there a better (and working :) ) way to achieve the above goal?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions