summaryrefslogtreecommitdiff
path: root/src/compiler/scala/reflect
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-02-16 16:58:28 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-16 19:25:38 +0100
commit862f7709cdabd82327ca0f37a480884c88f96be7 (patch)
tree688717816eeee19ddb391f1009c82d9b6f09f224 /src/compiler/scala/reflect
parent2fc0164a5e777a0495c1801d8d38d60158ec2a77 (diff)
parent6ef6c96eff2f0d2f505d45a1436d73a960193076 (diff)
downloadscala-862f7709cdabd82327ca0f37a480884c88f96be7.tar.gz
scala-862f7709cdabd82327ca0f37a480884c88f96be7.tar.bz2
scala-862f7709cdabd82327ca0f37a480884c88f96be7.zip
Merge remote-tracking branch 'origin/master' into topic/palladium0
Conflicts: src/compiler/scala/reflect/macros/compiler/Resolvers.scala src/compiler/scala/reflect/macros/contexts/Typers.scala src/compiler/scala/tools/reflect/ToolBoxFactory.scala src/reflect/scala/reflect/api/BuildUtils.scala
Diffstat (limited to 'src/compiler/scala/reflect')
-rw-r--r--src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala68
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Errors.scala173
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Resolvers.scala78
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Validators.scala344
-rw-r--r--src/compiler/scala/reflect/macros/contexts/Typers.scala17
5 files changed, 364 insertions, 316 deletions
diff --git a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala
index 2e82e34bd9..1413065a27 100644
--- a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala
+++ b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala
@@ -8,6 +8,11 @@ abstract class DefaultMacroCompiler extends Resolvers
with Errors {
val global: Global
import global._
+ import analyzer._
+ import treeInfo._
+ import definitions._
+ val runDefinitions = currentRun.runDefinitions
+ import runDefinitions.{Predef_???, _}
val typer: global.analyzer.Typer
val context = typer.context
@@ -15,13 +20,72 @@ abstract class DefaultMacroCompiler extends Resolvers
val macroDdef: DefDef
lazy val macroDef = macroDdef.symbol
+ case class MacroImplRefCompiler(untypedMacroImplRef: Tree, isImplBundle: Boolean) extends Resolver with Validator with Error
private case class MacroImplResolutionException(pos: Position, msg: String) extends Exception
def abort(pos: Position, msg: String) = throw MacroImplResolutionException(pos, msg)
+ /** Resolves a macro impl reference provided in the right-hand side of the given macro definition.
+ *
+ * Acceptable shapes of the right-hand side:
+ * 1) [<static object>].<method name>[[<type args>]] // vanilla macro impl ref
+ * 2) [<macro bundle>].<method name>[[<type args>]] // shiny new macro bundle impl ref
+ *
+ * Produces a tree, which represents a reference to a macro implementation if everything goes well,
+ * otherwise reports found errors and returns EmptyTree. The resulting tree should have the following format:
+ *
+ * qualifier.method[targs]
+ *
+ * Qualifier here might be omitted (local macro defs), be a static object (vanilla macro defs)
+ * or be a dummy instance of a macro bundle (e.g. new MyMacro(???).expand).
+ */
def resolveMacroImpl: Tree = {
+ def tryCompile(compiler: MacroImplRefCompiler): scala.util.Try[Tree] = {
+ try { compiler.validateMacroImplRef(); scala.util.Success(compiler.macroImplRef) }
+ catch { case ex: MacroImplResolutionException => scala.util.Failure(ex) }
+ }
+ val vanillaImplRef = MacroImplRefCompiler(macroDdef.rhs.duplicate, isImplBundle = false)
+ val (maybeBundleRef, methName, targs) = macroDdef.rhs.duplicate match {
+ case Applied(Select(Applied(RefTree(qual, bundleName), _, Nil), methName), targs, Nil) =>
+ (RefTree(qual, bundleName.toTypeName), methName, targs)
+ case Applied(Ident(methName), targs, Nil) =>
+ (Ident(context.owner.enclClass), methName, targs)
+ case _ =>
+ (EmptyTree, TermName(""), Nil)
+ }
+ val bundleImplRef = MacroImplRefCompiler(
+ atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(maybeBundleRef, List(List(Ident(Predef_???)))), methName), targs)),
+ isImplBundle = true
+ )
+ val vanillaResult = tryCompile(vanillaImplRef)
+ val bundleResult = tryCompile(bundleImplRef)
+
+ def ensureUnambiguousSuccess() = {
+ // we now face a hard choice of whether to report ambiguity:
+ // 1) when there are eponymous methods in both bundle and object
+ // 2) when both references to eponymous methods are resolved successfully
+ // doing #1 would cause less confusion in the long run, but it would also cause more frequent source incompatibilities
+ // e.g. it would fail to compile https://github.com/ReifyIt/basis
+ // therefore here we go for #2
+ // if (vanillaImplRef.looksCredible && bundleImplRef.looksCredible) MacroImplAmbiguousError()
+ if (vanillaResult.isSuccess && bundleResult.isSuccess) MacroImplAmbiguousError()
+ }
+
+ def reportMostAppropriateFailure() = {
+ typer.silent(_.typedTypeConstructor(maybeBundleRef)) match {
+ case SilentResultValue(result) if looksLikeMacroBundleType(result.tpe) =>
+ val bundle = result.tpe.typeSymbol
+ if (!isMacroBundleType(bundle.tpe)) MacroBundleWrongShapeError()
+ if (!bundle.owner.isStaticOwner) MacroBundleNonStaticError()
+ bundleResult.get
+ case _ =>
+ vanillaResult.get
+ }
+ }
+
try {
- validateMacroImplRef()
- macroImplRef
+ if (vanillaResult.isSuccess || bundleResult.isSuccess) ensureUnambiguousSuccess()
+ if (vanillaResult.isFailure && bundleResult.isFailure) reportMostAppropriateFailure()
+ vanillaResult.orElse(bundleResult).get
} catch {
case MacroImplResolutionException(pos, msg) =>
context.error(pos, msg)
diff --git a/src/compiler/scala/reflect/macros/compiler/Errors.scala b/src/compiler/scala/reflect/macros/compiler/Errors.scala
index 280baa2a42..490ab3657a 100644
--- a/src/compiler/scala/reflect/macros/compiler/Errors.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Errors.scala
@@ -13,12 +13,9 @@ trait Errors extends Traces {
import treeInfo._
import typer.TyperErrorGen._
import typer.infer.InferErrorGen._
- private val runDefinitions = currentRun.runDefinitions
import runDefinitions._
def globalSettings = global.settings
- // sanity check errors
-
private def implRefError(message: String) = {
val Applied(culprit, _, _) = macroDdef.rhs
abort(culprit.pos, message)
@@ -33,111 +30,125 @@ trait Errors extends Traces {
abort(culprit.pos, message)
}
- def MacroImplReferenceWrongShapeError() = implRefError(
+ def MacroImplAmbiguousError() = implRefError(
+ "macro implementation reference is ambiguous: makes sense both as\n"+
+ "a macro bundle method reference and a vanilla object method reference")
+
+ def MacroBundleNonStaticError() = bundleRefError("macro bundles must be static")
+
+ def MacroBundleWrongShapeError() = bundleRefError("macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter")
+
+ trait Error {
+ self: MacroImplRefCompiler =>
+
+ // sanity check errors
+
+ def MacroImplReferenceWrongShapeError() = implRefError(
"macro implementation reference has wrong shape. required:\n"+
"macro [<static object>].<method name>[[<type args>]] or\n" +
"macro [<macro bundle>].<method name>[[<type args>]]")
- def MacroImplWrongNumberOfTypeArgumentsError() = {
- val diagnostic = if (macroImpl.typeParams.length > targs.length) "has too few type arguments" else "has too many arguments"
- implRefError(s"macro implementation reference $diagnostic for " + treeSymTypeMsg(macroImplRef))
- }
-
- def MacroImplNotPublicError() = implRefError("macro implementation must be public")
+ def MacroImplWrongNumberOfTypeArgumentsError() = {
+ val diagnostic = if (macroImpl.typeParams.length > targs.length) "has too few type arguments" else "has too many arguments"
+ implRefError(s"macro implementation reference $diagnostic for " + treeSymTypeMsg(macroImplRef))
+ }
- def MacroImplOverloadedError() = implRefError("macro implementation cannot be overloaded")
+ private def macroImplementationWording =
+ if (isImplBundle) "bundle implementation"
+ else "macro implementation"
- def MacroImplNonTagImplicitParameters(params: List[Symbol]) = implRefError("macro implementations cannot have implicit parameters other than WeakTypeTag evidences")
+ def MacroImplNotPublicError() = implRefError(s"${macroImplementationWording} must be public")
- def MacroBundleNonStaticError() = bundleRefError("macro bundles must be static")
+ def MacroImplOverloadedError() = implRefError(s"${macroImplementationWording} cannot be overloaded")
- def MacroBundleWrongShapeError() = bundleRefError("macro bundles must be concrete classes having a single constructor with a `val c: Context` parameter")
+ def MacroImplNonTagImplicitParameters(params: List[Symbol]) = implRefError(s"${macroImplementationWording}s cannot have implicit parameters other than WeakTypeTag evidences")
- // compatibility errors
+ // compatibility errors
- // helpers
+ // 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 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 = {
- val coreAliases = List("WeakTypeTag", "Expr", "Tree")
- coreAliases.foldLeft(s)((res, x) => res.replace("c.universe." + x, "c." + x))
- }
+ private def abbreviateCoreAliases(s: String): String = {
+ val coreAliases = List("WeakTypeTag", "Expr", "Tree")
+ coreAliases.foldLeft(s)((res, x) => res.replace("c.universe." + x, "c." + x))
+ }
- private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean, untype: Boolean) = {
- def preprocess(tpe: Type) = if (untype) untypeMetalevel(tpe) else tpe
- var pssPart = (pss map (ps => ps map (p => p.defStringSeenAs(preprocess(p.info))) mkString ("(", ", ", ")"))).mkString
- if (abbreviate) pssPart = abbreviateCoreAliases(pssPart)
- var retPart = preprocess(restpe).toString
- if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart)
- pssPart + ": " + retPart
- }
+ private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean, untype: Boolean) = {
+ def preprocess(tpe: Type) = if (untype) untypeMetalevel(tpe) else tpe
+ var pssPart = (pss map (ps => ps map (p => p.defStringSeenAs(preprocess(p.info))) mkString ("(", ", ", ")"))).mkString
+ if (abbreviate) pssPart = abbreviateCoreAliases(pssPart)
+ var retPart = preprocess(restpe).toString
+ if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart)
+ pssPart + ": " + retPart
+ }
- // not exactly an error generator, but very related
- // and I dearly wanted to push it away from Macros.scala
- private def checkConforms(slot: String, rtpe: Type, atpe: Type) = {
- val verbose = macroDebugVerbose
-
- def check(rtpe: Type, atpe: Type): Boolean = {
- def success() = { if (verbose) println(rtpe + " <: " + atpe + "?" + EOL + "true"); true }
- (rtpe, atpe) match {
- case _ if rtpe eq atpe => success()
- case (TypeRef(_, RepeatedParamClass, rtpe :: Nil), TypeRef(_, RepeatedParamClass, atpe :: Nil)) => check(rtpe, atpe)
- case (ExprClassOf(_), TreeType()) if rtpe.prefix =:= atpe.prefix => success()
- case (SubtreeType(), ExprClassOf(_)) if rtpe.prefix =:= atpe.prefix => success()
- case _ => rtpe <:< atpe
+ // not exactly an error generator, but very related
+ // and I dearly wanted to push it away from Macros.scala
+ private def checkConforms(slot: String, rtpe: Type, atpe: Type) = {
+ val verbose = macroDebugVerbose
+
+ def check(rtpe: Type, atpe: Type): Boolean = {
+ def success() = { if (verbose) println(rtpe + " <: " + atpe + "?" + EOL + "true"); true }
+ (rtpe, atpe) match {
+ case _ if rtpe eq atpe => success()
+ case (TypeRef(_, RepeatedParamClass, rtpe :: Nil), TypeRef(_, RepeatedParamClass, atpe :: Nil)) => check(rtpe, atpe)
+ case (ExprClassOf(_), TreeType()) if rtpe.prefix =:= atpe.prefix => success()
+ case (SubtreeType(), ExprClassOf(_)) if rtpe.prefix =:= atpe.prefix => success()
+ case _ => rtpe <:< atpe
+ }
}
- }
- val ok =
- if (verbose) withTypesExplained(check(rtpe, atpe))
- else check(rtpe, atpe)
- if (!ok) {
- if (!verbose) explainTypes(rtpe, atpe)
- val msg = {
- val ss = Seq(rtpe, atpe) map (this abbreviateCoreAliases _.toString)
- s"type mismatch for $slot: ${ss(0)} does not conform to ${ss(1)}"
+ val ok =
+ if (verbose) withTypesExplained(check(rtpe, atpe))
+ else check(rtpe, atpe)
+ if (!ok) {
+ if (!verbose) explainTypes(rtpe, atpe)
+ val msg = {
+ val ss = Seq(rtpe, atpe) map (this abbreviateCoreAliases _.toString)
+ s"type mismatch for $slot: ${ss(0)} does not conform to ${ss(1)}"
+ }
+ compatibilityError(msg)
}
- compatibilityError(msg)
}
- }
- private def compatibilityError(message: String) =
- implRefError(
- "macro implementation has incompatible shape:"+
- "\n required: " + showMeth(rparamss, rret, abbreviate = true, untype = false) +
- "\n or : " + showMeth(rparamss, rret, abbreviate = true, untype = true) +
- "\n found : " + showMeth(aparamss, aret, abbreviate = false, untype = false) +
- "\n" + message)
+ private def compatibilityError(message: String) =
+ implRefError(
+ s"${macroImplementationWording} has incompatible shape:"+
+ "\n required: " + showMeth(rparamss, rret, abbreviate = true, untype = false) +
+ "\n or : " + showMeth(rparamss, rret, abbreviate = true, untype = true) +
+ "\n found : " + showMeth(aparamss, aret, abbreviate = false, untype = false) +
+ "\n" + message)
- def MacroImplParamssMismatchError() = compatibilityError("number of parameter sections differ")
+ def MacroImplParamssMismatchError() = compatibilityError("number of parameter sections differ")
- def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(lengthMsg("value", "found", aparams(rparams.length)))
+ def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(lengthMsg("value", "found", aparams(rparams.length)))
- def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(abbreviateCoreAliases(lengthMsg("value", "required", rparams(aparams.length))))
+ def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(abbreviateCoreAliases(lengthMsg("value", "required", rparams(aparams.length))))
- def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = checkConforms("parameter " + rparam.name, rparam.tpe, atpe)
+ def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = checkConforms("parameter " + rparam.name, rparam.tpe, atpe)
- def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = checkConforms("return type", atpe, rret)
+ def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = checkConforms("return type", atpe, rret)
- def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = 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) = {
- def fail(paramName: Name) = compatibilityError("types incompatible for parameter " + paramName + ": corresponding is not a vararg parameter")
- if (isRepeated(rparam) && !isRepeated(aparam)) fail(rparam.name)
- if (!isRepeated(rparam) && isRepeated(aparam)) fail(aparam.name)
- }
+ def MacroImplVarargMismatchError(aparam: Symbol, rparam: Symbol) = {
+ def fail(paramName: Name) = compatibilityError("types incompatible for parameter " + paramName + ": corresponding is not a vararg parameter")
+ if (isRepeated(rparam) && !isRepeated(aparam)) fail(rparam.name)
+ if (!isRepeated(rparam) && isRepeated(aparam)) fail(aparam.name)
+ }
- def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) =
- compatibilityError(NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value))
+ def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) =
+ compatibilityError(NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value))
- def MacroImplTparamInstantiationError(atparams: List[Symbol], e: NoInstance) = {
- val badps = atparams map (_.defString) mkString ", "
- compatibilityError(f"type parameters $badps cannot be instantiated%n${e.getMessage}")
+ def MacroImplTparamInstantiationError(atparams: List[Symbol], e: NoInstance) = {
+ val badps = atparams map (_.defString) mkString ", "
+ compatibilityError(f"type parameters $badps cannot be instantiated%n${e.getMessage}")
+ }
}
}
diff --git a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
index d2f9886f3c..807fb688a0 100644
--- a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
@@ -12,61 +12,35 @@ trait Resolvers {
import definitions._
import treeInfo._
import gen._
- private val runDefinitions = currentRun.runDefinitions
- import runDefinitions.{Predef_???, _}
+ import runDefinitions._
- /** Resolves a macro impl reference provided in the right-hand side of the given macro definition.
- *
- * Acceptable shapes of the right-hand side:
- * 1) [<static object>].<method name>[[<type args>]] // vanilla macro def
- * 2) [<macro bundle>].<method name>[[<type args>]] // shiny new macro bundle
- *
- * Produces a tree, which represents a reference to a macro implementation if everything goes well,
- * otherwise reports found errors and returns EmptyTree. The resulting tree should have the following format:
- *
- * qualifier.method[targs]
- *
- * Qualifier here might be omitted (macro defs local to blocks), be a static object (vanilla macro defs)
- * or be a dummy instance of a macro bundle (e.g. new MyMacro(???).expand).
- */
- lazy val macroImplRef: Tree = {
- val (maybeBundleRef, methName, targs) = macroDdef.rhs match {
- case Applied(Select(Applied(RefTree(qual, bundleName), _, Nil), methName), targs, Nil) =>
- (RefTree(qual, bundleName.toTypeName), methName, targs)
- case Applied(Ident(methName), targs, Nil) =>
- (Ident(context.owner.enclClass), methName, targs)
- case _ =>
- (EmptyTree, TermName(""), Nil)
- }
+ trait Resolver {
+ self: MacroImplRefCompiler =>
- val untypedImplRef = typer.silent(_.typedTypeConstructor(maybeBundleRef)) match {
- case SilentResultValue(result) if looksLikeMacroBundleType(result.tpe) =>
- val bundle = result.tpe.typeSymbol
- if (!isMacroBundleType(bundle.tpe)) MacroBundleWrongShapeError()
- if (!bundle.owner.isStaticOwner) MacroBundleNonStaticError()
- atPos(macroDdef.rhs.pos)(gen.mkTypeApply(Select(New(bundle, Ident(Predef_???)), methName), targs))
- case _ =>
- macroDdef.rhs
- }
+ val isImplBundle: Boolean
+ val isImplMethod = !isImplBundle
- val typedImplRef = typer.silent(_.typed(markMacroImplRef(untypedImplRef)), reportAmbiguousErrors = false)
- typedImplRef match {
- case SilentResultValue(success) => success
- case SilentTypeError(err) => abort(err.errPos, err.errMsg)
+ lazy val looksCredible: Boolean = {
+ val Applied(core, _, _) = untypedMacroImplRef
+ typer.silent(_.typed(markMacroImplRef(core)), reportAmbiguousErrors = false).nonEmpty
}
- }
- // FIXME: cannot write this concisely because of SI-7507
- // lazy val (isImplBundle, macroImplOwner, macroImpl, macroImplTargs) =
- private lazy val dissectedMacroImplRef =
- macroImplRef match {
- case MacroImplReference(isBundle, isBlackbox, owner, meth, targs) => (isBundle, isBlackbox, owner, meth, targs)
- case _ => MacroImplReferenceWrongShapeError()
- }
- lazy val isImplBundle = dissectedMacroImplRef._1
- lazy val isImplMethod = !isImplBundle
- lazy val isImplBlackbox = dissectedMacroImplRef._2
- lazy val macroImplOwner = dissectedMacroImplRef._3
- lazy val macroImpl = dissectedMacroImplRef._4
- lazy val targs = dissectedMacroImplRef._5
+ lazy val macroImplRef: Tree =
+ typer.silent(_.typed(markMacroImplRef(untypedMacroImplRef)), reportAmbiguousErrors = false) match {
+ case SilentResultValue(success) => success
+ case SilentTypeError(err) => abort(err.errPos, err.errMsg)
+ }
+
+ // FIXME: cannot write this concisely because of SI-7507
+ // lazy val (_, macroImplOwner, macroImpl, macroImplTargs) =
+ private lazy val dissectedMacroImplRef =
+ macroImplRef match {
+ case MacroImplReference(isBundle, isBlackbox, owner, meth, targs) => (isBlackbox, owner, meth, targs)
+ case _ => MacroImplReferenceWrongShapeError()
+ }
+ lazy val isImplBlackbox = dissectedMacroImplRef._1
+ lazy val macroImplOwner = dissectedMacroImplRef._2
+ lazy val macroImpl = dissectedMacroImplRef._3
+ lazy val targs = dissectedMacroImplRef._4
+ }
}
diff --git a/src/compiler/scala/reflect/macros/compiler/Validators.scala b/src/compiler/scala/reflect/macros/compiler/Validators.scala
index 02c1f7c431..fc118028dd 100644
--- a/src/compiler/scala/reflect/macros/compiler/Validators.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Validators.scala
@@ -1,9 +1,7 @@
package scala.reflect.macros
package compiler
-import java.util.UUID.randomUUID
import scala.reflect.internal.Flags._
-import scala.reflect.macros.TypecheckException
trait Validators {
self: DefaultMacroCompiler =>
@@ -11,189 +9,193 @@ trait Validators {
import global._
import analyzer._
import definitions._
- private val runDefinitions = currentRun.runDefinitions
import runDefinitions.{Predef_???, _}
- def validateMacroImplRef() = {
- sanityCheck()
- if (macroImpl != Predef_???) checkMacroDefMacroImplCorrespondence()
- }
+ trait Validator {
+ self: MacroImplRefCompiler =>
- private def sanityCheck() = {
- if (!macroImpl.isMethod) MacroImplReferenceWrongShapeError()
- if (macroImpl.typeParams.length != targs.length) MacroImplWrongNumberOfTypeArgumentsError()
- if (!macroImpl.isPublic) MacroImplNotPublicError()
- if (macroImpl.isOverloaded) MacroImplOverloadedError()
- val implicitParams = aparamss.flatten filter (_.isImplicit)
- if (implicitParams.nonEmpty) MacroImplNonTagImplicitParameters(implicitParams)
- val effectiveOwner = if (isImplMethod) macroImplOwner else macroImplOwner.owner
- val declaredInStaticObject = effectiveOwner.isStaticOwner || effectiveOwner.moduleClass.isStaticOwner
- if (!declaredInStaticObject) MacroImplReferenceWrongShapeError()
- }
+ def validateMacroImplRef() = {
+ sanityCheck()
+ if (macroImpl != Predef_???) checkMacroDefMacroImplCorrespondence()
+ }
- private def checkMacroDefMacroImplCorrespondence() = {
- val atvars = atparams map freshVar
- def atpeToRtpe(atpe: Type) = atpe.substSym(aparamss.flatten, rparamss.flatten).instantiateTypeParams(atparams, atvars)
-
- // we only check strict correspondence between value parameterss
- // type parameters of macro defs and macro impls don't have to coincide with each other
- if (aparamss.length != rparamss.length) MacroImplParamssMismatchError()
- map2(aparamss, rparamss)((aparams, rparams) => {
- if (aparams.length < rparams.length) MacroImplMissingParamsError(aparams, rparams)
- if (rparams.length < aparams.length) MacroImplExtraParamsError(aparams, rparams)
- })
-
- try {
- // cannot fuse this map2 and the map2 above because if aparamss.flatten != rparamss.flatten
- // then `atpeToRtpe` is going to fail with an unsound substitution
- map2(aparamss.flatten, rparamss.flatten)((aparam, rparam) => {
- if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam)
- if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam)
- val aparamtpe = aparam.tpe match {
- case MacroContextType(tpe) => tpe
- case tpe => tpe
- }
- checkMacroImplParamTypeMismatch(atpeToRtpe(aparamtpe), rparam)
+ private def sanityCheck() = {
+ if (!macroImpl.isMethod) MacroImplReferenceWrongShapeError()
+ if (macroImpl.typeParams.length != targs.length) MacroImplWrongNumberOfTypeArgumentsError()
+ if (!macroImpl.isPublic) MacroImplNotPublicError()
+ if (macroImpl.isOverloaded) MacroImplOverloadedError()
+ val implicitParams = aparamss.flatten filter (_.isImplicit)
+ if (implicitParams.nonEmpty) MacroImplNonTagImplicitParameters(implicitParams)
+ val effectiveOwner = if (isImplMethod) macroImplOwner else macroImplOwner.owner
+ val effectivelyStatic = effectiveOwner.isStaticOwner || effectiveOwner.moduleClass.isStaticOwner
+ val correctBundleness = if (isImplMethod) macroImplOwner.isModuleClass else macroImplOwner.isClass && !macroImplOwner.isModuleClass
+ if (!effectivelyStatic || !correctBundleness) MacroImplReferenceWrongShapeError()
+ }
+
+ private def checkMacroDefMacroImplCorrespondence() = {
+ val atvars = atparams map freshVar
+ def atpeToRtpe(atpe: Type) = atpe.substSym(aparamss.flatten, rparamss.flatten).instantiateTypeParams(atparams, atvars)
+
+ // we only check strict correspondence between value parameterss
+ // type parameters of macro defs and macro impls don't have to coincide with each other
+ if (aparamss.length != rparamss.length) MacroImplParamssMismatchError()
+ map2(aparamss, rparamss)((aparams, rparams) => {
+ if (aparams.length < rparams.length) MacroImplMissingParamsError(aparams, rparams)
+ if (rparams.length < aparams.length) MacroImplExtraParamsError(aparams, rparams)
})
- checkMacroImplResultTypeMismatch(atpeToRtpe(aret), rret)
+ try {
+ // cannot fuse this map2 and the map2 above because if aparamss.flatten != rparamss.flatten
+ // then `atpeToRtpe` is going to fail with an unsound substitution
+ map2(aparamss.flatten, rparamss.flatten)((aparam, rparam) => {
+ if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam)
+ if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam)
+ val aparamtpe = aparam.tpe match {
+ case MacroContextType(tpe) => tpe
+ case tpe => tpe
+ }
+ checkMacroImplParamTypeMismatch(atpeToRtpe(aparamtpe), rparam)
+ })
- val maxLubDepth = lubDepth(aparamss.flatten map (_.tpe)) max lubDepth(rparamss.flatten map (_.tpe))
- val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, maxLubDepth)
- val boundsOk = typer.silent(_.infer.checkBounds(macroDdef, NoPrefix, NoSymbol, atparams, atargs, ""))
- boundsOk match {
- case SilentResultValue(true) => // do nothing, success
- case SilentResultValue(false) | SilentTypeError(_) => MacroImplTargMismatchError(atargs, atparams)
+ checkMacroImplResultTypeMismatch(atpeToRtpe(aret), rret)
+
+ val maxLubDepth = lubDepth(aparamss.flatten map (_.tpe)) max lubDepth(rparamss.flatten map (_.tpe))
+ val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, maxLubDepth)
+ val boundsOk = typer.silent(_.infer.checkBounds(macroDdef, NoPrefix, NoSymbol, atparams, atargs, ""))
+ boundsOk match {
+ case SilentResultValue(true) => // do nothing, success
+ case SilentResultValue(false) | SilentTypeError(_) => MacroImplTargMismatchError(atargs, atparams)
+ }
+ } catch {
+ case ex: NoInstance => MacroImplTparamInstantiationError(atparams, ex)
}
- } catch {
- case ex: NoInstance => MacroImplTparamInstantiationError(atparams, ex)
}
- }
- // aXXX (e.g. aparamss) => characteristics of the actual macro impl signature extracted from the macro impl ("a" stands for "actual")
- // rXXX (e.g. rparamss) => characteristics of the reference macro impl signature synthesized from the macro def ("r" stands for "reference")
- // FIXME: cannot write this concisely because of SI-7507
- //lazy val MacroImplSig(atparams, aparamss, aret) = macroImplSig
- //lazy val MacroImplSig(_, rparamss, rret) = referenceMacroImplSig
- lazy val atparams = macroImplSig.tparams
- lazy val aparamss = macroImplSig.paramss
- lazy val aret = macroImplSig.ret
- lazy val rparamss = referenceMacroImplSig.paramss
- lazy val rret = referenceMacroImplSig.ret
-
- // Technically this can be just an alias to MethodType, but promoting it to a first-class entity
- // provides better encapsulation and convenient syntax for pattern matching.
- private case class MacroImplSig(tparams: List[Symbol], paramss: List[List[Symbol]], ret: Type) {
- private def tparams_s = if (tparams.isEmpty) "" else tparams.map(_.defString).mkString("[", ", ", "]")
- private def paramss_s = paramss map (ps => ps.map(s => s"${s.name}: ${s.tpe_*}").mkString("(", ", ", ")")) mkString ""
- override def toString = "MacroImplSig(" + tparams_s + paramss_s + ret + ")"
- }
+ // aXXX (e.g. aparamss) => characteristics of the actual macro impl signature extracted from the macro impl ("a" stands for "actual")
+ // rXXX (e.g. rparamss) => characteristics of the reference macro impl signature synthesized from the macro def ("r" stands for "reference")
+ // FIXME: cannot write this concisely because of SI-7507
+ //lazy val MacroImplSig(atparams, aparamss, aret) = macroImplSig
+ //lazy val MacroImplSig(_, rparamss, rret) = referenceMacroImplSig
+ lazy val atparams = macroImplSig.tparams
+ lazy val aparamss = macroImplSig.paramss
+ lazy val aret = macroImplSig.ret
+ lazy val rparamss = referenceMacroImplSig.paramss
+ lazy val rret = referenceMacroImplSig.ret
+
+ // Technically this can be just an alias to MethodType, but promoting it to a first-class entity
+ // provides better encapsulation and convenient syntax for pattern matching.
+ private case class MacroImplSig(tparams: List[Symbol], paramss: List[List[Symbol]], ret: Type) {
+ private def tparams_s = if (tparams.isEmpty) "" else tparams.map(_.defString).mkString("[", ", ", "]")
+ private def paramss_s = paramss map (ps => ps.map(s => s"${s.name}: ${s.tpe_*}").mkString("(", ", ", ")")) mkString ""
+ override def toString = "MacroImplSig(" + tparams_s + paramss_s + ret + ")"
+ }
- /** An actual macro implementation signature extracted from a macro implementation method.
- *
- * For the following macro impl:
- * def fooBar[T: c.WeakTypeTag]
- * (c: scala.reflect.macros.blackbox.Context)
- * (xs: c.Expr[List[T]])
- * : c.Expr[T] = ...
- *
- * This function will return:
- * (c: scala.reflect.macros.blackbox.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.
- *
- * This method cannot be reduced to just macroImpl.info, because macro implementations might
- * come in different shapes. If the implementation is an apply method of a *box.Macro-compatible object,
- * then it won't have (c: *box.Context) in its parameters, but will rather refer to *boxMacro.c.
- *
- * @param macroImpl The macro implementation symbol
- */
- private lazy val macroImplSig: MacroImplSig = {
- val tparams = macroImpl.typeParams
- val paramss = transformTypeTagEvidenceParams(macroImplRef, (param, tparam) => NoSymbol)
- val ret = macroImpl.info.finalResultType
- MacroImplSig(tparams, paramss, ret)
- }
+ /** An actual macro implementation signature extracted from a macro implementation method.
+ *
+ * For the following macro impl:
+ * def fooBar[T: c.WeakTypeTag]
+ * (c: scala.reflect.macros.blackbox.Context)
+ * (xs: c.Expr[List[T]])
+ * : c.Expr[T] = ...
+ *
+ * This function will return:
+ * (c: scala.reflect.macros.blackbox.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.
+ *
+ * This method cannot be reduced to just macroImpl.info, because macro implementations might
+ * come in different shapes. If the implementation is an apply method of a *box.Macro-compatible object,
+ * then it won't have (c: *box.Context) in its parameters, but will rather refer to *boxMacro.c.
+ *
+ * @param macroImpl The macro implementation symbol
+ */
+ private lazy val macroImplSig: MacroImplSig = {
+ val tparams = macroImpl.typeParams
+ val paramss = transformTypeTagEvidenceParams(macroImplRef, (param, tparam) => NoSymbol)
+ val ret = macroImpl.info.finalResultType
+ MacroImplSig(tparams, paramss, ret)
+ }
- /** A reference macro implementation signature extracted from a given macro definition.
- *
- * For the following macro def:
- * def foo[T](xs: List[T]): T = macro fooBar
- *
- * This function will return:
- * (c: scala.reflect.macros.blackbox.Context)(xs: c.Expr[List[T]])c.Expr[T] or
- * (c: scala.reflect.macros.whitebox.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.
- *
- * Also note that we need a DefDef, not the corresponding MethodSymbol, because that symbol would be of no use for us.
- * Macro signatures are verified when typechecking macro defs, which means that at that moment inspecting macroDef.info
- * means asking for cyclic reference errors.
- *
- * We need macro implementation symbol as well, because the return type of the macro definition might be omitted,
- * and in that case we'd need to infer it from the return type of the macro implementation. Luckily for us, we can
- * use that symbol without a risk of running into cycles.
- *
- * @param typer Typechecker of `macroDdef`
- * @param macroDdef The macro definition tree
- * @param macroImpl The macro implementation symbol
- */
- private lazy val referenceMacroImplSig: MacroImplSig = {
- // had to move method's body to an object because of the recursive dependencies between sigma and param
- object SigGenerator {
- val cache = scala.collection.mutable.Map[Symbol, Symbol]()
- val ctxTpe = if (isImplBlackbox) BlackboxContextClass.tpe else WhiteboxContextClass.tpe
- val ctxPrefix =
- if (isImplMethod) singleType(NoPrefix, makeParam(nme.macroContext, macroDdef.pos, ctxTpe, SYNTHETIC))
- else singleType(ThisType(macroImpl.owner), macroImpl.owner.tpe.member(nme.c))
- val paramss =
- if (isImplMethod) List(ctxPrefix.termSymbol) :: mmap(macroDdef.vparamss)(param)
- else mmap(macroDdef.vparamss)(param)
- val macroDefRet =
- if (!macroDdef.tpt.isEmpty) typer.typedType(macroDdef.tpt).tpe
- else computeMacroDefTypeFromMacroImplRef(macroDdef, macroImplRef) orElse AnyTpe
- val implReturnType = sigma(increaseMetalevel(ctxPrefix, macroDefRet))
-
- object SigmaTypeMap extends TypeMap {
- def mapPrefix(pre: Type) = pre match {
- case ThisType(sym) if sym == macroDef.owner =>
- singleType(singleType(ctxPrefix, MacroContextPrefix), ExprValue)
- case SingleType(NoPrefix, sym) =>
- mfind(macroDdef.vparamss)(_.symbol == sym).fold(pre)(p => singleType(singleType(NoPrefix, param(p)), ExprValue))
- case _ =>
- mapOver(pre)
- }
- def apply(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) =>
- val pre1 = mapPrefix(pre)
- val args1 = mapOverArgs(args, sym.typeParams)
- if ((pre eq pre1) && (args eq args1)) tp
- else typeRef(pre1, sym, args1)
- case _ =>
- mapOver(tp)
+ /** A reference macro implementation signature extracted from a given macro definition.
+ *
+ * For the following macro def:
+ * def foo[T](xs: List[T]): T = macro fooBar
+ *
+ * This function will return:
+ * (c: scala.reflect.macros.blackbox.Context)(xs: c.Expr[List[T]])c.Expr[T] or
+ * (c: scala.reflect.macros.whitebox.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.
+ *
+ * Also note that we need a DefDef, not the corresponding MethodSymbol, because that symbol would be of no use for us.
+ * Macro signatures are verified when typechecking macro defs, which means that at that moment inspecting macroDef.info
+ * means asking for cyclic reference errors.
+ *
+ * We need macro implementation symbol as well, because the return type of the macro definition might be omitted,
+ * and in that case we'd need to infer it from the return type of the macro implementation. Luckily for us, we can
+ * use that symbol without a risk of running into cycles.
+ *
+ * @param typer Typechecker of `macroDdef`
+ * @param macroDdef The macro definition tree
+ * @param macroImpl The macro implementation symbol
+ */
+ private lazy val referenceMacroImplSig: MacroImplSig = {
+ // had to move method's body to an object because of the recursive dependencies between sigma and param
+ object SigGenerator {
+ val cache = scala.collection.mutable.Map[Symbol, Symbol]()
+ val ctxTpe = if (isImplBlackbox) BlackboxContextClass.tpe else WhiteboxContextClass.tpe
+ val ctxPrefix =
+ if (isImplMethod) singleType(NoPrefix, makeParam(nme.macroContext, macroDdef.pos, ctxTpe, SYNTHETIC))
+ else singleType(ThisType(macroImpl.owner), macroImpl.owner.tpe.member(nme.c))
+ val paramss =
+ if (isImplMethod) List(ctxPrefix.termSymbol) :: mmap(macroDdef.vparamss)(param)
+ else mmap(macroDdef.vparamss)(param)
+ val macroDefRet =
+ if (!macroDdef.tpt.isEmpty) typer.typedType(macroDdef.tpt).tpe
+ else computeMacroDefTypeFromMacroImplRef(macroDdef, macroImplRef) orElse AnyTpe
+ val implReturnType = sigma(increaseMetalevel(ctxPrefix, macroDefRet))
+
+ object SigmaTypeMap extends TypeMap {
+ def mapPrefix(pre: Type) = pre match {
+ case ThisType(sym) if sym == macroDef.owner =>
+ singleType(singleType(ctxPrefix, MacroContextPrefix), ExprValue)
+ case SingleType(NoPrefix, sym) =>
+ mfind(macroDdef.vparamss)(_.symbol == sym).fold(pre)(p => singleType(singleType(NoPrefix, param(p)), ExprValue))
+ case _ =>
+ mapOver(pre)
+ }
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) =>
+ val pre1 = mapPrefix(pre)
+ val args1 = mapOverArgs(args, sym.typeParams)
+ if ((pre eq pre1) && (args eq args1)) tp
+ else typeRef(pre1, sym, args1)
+ case _ =>
+ mapOver(tp)
+ }
}
+ def sigma(tpe: Type): Type = SigmaTypeMap(tpe)
+
+ def makeParam(name: Name, pos: Position, tpe: Type, flags: Long) =
+ macroDef.newValueParameter(name.toTermName, pos, flags) setInfo tpe
+ def param(tree: Tree): Symbol = (
+ cache.getOrElseUpdate(tree.symbol, {
+ val sym = tree.symbol
+ assert(sym.isTerm, s"sym = $sym, tree = $tree")
+ makeParam(sym.name, sym.pos, sigma(increaseMetalevel(ctxPrefix, sym.tpe)), sym.flags)
+ })
+ )
}
- def sigma(tpe: Type): Type = SigmaTypeMap(tpe)
-
- def makeParam(name: Name, pos: Position, tpe: Type, flags: Long) =
- macroDef.newValueParameter(name.toTermName, pos, flags) setInfo tpe
- def param(tree: Tree): Symbol = (
- cache.getOrElseUpdate(tree.symbol, {
- val sym = tree.symbol
- assert(sym.isTerm, s"sym = $sym, tree = $tree")
- makeParam(sym.name, sym.pos, sigma(increaseMetalevel(ctxPrefix, sym.tpe)), sym.flags)
- })
- )
- }
- import SigGenerator._
- macroLogVerbose(s"generating macroImplSigs for: $macroDdef")
- val result = MacroImplSig(macroDdef.tparams map (_.symbol), paramss, implReturnType)
- macroLogVerbose(s"result is: $result")
- result
+ import SigGenerator._
+ macroLogVerbose(s"generating macroImplSigs for: $macroDdef")
+ val result = MacroImplSig(macroDdef.tparams map (_.symbol), paramss, implReturnType)
+ macroLogVerbose(s"result is: $result")
+ result
+ }
}
}
diff --git a/src/compiler/scala/reflect/macros/contexts/Typers.scala b/src/compiler/scala/reflect/macros/contexts/Typers.scala
index f1620b764b..28c1e3ddb3 100644
--- a/src/compiler/scala/reflect/macros/contexts/Typers.scala
+++ b/src/compiler/scala/reflect/macros/contexts/Typers.scala
@@ -20,15 +20,12 @@ trait Typers {
def typecheck(tree: Tree, mode: TypecheckMode = TERMmode, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
macroLogVerbose("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled))
val context = callsiteTyper.context
- val wrapper1 = if (!withImplicitViewsDisabled) (context.withImplicitsEnabled[Tree] _) else (context.withImplicitsDisabled[Tree] _)
- val wrapper2 = if (!withMacrosDisabled) (context.withMacrosEnabled[Tree] _) else (context.withMacrosDisabled[Tree] _)
- def wrapper (tree: => Tree) = wrapper1(wrapper2(tree))
- // if you get a "silent mode is not available past typer" here
- // don't rush to change the typecheck not to use the silent method when the silent parameter is false
- // typechecking uses silent anyways (e.g. in typedSelect), so you'll only waste your time
- // I'd advise fixing the root cause: finding why the context is not set to report errors
- // (also see reflect.runtime.ToolBoxes.typeCheckExpr for a workaround that might work for you)
- wrapper(callsiteTyper.silent(_.typed(universe.duplicateAndKeepPositions(tree), mode, pt), reportAmbiguousErrors = false) match {
+ val withImplicitFlag = if (!withImplicitViewsDisabled) (context.withImplicitsEnabled[Tree] _) else (context.withImplicitsDisabled[Tree] _)
+ val withMacroFlag = if (!withMacrosDisabled) (context.withMacrosEnabled[Tree] _) else (context.withMacrosDisabled[Tree] _)
+ def withContext(tree: => Tree) = withImplicitFlag(withMacroFlag(tree))
+ def withWrapping(tree: Tree)(op: Tree => Tree) = if (mode == TERMmode) universe.wrappingIntoTerm(tree)(op) else op(tree)
+ def typecheckInternal(tree: Tree) = callsiteTyper.silent(_.typed(universe.duplicateAndKeepPositions(tree), mode, pt), reportAmbiguousErrors = false)
+ withWrapping(tree)(wrappedTree => withContext(typecheckInternal(wrappedTree) match {
case universe.analyzer.SilentResultValue(result) =>
macroLogVerbose(result)
result
@@ -36,7 +33,7 @@ trait Typers {
macroLogVerbose(error.err.errMsg)
if (!silent) throw new TypecheckException(error.err.errPos, error.err.errMsg)
universe.EmptyTree
- })
+ }))
}
def inferImplicitValue(pt: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = {