Skip to content

Macro expansion exception related to Select #5786

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
liufengyun opened this issue Jan 24, 2019 · 1 comment
Closed

Macro expansion exception related to Select #5786

liufengyun opened this issue Jan 24, 2019 · 1 comment

Comments

@liufengyun
Copy link
Contributor

The following macro throws exception at expansion time. The code that is culprit is the 2nd case where we used Term.Select.copy.

The usage of the method Term.Select.copy is a walkaround because we lack proper constructors for select (#5567 ).

import scala.quoted._
import scala.tasty._

object scalatest {

  inline def assert(condition: => Boolean): Unit = ~assertImpl('(condition), '(""))

  def assertImpl(cond: Expr[Boolean], clue: Expr[Any])(implicit refl: Reflection): Expr[Unit] = {
    import refl._
    import util._
    import quoted.Toolbox.Default._

    def isImplicitMethodType(tp: Type): Boolean =
      Type.IsMethodType.unapply(tp).flatMap(tp => if tp.isImplicit then Some(true) else None).nonEmpty

    cond.unseal.underlyingArgument match {
      case Term.Apply(sel @ Term.Select(lhs, op), rhs :: Nil) =>
        val Term.IsSelect(select) = sel
        val cond = Term.Apply(Term.Select.copy(select)(lhs, ">"), rhs :: Nil).seal[Boolean]
        '{ scala.Predef.assert(~cond) }
      case Term.Apply(f @ Term.Apply(Term.IsSelect(sel @ Term.Select(Term.Apply(qual, lhs :: Nil), op)), rhs :: Nil), implicits)
      if isImplicitMethodType(f.tpe) =>
        let(lhs) { left =>
          let(rhs) { right =>
            let(Term.Apply(Term.Apply(Term.Select.copy(sel)(Term.Apply(qual, left :: Nil), op), right :: Nil), implicits)) { result =>
              val b = result.seal[Boolean]
              val code = '{ scala.Predef.assert(~b) }
              code.unseal
            }
          }
        }.seal[Unit]

      case _ =>
        '{ scala.Predef.assert(~cond) }
    }
  }

  inline def thisLineNumber = ~thisLineNumberImpl

  def thisLineNumberImpl(implicit refl: Reflection): Expr[Int] = {
    import refl._
    refl.rootPosition.startLine.toExpr
  }
}
object Test {
  import scalatest._

  trait EqInt
  implicit val eq: EqInt = new EqInt {}

  implicit class IntOps(x: Int) {
    def === (y: Int)(implicit c: EqInt) = x == y
  }

  def main(args: Array[String]): Unit = {
    val a: Int = 100
    assert(a === 5)
  }
}
@liufengyun
Copy link
Contributor Author

This is a wrong minimalization, close for now.

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