question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

quotes.reflect.memberType can return ClassInfo

See original GitHub issue

Discussed in https://github.com/lampepfl/dotty/discussions/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?

<div type='discussions-op-text'>

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?</div>

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:12 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
adamwcommented, May 14, 2022

@nicolasstucki does this mean that .memberType shouldn’t be used when trying to get the TypeRepr of a symbol obtained via Symbol.children? If it shouldn’t, what’s the correct way to do this?

My use-case is trying to get the types of implementations of a sealed trait in order to summon typeclass instances for them.

0reactions
sirthiascommented, Jul 14, 2022

Thank you, @nicolasstucki, for the pointer to that page! With the help of that example I was able to replace the complicated @jsoniter snippet with a much cleaner and simpler implementation, that does exactly what I need:

def adtChildren(tpe: TypeRepr): List[TypeRepr] =
  tpe.asType match
    case '[t] =>
      Expr.summon[Mirror.Of[t]].toList.flatMap {
        case '{ $m: Mirror.SumOf[t] { type MirroredElemTypes = subs } } => typeReprsOf[subs]
        case x                                                          => Nil
      }

def typeReprsOf[Ts: Type]: List[TypeRepr] =
  Type.of[Ts] match
    case '[EmptyTuple] => Nil
    case '[t *: ts]    => TypeRepr.of[t] :: typeReprsOf[ts]

No need for a call to tpe.typeSymbol.children anymore. 👍

Read more comments on GitHub >

github_iconTop Results From Across the Web

scala - Is it possible to match a quoted type of a sum type?
A.memberType(childSymbol).asType match { case '[f] => Expr.summon[BarOf[f]] }. Complete Functional Code : package bar import scala.quoted.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found