summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-08-17 11:50:01 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-08-17 11:57:18 +0200
commitddf27a1e0e4b9eae521651704e74298c33c9af6c (patch)
tree4d1adea4ffa6cd520e71c6997c6a69264acf0291 /src/compiler/scala/tools/nsc/typechecker
parent78f9ef3906c78413ff8835fdad3849bfe5516be2 (diff)
downloadscala-ddf27a1e0e4b9eae521651704e74298c33c9af6c.tar.gz
scala-ddf27a1e0e4b9eae521651704e74298c33c9af6c.tar.bz2
scala-ddf27a1e0e4b9eae521651704e74298c33c9af6c.zip
more cleanup for typedMacroBody
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala209
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala214
2 files changed, 186 insertions, 237 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index f6785b6541..5a110739cd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -16,6 +16,7 @@ trait ContextErrors {
import global._
import definitions._
+ import treeInfo._
object ErrorKinds extends Enumeration {
type ErrorKind = Value
@@ -429,8 +430,11 @@ trait ContextErrors {
def AbstractionFromVolatileTypeError(vd: ValDef) =
issueNormalTypeError(vd, "illegal abstraction from value with volatile type "+vd.symbol.tpe)
+ private[ContextErrors] def TypedApplyWrongNumberOfTpeParametersErrorMessage(fun: Tree) =
+ "wrong number of type parameters for "+treeSymTypeMsg(fun)
+
def TypedApplyWrongNumberOfTpeParametersError(tree: Tree, fun: Tree) = {
- issueNormalTypeError(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ issueNormalTypeError(tree, TypedApplyWrongNumberOfTpeParametersErrorMessage(fun))
setError(tree)
}
@@ -755,21 +759,24 @@ trait ContextErrors {
kindErrors.toList.mkString("\n", ", ", ""))
}
- def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type],
- tparams: List[Symbol], kindErrors: List[String]) = {
- if (settings.explaintypes.value) {
+ private[ContextErrors] def NotWithinBoundsErrorMessage(prefix: String, targs: List[Type], tparams: List[Symbol], explaintypes: Boolean) = {
+ if (explaintypes) {
val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds)
(targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ))
(targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi))
()
}
- issueNormalTypeError(tree,
- prefix + "type arguments " + targs.mkString("[", ",", "]") +
- " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
- (tparams map (_.defString)).mkString("[", ",", "]"))
+ prefix + "type arguments " + targs.mkString("[", ",", "]") +
+ " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
+ (tparams map (_.defString)).mkString("[", ",", "]")
}
+ def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type],
+ tparams: List[Symbol], kindErrors: List[String]) =
+ issueNormalTypeError(tree,
+ NotWithinBoundsErrorMessage(prefix, targs, tparams, settings.explaintypes.value))
+
//substExpr
def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) =
issueNormalTypeError(tree,
@@ -1093,144 +1100,115 @@ trait ContextErrors {
// using an exception here is actually a good idea
// because the lifespan of this exception is extremely small and controlled
// moreover exceptions let us avoid an avalanche of "if (!hasError) do stuff" checks
- case class MacroBodyTypecheckException() extends Exception
+ case object MacroBodyTypecheckException extends Exception with scala.util.control.ControlThrowable
trait MacroErrors {
self: MacroTyper =>
- implicit val context = typer.context
+ private implicit val context0 = typer.context
+ val context = typer.context
+
+ // helpers
+
+ private def lengthMsg(flavor: String, violation: String, extra: Symbol) = {
+ val noun = if (flavor == "value") "parameter" else "type parameter"
+ val message = noun + " lists have different length, " + violation + " extra " + noun
+ val suffix = if (extra ne NoSymbol) " " + extra.defString else ""
+ message + suffix
+ }
+
+ private def abbreviateCoreAliases(s: String): String = List("AbsTypeTag", "Expr").foldLeft(s)((res, x) => res.replace("c.universe." + x, "c." + x))
- def fail() = {
+ private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = {
+ var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString
+ if (abbreviate) argsPart = abbreviateCoreAliases(argsPart)
+ var retPart = restpe.toString
+ if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart)
+ argsPart + ": " + retPart
+ }
+
+ // not exactly an error generator, but very related
+ // and I dearly wanted to push it away from Macros.scala
+ private def checkSubType(slot: String, rtpe: Type, atpe: Type) = {
+ val ok = if (macroDebugVerbose || settings.explaintypes.value) {
+ if (rtpe eq atpe) println(rtpe + " <: " + atpe + "?" + EOL + "true")
+ withTypesExplained(rtpe <:< atpe)
+ } else rtpe <:< atpe
+ if (!ok) {
+ compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, abbreviateCoreAliases(rtpe.toString), abbreviateCoreAliases(atpe.toString)))
+ }
+ }
+
+ // errors
+
+ private def fail() = {
// need to set the IS_ERROR flag to prohibit spurious expansions
if (macroDef != null) macroDef setFlag IS_ERROR
// not setting ErrorSymbol as in `infer.setError`, because we still need to know that it's a macro
// otherwise assignTypeToTree in Namers might fail if macroDdef.tpt == EmptyTree
macroDdef setType ErrorType
- throw MacroBodyTypecheckException()
+ throw MacroBodyTypecheckException
}
- def MacroDefIsHardwired() = {
- macroLogVerbose("typecheck terminated unexpectedly: macro is hardwired")
- assert(!macroDdef.tpt.isEmpty, "hardwired macros must provide result type")
- throw MacroBodyTypecheckException()
+ private def genericError(tree: Tree, message: String) = {
+ issueNormalTypeError(tree, message)
+ fail()
}
- def MacroFeatureNotEnabled() = {
- macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled")
- macroDef setFlag IS_ERROR
- throw MacroBodyTypecheckException()
- }
+ private def implRefError(message: String) = genericError(methPart(macroDdef.rhs), message)
- def MacroDefUntypeableBodyError() = {
- // do nothing, just fail
- // relevant typecheck errors have already been reported
- fail()
- }
+ private def compatibilityError(message: String) =
+ implRefError(
+ "macro implementation has wrong shape:"+
+ "\n required: " + showMeth(rparamss, rret, abbreviate = true) +
+ "\n found : " + showMeth(aparamss, aret, abbreviate = false) +
+ "\n" + message)
- def MacroDefInvalidBodyError() = {
- issueNormalTypeError(macroDdef,
- "macro body has wrong shape:" +
- "\n required: macro [<implementation object>].<method name>[[<type args>]]")
- fail()
- }
+ // Phase I: sanity checks
- def MacroImplNotPublicError() = {
- issueNormalTypeError(macroDdef.rhs, "macro implementation must be public")
- fail()
+ def MacroDefIsFastTrack() = {
+ macroLogVerbose("typecheck terminated unexpectedly: macro is fast track")
+ assert(!macroDdef.tpt.isEmpty, "fast track macros must provide result type")
+ throw MacroBodyTypecheckException // don't call fail, because we don't need IS_ERROR
}
- def MacroImplOverloadedError() = {
- issueNormalTypeError(macroDdef.rhs, "macro implementation cannot be overloaded")
+ def MacroFeatureNotEnabled() = {
+ macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled")
fail()
}
- def MacroImplNeedsTypeArgumentsError() = {
- issueNormalTypeError(macroDdef.rhs, "macro implementation reference needs type arguments")
- fail()
- }
+ // Phase II: typecheck the right-hand side of the macro def
- def MacroImplDoesntNeedTypeArgumentsError() = {
- issueNormalTypeError(macroDdef.rhs, "macro implementation reference doesn't need type arguments")
- fail()
- }
+ // do nothing, just fail. relevant typecheck errors have already been reported
+ def MacroDefUntypeableBodyError() = fail()
- def MacroImplNotStaticError() = {
- issueNormalTypeError(macroDdef.rhs, "macro implementation must be in statically accessible object")
- fail()
- }
+ def MacroDefInvalidBodyError() = genericError(macroDdef, "macro body has wrong shape:\n required: macro [<implementation object>].<method name>[[<type args>]]")
- // prohibit implicit params on macro implementations
- // we don't have to do this, but it appears to be more clear than allowing them
- def MacroImplNonTagImplicitParameters(params: List[Symbol]) = {
- issueSymbolTypeError(params.head, "macro implementations cannot have implicit parameters other than AbsTypeTag evidences")
- fail()
- }
+ def MacroImplNotPublicError() = implRefError("macro implementation must be public")
- private def abbreviateCoreAliases(s: String): String = {
- var result = s
- result = result.replace("c.universe.AbsTypeTag", "c.AbsTypeTag")
- result = result.replace("c.universe.Expr", "c.Expr")
- result
- }
+ def MacroImplOverloadedError() = implRefError("macro implementation cannot be overloaded")
- private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = {
- var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString
- if (abbreviate) argsPart = abbreviateCoreAliases(argsPart)
- var retPart = restpe.toString
- if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart)
- argsPart + ": " + retPart
- }
+ def MacroImplWrongNumberOfTypeArgumentsError(macroImplRef: Tree) = implRefError(typer.TyperErrorGen.TypedApplyWrongNumberOfTpeParametersErrorMessage(macroImplRef))
- private def compatibilityError(message: String) = {
- issueNormalTypeError(macroDdef.rhs,
- "macro implementation has wrong shape:"+
- "\n required: " + showMeth(rparamss, rret, abbreviate = true) +
- "\n found : " + showMeth(aparamss, aret, abbreviate = false) +
- "\n" + message)
- fail()
- }
+ def MacroImplNotStaticError() = implRefError("macro implementation must be in statically accessible object")
- def MacroImplParamssMismatchError() = {
- compatibilityError("number of parameter sections differ")
- }
+ // Phase III: check compatibility between the macro def and its macro impl
+ // aXXX (e.g. aparams) => characteristics of the macro impl ("a" stands for "actual")
+ // rXXX (e.g. rparams) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference")
- private def lengthMsg(which: String, extra: Symbol) = {
- "parameter lists have different length, " + which + " extra parameter " + extra.defString
- }
+ def MacroImplNonTagImplicitParameters(params: List[Symbol]) = compatibilityError("macro implementations cannot have implicit parameters other than AbsTypeTag evidences")
- def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = {
- compatibilityError(lengthMsg("found", aparams(rparams.length)))
- }
+ def MacroImplParamssMismatchError() = compatibilityError("number of parameter sections differ")
- def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = {
- compatibilityError(abbreviateCoreAliases(lengthMsg("required", rparams(aparams.length))))
- }
+ def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(lengthMsg("value", "found", aparams(rparams.length)))
- // not exactly an error generator, but very related
- // and I dearly wanted to push it away from Macros.scala
- def checkSubType(slot: String, rtpe: Type, atpe: Type) = {
- val ok = if (macroDebugVerbose) {
- if (rtpe eq atpe) println(rtpe + " <: " + atpe + "?" + EOL + "true")
- withTypesExplained(rtpe <:< atpe)
- } else rtpe <:< atpe
- if (!ok) {
- compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, abbreviateCoreAliases(rtpe.toString), abbreviateCoreAliases(atpe.toString)))
- }
- }
+ def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(abbreviateCoreAliases(lengthMsg("value", "required", rparams(aparams.length))))
- def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = {
- checkSubType("parameter " + rparam.name, rparam.tpe, atpe)
- }
+ def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = checkSubType("parameter " + rparam.name, rparam.tpe, atpe)
- def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = {
- checkSubType("return type", atpe, rret)
- }
+ def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = checkSubType("return type", atpe, rret)
- def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = {
- // in the error message rparamss come first
- // hence rparam should also come first if possible
- compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name)
- }
+ def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name)
def MacroImplVarargMismatchError(aparam: Symbol, rparam: Symbol) = {
if (isRepeated(rparam) && !isRepeated(aparam))
@@ -1239,17 +1217,12 @@ trait ContextErrors {
compatibilityError("types incompatible for parameter " + aparam.name + ": corresponding is not a vararg parameter")
}
- def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) = {
- val bounds = atparams map (tp => tp.info.instantiateTypeParams(atparams, atargs).bounds)
- compatibilityError("type arguments " + atargs.mkString("[", ",", "]") +
- " do not conform to " + atparams.head.owner + "'s type parameter bounds " +
- (atparams map (_.defString)).mkString("[", ",", "]"))
- }
+ def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) =
+ compatibilityError(typer.infer.InferErrorGen.NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value))
- def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) = {
+ def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) =
compatibilityError(
"type parameters "+(atparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+
ex.getMessage)
- }
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 2c8af627d0..1b75d822d4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -24,7 +24,7 @@ import scala.reflect.internal.util.Collections._
*
* Then fooBar needs to point to a static method of the following form:
*
- * def fooBar[T: c.AbsTypeTag]
+ * def fooBar[T: c.AbsTypeTag] // type tag annotation is optional
* (c: scala.reflect.macros.Context)
* (xs: c.Expr[List[T]])
* : c.Expr[T] = {
@@ -213,11 +213,86 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
MacroImplBinding.unpickle(pickle)
}
+ /** Transforms parameters lists of a macro impl.
+ * The `transform` function is invoked only for AbsTypeTag evidence parameters.
+ *
+ * The transformer takes two arguments: a value parameter from the parameter list
+ * and a type parameter that is witnesses by the value parameter.
+ *
+ * If the transformer returns a NoSymbol, the value parameter is not included from the result.
+ * If the transformer returns something else, this something else is included in the result instead of the value parameter.
+ *
+ * Despite of being highly esoteric, this function significantly simplifies signature analysis.
+ * For example, it can be used to strip macroImpl.paramss from the evidences (necessary when checking def <-> impl correspondence)
+ * or to streamline creation of the list of macro arguments.
+ */
+ private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Symbol): List[List[Symbol]] = {
+ if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do
+ if (paramss.head.isEmpty || !(paramss.head.head.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do
+ def transformTag(param: Symbol): Symbol = param.tpe.dealias match {
+ case TypeRef(SingleType(SingleType(NoPrefix, c), universe), AbsTypeTagClass, targ :: Nil)
+ if c == paramss.head.head && universe == MacroContextUniverse =>
+ transform(param, targ.typeSymbol)
+ case _ =>
+ param
+ }
+ val transformed = paramss.last map transformTag filter (_ ne NoSymbol)
+ if (transformed.isEmpty) paramss.init else paramss.init :+ transformed
+ }
+
+ def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroImpl: Symbol): Type = {
+ // Step I. Transform c.Expr[T] to T
+ var runtimeType = macroImpl.tpe.finalResultType.dealias match {
+ case TypeRef(_, ExprClass, runtimeType :: Nil) => runtimeType
+ case _ => AnyTpe // so that macro impls with rhs = ??? don't screw up our inference
+ }
+
+ // Step II. Transform type parameters of a macro implementation into type arguments in a macro definition's body
+ runtimeType = runtimeType.substituteTypes(macroImpl.typeParams, loadMacroImplBinding(macroDdef.symbol).targs.map(_.tpe))
+
+ // Step III. Transform c.prefix.value.XXX to this.XXX and implParam.value.YYY to defParam.YYY
+ def unsigma(tpe: Type): Type =
+ transformTypeTagEvidenceParams(macroImpl.paramss, (param, tparam) => NoSymbol) match {
+ case (implCtxParam :: Nil) :: implParamss =>
+ val implToDef = flatMap2(implParamss, macroDdef.vparamss)(map2(_, _)((_, _))).toMap
+ object UnsigmaTypeMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) =>
+ val pre1 = pre match {
+ case SingleType(SingleType(SingleType(NoPrefix, c), prefix), value) if c == implCtxParam && prefix == MacroContextPrefix && value == ExprValue =>
+ ThisType(macroDdef.symbol.owner)
+ case SingleType(SingleType(NoPrefix, implParam), value) if value == ExprValue =>
+ implToDef get implParam map (defParam => SingleType(NoPrefix, defParam.symbol)) getOrElse pre
+ case _ =>
+ pre
+ }
+ val args1 = args map mapOver
+ TypeRef(pre1, sym, args1)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ UnsigmaTypeMap(tpe)
+ case _ =>
+ tpe
+ }
+
+ unsigma(runtimeType)
+ }
+
/** A reference macro implementation signature compatible with a given macro definition.
*
- * In the example above:
+ * In the example above for the following macro def:
+ * def foo[T](xs: List[T]): T = macro fooBar
+ *
+ * This function will return:
* (c: scala.reflect.macros.Context)(xs: c.Expr[List[T]]): c.Expr[T]
*
+ * Note that type tag evidence parameters are not included into the result.
+ * Type tag context bounds for macro impl tparams are optional.
+ * Therefore compatibility checks ignore such parameters, and we don't need to bother about them here.
+ *
* @param macroDef The macro definition symbol
* @param tparams The type parameters of the macro definition
* @param vparamss The value parameters of the macro definition
@@ -283,53 +358,22 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
macroTraceVerbose("macroImplSig is: ")(paramss, implRetTpe)
}
- /** Transforms parameters lists of a macro impl.
- * The `transform` function is invoked only for AbsTypeTag evidence parameters.
- *
- * The transformer takes two arguments: a value parameter from the parameter list
- * and a type parameter that is witnesses by the value parameter.
- *
- * If the transformer returns a NoSymbol, the value parameter is not included from the result.
- * If the transformer returns something else, this something else is included in the result instead of the value parameter.
- *
- * Despite of being highly esoteric, this function significantly simplifies signature analysis.
- * For example, it can be used to strip macroImpl.paramss from the evidences (necessary when checking def <-> impl correspondence)
- * or to streamline creation of the list of macro arguments.
- */
- private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Symbol): List[List[Symbol]] = {
- if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do
- if (paramss.head.isEmpty || !(paramss.head.head.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do
- def transformTag(param: Symbol): Symbol = param.tpe.dealias match {
- case TypeRef(SingleType(SingleType(NoPrefix, c), universe), AbsTypeTagClass, targ :: Nil)
- if c == paramss.head.head && universe == MacroContextUniverse =>
- transform(param, targ.typeSymbol)
- case _ =>
- param
- }
- val transformed = paramss.last map transformTag filter (_ ne NoSymbol)
- if (transformed.isEmpty) paramss.init else paramss.init :+ transformed
- }
-
- /** As specified above, body of a macro definition must reference its implementation.
- * This function verifies that the body indeed refers to a method, and that
- * the referenced macro implementation is compatible with the given macro definition.
- *
- * This means that macro implementation (fooBar in example above) must:
- * 1) Refer to a statically accessible, non-overloaded method.
- * 2) Have the right parameter lists as outlined in the SIP / in the doc comment of this class.
+ /** Verifies that the body of a macro def typechecks to a reference to a static public non-overloaded method,
+ * and that that method is signature-wise compatible with the given macro definition.
*
- * @return typechecked rhs of the given macro definition
+ * @return Typechecked rhs of the given macro definition if everything is okay.
+ * EmptyTree if an error occurs.
*/
def typedMacroBody(typer: Typer, macroDdef: DefDef): Tree =
try new MacroTyper(typer, macroDdef).typed
- catch { case MacroBodyTypecheckException() => EmptyTree }
+ catch { case MacroBodyTypecheckException => EmptyTree }
class MacroTyper(val typer: Typer, val macroDdef: DefDef) extends MacroErrors {
// Phase I: sanity checks
val macroDef = macroDdef.symbol
macroLogVerbose("typechecking macro def %s at %s".format(macroDef, macroDdef.pos))
assert(macroDef.isTermMacro, macroDdef)
- if (fastTrack contains macroDef) MacroDefIsHardwired()
+ if (fastTrack contains macroDef) MacroDefIsFastTrack()
if (!typer.checkFeature(macroDdef.pos, MacrosFeature, immediate = true)) MacroFeatureNotEnabled()
// we use typed1 instead of typed, because otherwise adapt is going to mess us up
@@ -377,15 +421,15 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
if (!meth.isMethod) MacroDefInvalidBodyError()
if (!meth.isPublic) MacroImplNotPublicError()
if (meth.isOverloaded) MacroImplOverloadedError()
- if (meth.typeParams.nonEmpty && targs.isEmpty) MacroImplNeedsTypeArgumentsError()
- if (meth.typeParams.isEmpty && targs.nonEmpty) MacroImplDoesntNeedTypeArgumentsError()
if (!owner.isStaticOwner && !owner.moduleClass.isStaticOwner) MacroImplNotStaticError()
+ if (meth.typeParams.length != targs.length) MacroImplWrongNumberOfTypeArgumentsError(typed)
bindMacroImpl(macroDef, typed)
case _ =>
MacroDefInvalidBodyError()
}
// Phase III: check compatibility between the macro def and its macro impl
+ // this check ignores type tag evidence parameters, because type tag context bounds are optional
// aXXX (e.g. aparamss) => characteristics of the macro impl ("a" stands for "actual")
// rXXX (e.g. rparamss) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference")
val macroImpl = typed.symbol
@@ -432,74 +476,6 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
}
}
- def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroImpl: Symbol): Type = {
- // downgrade from metalevel-0 to metalevel-1
- var runtimeType = macroImpl.tpe.finalResultType.dealias match {
- case TypeRef(_, ExprClass, runtimeType :: Nil) => runtimeType
- case _ => AnyTpe
- }
-
- // transform type parameters of a macro implementation into type parameters of a macro definition
- runtimeType = runtimeType map {
- case TypeRef(pre, sym, args) =>
- // sym.paramPos is unreliable (see an example in `macroArgs`)
- val tparams = macroImpl.typeParams map (_.deSkolemize)
- val paramPos = tparams indexOf sym.deSkolemize
- val sym1 =
- if (paramPos == -1) sym
- else loadMacroImplBinding(macroDdef.symbol).targs(paramPos).tpe.typeSymbol
- TypeRef(pre, sym1, args)
- case tpe =>
- tpe
- }
-
- // as stated in the spec, before being matched to macroimpl, type and value parameters of macrodef
- // undergo a special transformation, sigma, that adapts them to the different metalevel macroimpl lives in
- // as a result, we need to reverse this transformation when inferring macrodef ret from macroimpl ret
- def unsigma(tpe: Type): Type = {
- // unfortunately, we cannot dereference ``paramss'', because we're in the middle of inferring a type for ``macroDdef''
-// val defParamss = macroDdef.symbol.paramss
- val defParamss = mmap(macroDdef.vparamss)(_.symbol)
- var implParamss = macroImpl.paramss
- implParamss = transformTypeTagEvidenceParams(implParamss, (param, tparam) => NoSymbol)
-
- val implCtxParam = if (implParamss.nonEmpty && implParamss(0).nonEmpty) implParamss(0)(0) else null
- def implParamToDefParam(implParam: Symbol): Symbol = {
- val indices = (((implParamss drop 1).zipWithIndex) map { case (implParams, index) => (index, implParams indexOf implParam) } filter (_._2 != -1)).headOption
- val defParam = indices flatMap {
- case (plistIndex, pIndex) =>
- if (defParamss.length <= plistIndex) None
- else if (defParamss(plistIndex).length <= pIndex) None
- else Some(defParamss(plistIndex)(pIndex))
- }
- defParam.orNull
- }
-
- class UnsigmaTypeMap extends TypeMap {
- def apply(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) =>
- val pre1 = pre match {
- case SingleType(SingleType(SingleType(NoPrefix, param), prefix), value) if param == implCtxParam && prefix == MacroContextPrefix && value == ExprValue =>
- ThisType(macroDdef.symbol.owner)
- case SingleType(SingleType(NoPrefix, param), value) if implParamToDefParam(param) != null && value == ExprValue =>
- val macroDefParam = implParamToDefParam(param)
- SingleType(NoPrefix, macroDefParam)
- case _ =>
- pre
- }
- val args1 = args map mapOver
- TypeRef(pre1, sym, args1)
- case _ =>
- mapOver(tp)
- }
- }
-
- new UnsigmaTypeMap() apply tpe
- }
-
- unsigma(runtimeType)
- }
-
/** Macro classloader that is used to resolve and run macro implementations.
* Loads classes from from -cp (aka the library classpath).
* Is also capable of detecting REPL and reusing its classloader.
@@ -530,7 +506,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
* 4) Resolves macro implementation within the loaded companion.
*
* @return Requested runtime if macro implementation can be loaded successfully from either of the mirrors,
- * null otherwise.
+ * `null` otherwise.
*/
type MacroRuntime = List[Any] => Any
private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, MacroRuntime]
@@ -585,9 +561,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
/** Calculate the arguments to pass to a macro implementation when expanding the provided tree.
*
* This includes inferring the exact type and instance of the macro context to pass, and also
- * allowing for missing parameter sections in macro implementation (see ``macroImplParamsss'' for more info).
+ * allowing for missing parameter sections in macro implementation (see `macroImplParamsss` for more info).
*
- * @return list of runtime objects to pass to the implementation obtained by ``macroRuntime''
+ * @return list of runtime objects to pass to the implementation obtained by `macroRuntime`
*/
private def macroArgs(typer: Typer, expandee: Tree): Option[List[Any]] = {
val macroDef = expandee.symbol
@@ -643,8 +619,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
// val outer2 = new outer1.C[String]
// outer2.foo[Boolean]
//
- // then T and U need to be inferred from the lexical scope of the call using ``asSeenFrom''
- // whereas V won't be resolved by asSeenFrom and need to be loaded directly from ``expandee'' which needs to contain a TypeApply node
+ // then T and U need to be inferred from the lexical scope of the call using `asSeenFrom`
+ // whereas V won't be resolved by asSeenFrom and need to be loaded directly from `expandee` which needs to contain a TypeApply node
// also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
val tags = binding.signature filter (_ != -1) map (paramPos => {
val targ = binding.targs(paramPos).tpe.typeSymbol
@@ -688,14 +664,14 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
}
/** Keeps track of macros in-flight.
- * See more informations in comments to ``openMacros'' in ``scala.reflect.macros.Context''.
+ * See more informations in comments to `openMacros` in `scala.reflect.macros.Context`.
*/
var openMacros = List[MacroContext]()
def enclosingMacroPosition = openMacros map (_.macroApplication.pos) find (_ ne NoPosition) getOrElse NoPosition
/** Performs macro expansion:
- * 1) Checks whether the expansion needs to be delayed (see ``mustDelayMacroExpansion'')
- * 2) Loads macro implementation using ``macroMirror''
+ * 1) Checks whether the expansion needs to be delayed (see `mustDelayMacroExpansion`)
+ * 2) Loads macro implementation using `macroMirror`
* 3) Synthesizes invocation arguments for the macro implementation
* 4) Checks that the result is a tree bound to this universe
* 5) Typechecks the result against the return type of the macro definition
@@ -789,7 +765,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
Failure(expandee)
}
- /** Does the same as ``macroExpand'', but without typechecking the expansion
+ /** Does the same as `macroExpand`, but without typechecking the expansion
* Meant for internal use within the macro infrastructure, don't use it elsewhere.
*/
private def macroExpand1(typer: Typer, expandee: Tree): MacroExpansionResult =
@@ -1047,7 +1023,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
/** Performs macro expansion on all subtrees of a given tree.
* Innermost macros are expanded first, outermost macros are expanded last.
- * See the documentation for ``macroExpand'' for more information.
+ * See the documentation for `macroExpand` for more information.
*/
def macroExpandAll(typer: Typer, expandee: Tree): Tree =
new Transformer {