Skip to content
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

Add the possibility to type check the pattern of a case definition in a macro #7794

Closed
scabug opened this issue Aug 28, 2013 · 4 comments
Closed

Comments

@scabug
Copy link

scabug commented Aug 28, 2013

It would be nice to have a typeCheckPattern method in scala.reflect.macros.Context. Right now, none of the existing ways to determine the type of a tree works for patterns:

def macroImpl(c: Context)(...) = {
  ...
  val CaseDef(pattern, guard, body) = ...

  // null
  pattern.tpe

  // Throws TypeCheckException
  c.typeCheck(pattern)
}

Invoking the tpe method on a pattern always results in null, using the existing typeCheck function in the Context class throws a TypeCheckException. A full example is attached to this issue.

@scabug
Copy link
Author

scabug commented Aug 28, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7794?orig=1
Reporter: Martin Zuber (mzuber)
Affected Versions: 2.10.2
Attachments:

@scabug
Copy link
Author

scabug commented Sep 7, 2013

@xeno-by said:
The problem here is that typechecking pattern requires a special typechecker mode called PATTERNmode. In fact, there's a bunch of such modes that cover typechecking types, type constructors, super constructor calls, etc. Unfortunately, c.typeCheck works in EXPRmode and doesn't provide a way to customize it.

There are multiple ways to addressing this problem. The first one involves exposing a number of specialized typeCheckXXX methods, e.g. typeCheckExpr, typeCheckType, typeCheckPattern, etc. The second one implies introducing Mode and passing it as a parameter to c.typeCheck. I don't feel very comfortable with either of them (the first one means a bunch of new methods, the second one means another class in the reflection API), so I would like to defer this decision to the reflection API revamp that is supposedly happening in 2.12.

In the meanwhile, you can cast to internal APIs to work around the problem (please note that PATTERNmode requires a non-wildcard expected type - you can get it by typechecking the scrutinee of the pattern match):

import scala.reflect.macros.Context
import language.experimental.macros

object Macros {
  def impl(c: Context) = {
    import c.universe._
    val expr = q"List(1)"
    val texpr = c.typeCheck(expr)
    val pat = pq"List(1)"
    val tpat = {
      val g = c.universe.asInstanceOf[scala.tools.nsc.Global]
      val ty = c.asInstanceOf[scala.reflect.macros.contexts.Context].callsiteTyper.asInstanceOf[g.analyzer.Typer]
      val tpat = ty.typed(pat.asInstanceOf[g.Tree], scala.reflect.internal.Mode.PATTERNmode, g.typeOf[List[Int]])
      tpat.asInstanceOf[Tree]
    }
    println((texpr, tpat))
    c.literalUnit
  }

  def foo = macro impl
}

object Test extends App {
  println(Macros.foo)
}

12:38 ~/Projects/Master/sandbox (master)$ scalac Macros.scala && scalac Test.scala
(immutable.this.List.apply[Int](1),immutable.this.List.unapplySeq[Int](<unapply-selector>) <unapply> (1))

Would that work for you?

@scabug
Copy link
Author

scabug commented Sep 10, 2013

Martin Zuber (mzuber) said:
This will work for me, thank you for the hint.

@scabug
Copy link
Author

scabug commented Dec 11, 2013

@xeno-by said:
#6814

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