Skip to content

Expr.summon does not work with imported givens from a class instance #11557

@deusaquilus

Description

@deusaquilus

Compiler version

3.0.0-RC1
also on 3.0.0-RC2-bin-20210227-07d9dd2-NIGHTLY

Minimized code

Create some kind of typeclass with an implementation inside of a class-instance

trait MyEncoder[T] {
  def encode(t: T): String
}

class MyContext {
  given intEncoder: MyEncoder[Int] = new MyEncoder[Int] { def encode(t: Int) = s"${t}" }
}

Then make a macro that summons this using Expr.summon.

object MyMacro {
  inline def getAndEncode[T](t: T): String = ${ getAndEncodeImpl('t) }
  def getAndEncodeImpl[T: Type](t: Expr[T])(using qctx: Quotes): Expr[String] = {
    import qctx.reflect._
    val enc = 
      Expr.summon[MyEncoder[T]] match
        case Some(enc) => enc
        case None => report.throwError("Can't find encoder")
    '{ $enc.encode($t) }
  }
}

Then import the context and use the macro:

  def doEncoding: Unit = {
    val ctx = new MyContext()
    import ctx.{*, given}
    println(MyMacro.getAndEncode(123))
  }

Output

Compilation fails, report error case "Can't find encoder" is hit.

[error] 15 |    println(MyMacro.getAndEncode(123))
[error]    |            ^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |            Can't find encoder

Expectation

Compile should work and the given should be correctly summoned.

Note that if instead of using a macro I use a regular method, it will work:

  def encodeIt[T](t: T)(using enc: MyEncoder[T]) = enc.encode(t)

  def doEncoding: Unit = {
    val ctx = new MyContext()
    import ctx.{*, given}
    println(encodeIt(123))
  }

Why the discrepancy?

Also, note that if you declare the given directly in the doEncoding method it will work:

  def doEncoding: Unit = {
    val ctx = new MyContext()
    given intEncoder: MyEncoder[Int] = new MyEncoder[Int] { def encode(t: Int) = s"${t}" }
    println(MyMacro.getAndEncode(123))
  }

Why the discrepancy?

Code

Full code sample is available here:
https://github.com/deusaquilus/expr_summon_issue

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions