Skip to content

No Labels found when Summoning Mirror and Passing to a Splice #8007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
deusaquilus opened this issue Jan 15, 2020 · 4 comments
Closed

No Labels found when Summoning Mirror and Passing to a Splice #8007

deusaquilus opened this issue Jan 15, 2020 · 4 comments
Assignees

Comments

@deusaquilus
Copy link
Contributor

minimized code

  // Summon a mirror for a particular type 
  inline def summonMirror[T]: Option[Mirror.Of[T]] =
    summonFrom {
      case given m: Mirror.Of[T] => Some(m)
      case _ => None
    }

  // Get fields from a mirror:
  inline def mirrorFields[Fields <: Tuple]: List[String] = 
    inline erasedValue[Fields] match {
      case _: (field *: fields) => constValue[field].toString :: mirrorFields[fields]
      case _ => Nil
    }

  inline def usingSummonFrom[T](value: =>T): String = 
    ${ usingSummonFromImpl('value, summonMirror[T]) }

  def usingSummonFromImpl[T: Type](value: Expr[T], m: Option[Mirror.Of[T]])(given qctx: QuoteContext): Expr[String] = {
    import qctx.tasty.{_, given}
    val theMirror = m match { case Some(mirror) => mirror }

    theMirror match {
      case m: Mirror.ProductOf[T] => println("it's a product: " + mirrorFields[m.MirroredElemLabels])
    }

    '{ "Doesn't matter" }
  }

expectation

Say we have a case class Person(name: String, age :Int), the fields List("name", "age") should be returned. Instead, the mirror contains no fields.

@deusaquilus
Copy link
Contributor Author

I am trying to minimize this code but if I try to just returned the summoned mirror like this:

  def usingSummonFromImpl[T: Type](value: Expr[T], m: Option[Mirror.Of[T]])(given qctx: QuoteContext): Expr[Mirror.Of[T]] = {
    import qctx.tasty.{_, given}
    val theMirror = m match { case Some(mirror) => mirror }
    Expr(theMirror)
  }

I run into the following error:

[error] -- Error: /home/alexander/git/dotty/dotty_test/src/main/scala/derivation/SummonJsonEncoderTest.scala:26:19 
[error] 26 |    Expr(theMirror)
[error]    |                   ^
[error]    |no implicit argument of type quoted.Liftable[
[error]    |  scala.deriving.Mirror{
[error]    |    MirroredType = T; MirroredMonoType = T; MirroredElemTypes <: Tuple
[error]    |  }
[error]    |] was found for an implicit parameter of method apply in object Expr.
[error]    |I found:
[error]    |
[error]    |    quoted.Liftable.DoubleIsLiftable[Nothing]
[error]    |
[error]    |But method DoubleIsLiftable in object Liftable does not match type quoted.Liftable[
[error]    |  scala.deriving.Mirror{
[error]    |    MirroredType = T; MirroredMonoType = T; MirroredElemTypes <: Tuple
[error]    |  }
[error]    |].

Is there a way to wrap this mirror into an Expr and return it directly?

@biboudis
Copy link
Contributor

Thanks for reporting this (these are super useful reports, keep them coming because they combine features). Just a small note: apart from minimisation it is super useful if we also get the imports, the enclosing objects and the main method code. We can quickly identity and turn this into either a pos, neg, or run test.

Regarding the error I didn't solve it but I have some observations:

Initially, my reaction was that List() would be the right answer due to case _ => Nil in mirrorFields. After changing it to case _: Unit => Nil I started getting an irreducible match.

cannot reduce inline match with
   |                            scrutinee:  scala.compiletime.erasedValue[m.MirroredElemTypes] : m.MirroredElemTypes
   |                            patterns :  case _:*:[field @ _, fields @ _]
   |                                        case _:Unit

The documented way to summon a given is with summonExpr inside macros. I don't know how this pattern with summonMirror inside the top-level splice is intended to work (@nicolasstucki will provide insight here) so I proceeded with trying to reach to a workaround with summonExpr. Consequently, I used this structure (as we discussed here: #7974 (comment)) but unfortunately I couldn't splice the mirror successfully. I wanted to effectively achieve this:

case '{$m: Mirror.ProductOf[T]} => "it's a product: " + mirrorFields[$m.MirroredElemLabels]

I added the test and will continue the investigation #8011

@biboudis biboudis self-assigned this Jan 15, 2020
@deusaquilus
Copy link
Contributor Author

deusaquilus commented Jan 16, 2020

@biboudis I'm assuming that m and not $m in mirrorFields[$m.MirroredElemLabels]. My main point is that I need some way to effectively summon mirrors inside of macros. If your approach above worked I could use that instead of my approach with summonMirror (I actually like it more since with yours I can get any mirror I want in the macro as opposed to being forced to pass them in).

@biboudis
Copy link
Contributor

biboudis commented Jan 17, 2020

#8011 demonstrates the workaround/solution to this problem

biboudis added a commit that referenced this issue Jan 24, 2020
Fix #8007: Add regression and show type class derivation with macros
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants