Permalink
Browse files

SI-5744 evidence params are now SYNTHETIC

The macro def <-> macro impl correspondence check compares names of the
corresponding parameters in def and impl and reports an error if they
don't match. This was originally designed to avoid confusion w.r.t named
arguments (which ended up being never implemented as described in SI-5920).

Sometimes parameter names are generated by the compiler, which puts the
user in a tough position. Luckily, there's an escape hatch built it, which
omits the name correspondence check if one of the parameters is SYNTHETIC.
Everything went well until we realized that evidences generated by
context bounds aren't SYNTHETIC, which led to the bug at hand.

Marking auto-generated evidence parameters SYNTHETIC was only the first
step, as the correspondence checker uses parameter symbols, not parameter
trees. Why's that a problem? Because SYNTHETIC doesn't get propagated from def
trees to their underlying symbols (see ValueParameterFlags).

Unfortunately one cannot just change ValueParameterFlags, because that
would break printouts generated in TypeDiagnostics, which is designed to not
print synthetic symbols. Thus we modify methodTypeErrorString in
TypeDiagnostics to always print synthetic symbols.

Therefore now we propagate all paramSym.flags when doing correspondent sweeps
to keep them in sync between def trees and their underlying symbols. This
fixes the problem.
  • Loading branch information...
1 parent 466fc67 commit 9d5d55bdf4e36489c249fe9736d53c8d12a9d7e5 @u-abramchuk u-abramchuk committed Feb 5, 2013
@@ -589,7 +589,7 @@ abstract class TreeBuilder {
if (contextBounds.isEmpty) vparamss
else {
val mods = Modifiers(if (owner.isTypeName) PARAMACCESSOR | LOCAL | PRIVATE else PARAM)
- def makeEvidenceParam(tpt: Tree) = ValDef(mods | IMPLICIT, freshTermName(nme.EVIDENCE_PARAM_PREFIX), tpt, EmptyTree)
+ def makeEvidenceParam(tpt: Tree) = ValDef(mods | IMPLICIT | SYNTHETIC, freshTermName(nme.EVIDENCE_PARAM_PREFIX), tpt, EmptyTree)
val evidenceParams = contextBounds map makeEvidenceParam
val vparamssLast = if(vparamss.nonEmpty) vparamss.last else Nil
@@ -333,9 +333,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
def param(tree: Tree): Symbol =
paramCache.getOrElseUpdate(tree.symbol, {
val sym = tree.symbol
- val sigParam = makeParam(sym.name, sym.pos, implType(sym.isType, sym.tpe))
- if (sym.isSynthetic) sigParam.flags |= SYNTHETIC
- sigParam
+ makeParam(sym.name, sym.pos, implType(sym.isType, sym.tpe), sym.flags)
})
val paramss = List(ctxParam) :: mmap(vparamss)(param)
@@ -111,14 +111,9 @@ trait TypeDiagnostics {
"\n(Note that variables need to be initialized to be defined)"
else ""
- /** Only prints the parameter names if they're not synthetic,
- * since "x$1: Int" does not offer any more information than "Int".
- */
private def methodTypeErrorString(tp: Type) = tp match {
case mt @ MethodType(params, resultType) =>
- def forString =
- if (params exists (_.isSynthetic)) params map (_.tpe)
- else params map (_.defString)
+ def forString = params map (_.defString)
forString.mkString("(", ",", ")") + resultType
case x => x.toString
@@ -274,7 +274,7 @@ class Flags extends ModifierFlags {
* from Modifiers. Others which may be applied at creation time are:
* SYNTHETIC.
*/
- final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM | STABLE
+ final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM | STABLE | SYNTHETIC
final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC
final val VarianceFlags = COVARIANT | CONTRAVARIANT
@@ -0,0 +1,22 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.Context
+
+object Macros {
+ def foo[U: Numeric](x: U) = macro foo_impl[U]
+ def bar[U: Numeric : Equiv, Y <% String](x: U)(implicit s: String) = macro bar_impl[U, Y]
+
+ def foo_impl[U](c: Context)(x: c.Expr[U])(numeric: c.Expr[Numeric[U]]) = {
+ import c.universe._
+ val plusOne = Apply(Select(numeric.tree, newTermName("plus")), List(x.tree, Literal(Constant(1))))
+ val body = Apply(Select(Ident(definitions.PredefModule), newTermName("println")), List(plusOne))
+ c.Expr[Unit](body)
+ }
+
+ def bar_impl[U, Y](c: Context)(x: c.Expr[U])(numeric: c.Expr[Numeric[U]], equiv: c.Expr[Equiv[U]], viewAsString: c.Expr[Y => String], s: c.Expr[String]) = {
+ import c.universe._
+ val plusOne = Apply(Select(numeric.tree, newTermName("plus")), List(x.tree, Literal(Constant(1))))
+ val plusLen = Apply(Select(numeric.tree, newTermName("plus")), List(plusOne, Select(s.tree, newTermName("length"))))
+ val body = Apply(Select(Ident(definitions.PredefModule), newTermName("println")), List(plusLen))
+ c.Expr[Unit](body)
+ }
+}
@@ -0,0 +1,6 @@
+object Test extends App {
+ import Macros._
+ foo(42)
+ implicit val s = ""
+ bar(43)
+}

0 comments on commit 9d5d55b

Please sign in to comment.