summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-06-06 02:05:10 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-06-08 15:23:11 +0200
commit1708a7fffdb653a638927c2b4ff30a7a0be0f3fe (patch)
tree1d270cc0b3c4a7424f2444a4d1dca460699abb6a
parentfb67a1d3aea159fd39e5c0fad14ffa089a5d6ba5 (diff)
downloadscala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.tar.gz
scala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.tar.bz2
scala-1708a7fffdb653a638927c2b4ff30a7a0be0f3fe.zip
macros: refactoring of fast track infrastructure
As a result, hardwired macros don't need implementation stubs. This is very important, because in a few commits scala.reflect.makro.Context will move out from scala-library.jar. Also adding fast track entries doesn't require jumping through hoops with PDTs. It's as simple as defining PartialFunction[Tree, Any].
-rw-r--r--lib/scala-compiler.jar.desired.sha12
-rw-r--r--lib/scala-library.jar.desired.sha12
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala3
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/compiler/scala/reflect/reify/Taggers.scala104
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala245
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala3
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala46
-rwxr-xr-xsrc/library/scala/reflect/api/Universe.scala14
-rw-r--r--src/library/scala/reflect/makro/Context.scala15
-rw-r--r--src/library/scala/reflect/makro/internal/Utils.scala148
-rw-r--r--src/library/scala/reflect/makro/internal/macroImpl.scala17
-rw-r--r--src/library/scala/reflect/makro/internal/package.scala17
-rw-r--r--test/files/run/macro-invalidusage-partialapplication-with-tparams.check3
-rw-r--r--test/files/run/macro-invalidusage-partialapplication-with-tparams.flags1
-rw-r--r--test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala13
-rw-r--r--test/files/run/macro-invalidusage-partialapplication-with-tparams/Test_2.scala8
19 files changed, 346 insertions, 311 deletions
diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1
index b2d1ae35eb..624a57ada7 100644
--- a/lib/scala-compiler.jar.desired.sha1
+++ b/lib/scala-compiler.jar.desired.sha1
@@ -1 +1 @@
-0939b5f357e4b0a6ecb3b6218a1a53841aae258d ?scala-compiler.jar
+fbdefcf1a7a2bcd71373f08acd13e84d869ceeaf ?scala-compiler.jar
diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1
index ebc617f19a..21e2ed8665 100644
--- a/lib/scala-library.jar.desired.sha1
+++ b/lib/scala-library.jar.desired.sha1
@@ -1 +1 @@
-2abaea76bd10ccb7afe29604b1156fb7f8c6c36e ?scala-library.jar
+e19956225d174f0f3bc0a1d014f208b68d399d66 ?scala-library.jar
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 96819eab91..6141cc184d 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -486,6 +486,9 @@ trait Definitions extends reflect.api.StandardDefinitions {
// [Eugene] is this a good place for ReflectMirrorPrefix?
def ReflectMirrorPrefix = gen.mkAttributedRef(ReflectMirror) setType singleType(ReflectMirror.owner.thisPrefix, ReflectMirror)
+ lazy val ApiUniverseClass = requiredClass[scala.reflect.api.Universe]
+ def ApiUniverseReify = getMemberMethod(ApiUniverseClass, nme.reify)
+
lazy val PartialManifestClass = requiredClass[scala.reflect.ClassManifest[_]]
lazy val PartialManifestModule = requiredModule[scala.reflect.ClassManifest.type]
lazy val FullManifestClass = requiredClass[scala.reflect.Manifest[_]]
diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala
index bd4d9a9f34..14d42387f7 100644
--- a/src/compiler/scala/reflect/internal/StdNames.scala
+++ b/src/compiler/scala/reflect/internal/StdNames.scala
@@ -130,6 +130,7 @@ trait StdNames {
final val ClassTag: NameType = "ClassTag"
final val TypeTag : NameType = "TypeTag"
final val ConcreteTypeTag: NameType = "ConcreteTypeTag"
+ final val String: NameType = "String"
// fictions we use as both types and terms
final val ERROR: NameType = "<error>"
@@ -223,7 +224,6 @@ trait StdNames {
final val Product: NameType = "Product"
final val Serializable: NameType = "Serializable"
final val Singleton: NameType = "Singleton"
- final val String: NameType = "String"
final val Throwable: NameType = "Throwable"
final val Annotation: NameType = "Annotation"
diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala
new file mode 100644
index 0000000000..5665c0948e
--- /dev/null
+++ b/src/compiler/scala/reflect/reify/Taggers.scala
@@ -0,0 +1,104 @@
+package scala.reflect.reify
+
+import scala.reflect.makro.{ReificationError, UnexpectedReificationError}
+import scala.reflect.makro.runtime.Context
+
+abstract class Taggers {
+ val c: Context
+
+ import c.mirror._
+ import definitions._
+
+ val coreTags = Map(
+ ByteClass.asType -> newTermName("Byte"),
+ ShortClass.asType -> newTermName("Short"),
+ CharClass.asType -> newTermName("Char"),
+ IntClass.asType -> newTermName("Int"),
+ LongClass.asType -> newTermName("Long"),
+ FloatClass.asType -> newTermName("Float"),
+ DoubleClass.asType -> newTermName("Double"),
+ BooleanClass.asType -> newTermName("Boolean"),
+ UnitClass.asType -> newTermName("Unit"),
+ AnyClass.asType -> newTermName("Any"),
+ ObjectClass.asType -> newTermName("Object"),
+ AnyValClass.asType -> newTermName("AnyVal"),
+ AnyRefClass.asType -> newTermName("AnyRef"),
+ NothingClass.asType -> newTermName("Nothing"),
+ NullClass.asType -> newTermName("Null"),
+ StringClass.asType -> newTermName("String"))
+
+ // todo. the following two methods won't be necessary once we implement implicit macro generators for tags
+
+ def materializeArrayTag(prefix: Tree, tpe: Type): Tree =
+ materializeClassTag(prefix, tpe)
+
+ def materializeErasureTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree =
+ if (concrete) materializeClassTag(prefix, tpe) else materializeTypeTag(prefix, tpe, concrete = false)
+
+ def materializeClassTag(prefix: Tree, tpe: Type): Tree =
+ materializeTag(prefix, tpe, ClassTagModule, {
+ val erasure = c.reifyErasure(tpe, concrete = true)
+ val factory = TypeApply(Select(Ident(ClassTagModule), "apply"), List(TypeTree(tpe)))
+ Apply(factory, List(erasure))
+ })
+
+ def materializeTypeTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = {
+ val tagModule = if (concrete) ConcreteTypeTagModule else TypeTagModule
+ materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, concrete = concrete))
+ }
+
+ private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = {
+ val result =
+ tpe match {
+ case coreTpe if coreTags contains coreTpe =>
+ val ref = if (tagModule.owner.isPackageClass) Ident(tagModule) else Select(prefix, tagModule.name)
+ Select(ref, coreTags(coreTpe))
+ case _ =>
+ val manifestInScope = nonSyntheticManifestInScope(tpe)
+ if (manifestInScope.isEmpty) translatingReificationErrors(materializer)
+ else gen.mkMethodCall(staticModule("scala.reflect.package"), newTermName("manifestToConcreteTypeTag"), List(tpe), List(manifestInScope))
+ }
+ try c.typeCheck(result)
+ catch { case terr @ c.TypeError(pos, msg) => failTag(result, terr) }
+ }
+
+ private def nonSyntheticManifestInScope(tpe: Type) = {
+ val ManifestClass = staticClass("scala.reflect.Manifest")
+ val ManifestModule = staticModule("scala.reflect.Manifest")
+ val manifest = c.inferImplicitValue(appliedType(ManifestClass.asTypeConstructor, List(tpe)))
+ val notOk = manifest.isEmpty || (manifest exists (sub => sub.symbol != null && (sub.symbol == ManifestModule || sub.symbol.owner == ManifestModule)))
+ if (notOk) EmptyTree else manifest
+ }
+
+ def materializeExpr(prefix: Tree, expr: Tree): Tree = {
+ val result = translatingReificationErrors(c.reifyTree(prefix, expr))
+ try c.typeCheck(result)
+ catch { case terr @ c.TypeError(pos, msg) => failExpr(result, terr) }
+ }
+
+ private def translatingReificationErrors(materializer: => Tree): Tree = {
+ try materializer
+ catch {
+ case ReificationError(pos, msg) =>
+ c.error(pos.asInstanceOf[c.Position], msg) // this cast is a very small price for the sanity of exception handling
+ EmptyTree
+ case UnexpectedReificationError(pos, err, cause) if cause != null =>
+ throw cause
+ }
+ }
+
+ private def failTag(result: Tree, reason: Any): Nothing = {
+ val Apply(TypeApply(fun, List(tpeTree)), _) = c.macroApplication
+ val tpe = tpeTree.tpe
+ val PolyType(_, MethodType(_, tagTpe)) = fun.tpe
+ val tagModule = tagTpe.typeSymbol.companionSymbol
+ if (c.compilerSettings.contains("-Xlog-implicits"))
+ c.echo(c.enclosingPosition, s"cannot materialize ${tagModule.name}[$tpe] as $result because:\n$reason")
+ c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe))
+ }
+
+ private def failExpr(result: Tree, reason: Any): Nothing = {
+ val Apply(_, expr :: Nil) = c.macroApplication
+ c.abort(c.enclosingPosition, s"Cannot materialize $expr as $result because:\n$reason")
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index d43dceca58..8895642893 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -7,7 +7,6 @@ import scala.tools.nsc.util.ClassPath._
import scala.reflect.ReflectionUtils
import scala.collection.mutable.ListBuffer
import scala.compat.Platform.EOL
-import scala.reflect.makro.runtime.{Context => MacroContext}
import util.Statistics._
import scala.reflect.makro.util._
import java.lang.{Class => jClass}
@@ -38,7 +37,7 @@ import java.lang.reflect.{Array => jArray, Method => jMethod}
* (Expr(elems))
* (TypeTag(Int))
*/
-trait Macros extends Traces {
+trait Macros extends scala.tools.reflect.FastTrack with Traces {
self: Analyzer =>
import global._
@@ -186,6 +185,12 @@ trait Macros extends Traces {
import typer.context
macroLogVerbose("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos))
+ if (fastTrack contains ddef.symbol) {
+ macroLogVerbose("typecheck terminated unexpectedly: macro is hardwired")
+ assert(!ddef.tpt.isEmpty, "hardwired macros must provide result type")
+ return EmptyTree
+ }
+
if (!typer.checkFeature(ddef.pos, MacrosFeature, immediate = true)) {
macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled")
ddef.symbol setFlag IS_ERROR
@@ -635,39 +640,8 @@ trait Macros extends Traces {
* @return Some(runtime) if macro implementation can be loaded successfully from either of the mirrors,
* None otherwise.
*/
- private type MacroRuntime = List[Any] => Any
+ type MacroRuntime = List[Any] => Any
private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, Option[MacroRuntime]]
- private lazy val fastTrack: Map[Symbol, MacroRuntime] = {
- import scala.reflect.api.Universe
- import scala.reflect.makro.internal._
- Map( // challenge: how can we factor out the common code? Does not seem to be easy.
- MacroInternal_materializeArrayTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeArrayTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeErasureTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeErasureTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeClassTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeClassTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeTypeTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeTypeTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- }),
- MacroInternal_materializeConcreteTypeTag -> (args => {
- assert(args.length == 3, args)
- val c = args(0).asInstanceOf[MacroContext]
- materializeConcreteTypeTag_impl(c)(args(1).asInstanceOf[c.Expr[Universe]])(args(2).asInstanceOf[c.TypeTag[_]])
- })
- )
- }
private def macroRuntime(macroDef: Symbol): Option[MacroRuntime] = {
macroTraceVerbose("looking for macro implementation: ")(macroDef)
if (fastTrack contains macroDef) {
@@ -794,15 +768,14 @@ trait Macros extends Traces {
}
}
- /** Should become private again once we're done with migrating typetag generation from implicits */
- def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext { val mirror: global.type } =
+ private def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext =
new {
- val mirror: global.type = global
+ val mirror: self.global.type = self.global
val callsiteTyper: mirror.analyzer.Typer = typer.asInstanceOf[global.analyzer.Typer]
- // todo. infer precise typetag for this Expr, namely the PrefixType member of the Context refinement
- val prefix = Expr(prefixTree)(TypeTag.Nothing)
val expandee = expandeeTree
- } with MacroContext {
+ } with UnaffiliatedMacroContext {
+ // todo. infer precise typetag for this Expr, namely the PrefixType member of the Context refinement
+ val prefix = Expr[Nothing](prefixTree)(TypeTag.Nothing)
override def toString = "MacroContext(%s@%s +%d)".format(expandee.symbol.name, expandee.pos, enclosingMacros.length - 1 /* exclude myself */)
}
@@ -836,96 +809,111 @@ trait Macros extends Traces {
val context = expandee.attachmentOpt[MacroAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefixTree, expandee))
var argss: List[List[Any]] = List(context) :: exprArgs.toList
macroTraceVerbose("argss: ")(argss)
+ val rawArgss =
+ if (fastTrack contains macroDef) {
+ if (fastTrack(macroDef) validate argss) argss
+ else {
+ // if you're getting here, it's not necessarily partial application that is at fault
+ // for example, if a signature of a hardwired macro has been changed without updated FastTrack
+ // then the corresponding partial function in FastTrack will refuse to process the expandee
+ // validation will return false, and control flow will end up here
+ // however, for simplicity sake, I didn't introduce the notion of error handling to FastTrack
+ // so all kinds of validation errors produce `MacroPartialApplicationError`
+ typer.TyperErrorGen.MacroPartialApplicationError(expandee)
+ return None
+ }
+ } else {
+ val ann = macroDef.getAnnotation(MacroImplAnnotation).getOrElse(throw new Error("assertion failed. %s: %s".format(macroDef, macroDef.annotations)))
+ val macroImpl = ann.args(0).symbol
+ var paramss = macroImpl.paramss
+ val tparams = macroImpl.typeParams
+ macroTraceVerbose("paramss: ")(paramss)
+
+ // we need to take care of all possible combos of nullary/empty-paramlist macro defs vs nullary/empty-arglist invocations
+ // nullary def + nullary invocation => paramss and argss match, everything is okay
+ // nullary def + empty-arglist invocation => illegal Scala code, impossible, everything is okay
+ // empty-paramlist def + nullary invocation => uh-oh, we need to append a List() to argss
+ // empty-paramlist def + empty-arglist invocation => paramss and argss match, everything is okay
+ // that's almost it, but we need to account for the fact that paramss might have context bounds that mask the empty last paramlist
+ val paramss_without_evidences = transformTypeTagEvidenceParams(paramss, (param, tparam) => None)
+ val isEmptyParamlistDef = paramss_without_evidences.nonEmpty && paramss_without_evidences.last.isEmpty
+ val isEmptyArglistInvocation = argss.nonEmpty && argss.last.isEmpty
+ if (isEmptyParamlistDef && !isEmptyArglistInvocation) {
+ macroLogVerbose("isEmptyParamlistDef && !isEmptyArglistInvocation: appending a List() to argss")
+ argss = argss :+ Nil
+ }
- val ann = macroDef.getAnnotation(MacroImplAnnotation).getOrElse(throw new Error("assertion failed. %s: %s".format(macroDef, macroDef.annotations)))
- val macroImpl = ann.args(0).symbol
- var paramss = macroImpl.paramss
- val tparams = macroImpl.typeParams
- macroTraceVerbose("paramss: ")(paramss)
-
- // we need to take care of all possible combos of nullary/empty-paramlist macro defs vs nullary/empty-arglist invocations
- // nullary def + nullary invocation => paramss and argss match, everything is okay
- // nullary def + empty-arglist invocation => illegal Scala code, impossible, everything is okay
- // empty-paramlist def + nullary invocation => uh-oh, we need to append a List() to argss
- // empty-paramlist def + empty-arglist invocation => paramss and argss match, everything is okay
- // that's almost it, but we need to account for the fact that paramss might have context bounds that mask the empty last paramlist
- val paramss_without_evidences = transformTypeTagEvidenceParams(paramss, (param, tparam) => None)
- val isEmptyParamlistDef = paramss_without_evidences.nonEmpty && paramss_without_evidences.last.isEmpty
- val isEmptyArglistInvocation = argss.nonEmpty && argss.last.isEmpty
- if (isEmptyParamlistDef && !isEmptyArglistInvocation) {
- macroLogVerbose("isEmptyParamlistDef && !isEmptyArglistInvocation: appending a List() to argss")
- argss = argss :+ Nil
- }
+ // nb! check partial application against paramss without evidences
+ val numParamLists = paramss_without_evidences.length
+ val numArgLists = argss.length
+ if (numParamLists != numArgLists) {
+ typer.TyperErrorGen.MacroPartialApplicationError(expandee)
+ return None
+ }
- // nb! check partial application against paramss without evidences
- val numParamLists = paramss_without_evidences.length
- val numArgLists = argss.length
- if (numParamLists != numArgLists) {
- typer.TyperErrorGen.MacroPartialApplicationError(expandee)
- return None
- }
+ // if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
+ // consider the following example:
+ //
+ // class D[T] {
+ // class C[U] {
+ // def foo[V] = macro Impls.foo[T, U, V]
+ // }
+ // }
+ //
+ // val outer1 = new D[Int]
+ // 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
+ // also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
+ val resolved = collection.mutable.Map[Symbol, Type]()
+ paramss = transformTypeTagEvidenceParams(paramss, (param, tparam) => {
+ val TypeApply(_, implRefTargs) = ann.args(0)
+ var implRefTarg = implRefTargs(tparam.paramPos).tpe.typeSymbol
+ val tpe = if (implRefTarg.isTypeParameterOrSkolem) {
+ if (implRefTarg.owner == macroDef) {
+ // [Eugene] doesn't work when macro def is compiled separately from its usages
+ // then implRefTarg is not a skolem and isn't equal to any of macroDef.typeParams
+ // val paramPos = implRefTarg.deSkolemize.paramPos
+ val paramPos = macroDef.typeParams.indexWhere(_.name == implRefTarg.name)
+ typeArgs(paramPos).tpe
+ } else
+ implRefTarg.tpe.asSeenFrom(
+ if (prefixTree == EmptyTree) macroDef.owner.tpe else prefixTree.tpe,
+ macroDef.owner)
+ } else
+ implRefTarg.tpe
+ macroLogVerbose("resolved tparam %s as %s".format(tparam, tpe))
+ resolved(tparam) = tpe
+ param.tpe.typeSymbol match {
+ case definitions.TypeTagClass =>
+ // do nothing
+ case definitions.ConcreteTypeTagClass =>
+ if (!tpe.isConcrete) context.abort(context.enclosingPosition, "cannot create ConcreteTypeTag from a type %s having unresolved type parameters".format(tpe))
+ // otherwise do nothing
+ case _ =>
+ throw new Error("unsupported tpe: " + tpe)
+ }
+ Some(tparam)
+ })
+ val tags = paramss.last takeWhile (_.isType) map (resolved(_)) map (tpe => {
+ // generally speaking, it's impossible to calculate erasure from a tpe here
+ // the tpe might be compiled by this run, so its jClass might not exist yet
+ // hence I just pass `null` instead and leave this puzzle to macro programmers
+ val ttag = TypeTag(tpe, null)
+ if (ttag.isConcrete) ttag.toConcrete else ttag
+ })
+ if (paramss.lastOption map (params => !params.isEmpty && params.forall(_.isType)) getOrElse false) argss = argss :+ Nil
+ argss = argss.dropRight(1) :+ (tags ++ argss.last) // todo. add support for context bounds in argss
- // if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
- // consider the following example:
- //
- // class D[T] {
- // class C[U] {
- // def foo[V] = macro Impls.foo[T, U, V]
- // }
- // }
- //
- // val outer1 = new D[Int]
- // 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
- // also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
- val resolved = collection.mutable.Map[Symbol, Type]()
- paramss = transformTypeTagEvidenceParams(paramss, (param, tparam) => {
- val TypeApply(_, implRefTargs) = ann.args(0)
- var implRefTarg = implRefTargs(tparam.paramPos).tpe.typeSymbol
- val tpe = if (implRefTarg.isTypeParameterOrSkolem) {
- if (implRefTarg.owner == macroDef) {
- // [Eugene] doesn't work when macro def is compiled separately from its usages
- // then implRefTarg is not a skolem and isn't equal to any of macroDef.typeParams
-// val paramPos = implRefTarg.deSkolemize.paramPos
- val paramPos = macroDef.typeParams.indexWhere(_.name == implRefTarg.name)
- typeArgs(paramPos).tpe
- } else
- implRefTarg.tpe.asSeenFrom(
- if (prefixTree == EmptyTree) macroDef.owner.tpe else prefixTree.tpe,
- macroDef.owner)
- } else
- implRefTarg.tpe
- macroLogVerbose("resolved tparam %s as %s".format(tparam, tpe))
- resolved(tparam) = tpe
- param.tpe.typeSymbol match {
- case definitions.TypeTagClass =>
- // do nothing
- case definitions.ConcreteTypeTagClass =>
- if (!tpe.isConcrete) context.abort(context.enclosingPosition, "cannot create ConcreteTypeTag from a type %s having unresolved type parameters".format(tpe))
- // otherwise do nothing
- case _ =>
- throw new Error("unsupported tpe: " + tpe)
+ assert(argss.length == paramss.length, "argss: %s, paramss: %s".format(argss, paramss))
+ val rawArgss = for ((as, ps) <- argss zip paramss) yield {
+ if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
+ else as
+ }
+ rawArgss
}
- Some(tparam)
- })
- val tags = paramss.last takeWhile (_.isType) map (resolved(_)) map (tpe => {
- // generally speaking, it's impossible to calculate erasure from a tpe here
- // the tpe might be compiled by this run, so its jClass might not exist yet
- // hence I just pass `null` instead and leave this puzzle to macro programmers
- val ttag = TypeTag(tpe, null)
- if (ttag.isConcrete) ttag.toConcrete else ttag
- })
- if (paramss.lastOption map (params => !params.isEmpty && params.forall(_.isType)) getOrElse false) argss = argss :+ Nil
- argss = argss.dropRight(1) :+ (tags ++ argss.last) // todo. add support for context bounds in argss
-
- assert(argss.length == paramss.length, "argss: %s, paramss: %s".format(argss, paramss))
- val rawArgss = for ((as, ps) <- argss zip paramss) yield {
- if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
- else as
- }
val rawArgs = rawArgss.flatten
macroTraceVerbose("rawArgs: ")(rawArgs)
Some(rawArgs)
@@ -1124,7 +1112,10 @@ trait Macros extends Traces {
else {
macroLogLite("typechecking macro expansion %s at %s".format(expandee, expandee.pos))
macroArgs(typer, expandee).fold(failExpansion(): MacroExpansionResult) {
- case args @ ((context: MacroContext) :: _) =>
+ // [Eugene++] crashes virtpatmat:
+ // case args @ ((context: MacroContext) :: _) =>
+ case args @ (context0 :: _) =>
+ val context = context0.asInstanceOf[MacroContext]
if (nowDelayed) {
macroLogLite("macro expansion is delayed: %s".format(expandee))
delayed += expandee -> undetparams
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 6d9c9c4ce8..553294d0fe 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1309,9 +1309,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
}
List(tree1)
}
- case Import(_, _) => Nil
- case DefDef(mods, _, _, _, _, _) if (mods hasFlag MACRO) => Nil
- case _ => List(transform(tree))
+ case Import(_, _) => Nil
+ case DefDef(mods, _, _, _, _, _) if (mods hasFlag MACRO) || (tree.symbol hasFlag MACRO) => Nil
+ case _ => List(transform(tree))
}
/* Check whether argument types conform to bounds of type parameters */
@@ -1496,7 +1496,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
private def transformCaseApply(tree: Tree, ifNot: => Unit) = {
val sym = tree.symbol
-
+
def isClassTypeAccessible(tree: Tree): Boolean = tree match {
case TypeApply(fun, targs) =>
isClassTypeAccessible(fun)
@@ -1505,7 +1505,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
// the companion class is actually not a ClassSymbol, but a reference to an abstract type.
module.symbol.companionClass.isClass
}
-
+
val doTransform =
sym.isSourceMethod &&
sym.isCase &&
diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
index 329a247106..3033230603 100644
--- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -1,10 +1,10 @@
package scala.tools.nsc
package typechecker
-import scala.reflect.makro.runtime.{Context => MacroContext}
-
trait StdAttachments {
self: Analyzer =>
+ type UnaffiliatedMacroContext = scala.reflect.makro.runtime.Context
+ type MacroContext = UnaffiliatedMacroContext { val mirror: self.global.type }
case class MacroAttachment(delayed: Boolean, typerContext: Context, macroContext: Option[MacroContext])
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 88118adbe5..a2ef06fe38 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -5213,7 +5213,8 @@ trait Typers extends Modes with Adaptations with Taggings {
}
val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous))
- if (isMacroBodyOkay) computeMacroDefTypeFromMacroImpl(ddef, tree.symbol, tree1.symbol) else AnyClass.tpe
+ val shouldInheritMacroImplReturnType = ddef.tpt.isEmpty
+ if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree.symbol, tree1.symbol) else AnyClass.tpe
}
def transformedOr(tree: Tree, op: => Tree): Tree = transformed.get(tree) match {
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
new file mode 100644
index 0000000000..738bcd01a7
--- /dev/null
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -0,0 +1,46 @@
+package scala.tools
+package reflect
+
+import scala.reflect.reify.Taggers
+import scala.tools.nsc.typechecker.{Analyzer, Macros}
+
+/** Optimizes system macro expansions by hardwiring them directly to their implementations
+ * bypassing standard reflective load and invoke to avoid the overhead of Java/Scala reflection.
+ */
+trait FastTrack {
+ self: Macros with Analyzer =>
+
+ import global._
+ import definitions._
+
+ import language.implicitConversions
+ private implicit def context2taggers(c0: MacroContext) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
+
+ implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args)
+ type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree]
+ case class FastTrackEntry(sym: Symbol, expander: FastTrackExpander) {
+ def validate(argss: List[List[Any]]): Boolean = {
+ val c = argss.flatten.apply(0).asInstanceOf[MacroContext]
+ val isValid = expander isDefinedAt (c, c.expandee)
+ isValid
+ }
+ def run(args: List[Any]): Any = {
+ val c = args(0).asInstanceOf[MacroContext]
+ val result = expander((c, c.expandee))
+ c.Expr[Nothing](result)(c.TypeTag.Nothing)
+ }
+ }
+
+ lazy val fastTrack: Map[Symbol, FastTrackEntry] = {
+ var registry = Map[Symbol, FastTrackEntry]()
+ implicit class BindTo(sym: Symbol) { def bindTo(expander: FastTrackExpander): Unit = if (sym != NoSymbol) registry += sym -> FastTrackEntry(sym, expander) }
+ MacroInternal_materializeArrayTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeArrayTag(u, tt.tpe) }
+ MacroInternal_materializeErasureTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeErasureTag(u, tt.tpe, concrete = false) }
+ MacroInternal_materializeClassTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeClassTag(u, tt.tpe) }
+ MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, tt.tpe, concrete = false) }
+ MacroInternal_materializeConcreteTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, tt.tpe, concrete = true) }
+ ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, expr) }
+ MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, expr) }
+ registry
+ }
+} \ No newline at end of file
diff --git a/src/library/scala/reflect/api/Universe.scala b/src/library/scala/reflect/api/Universe.scala
index 05b5963c73..ce1b806812 100755
--- a/src/library/scala/reflect/api/Universe.scala
+++ b/src/library/scala/reflect/api/Universe.scala
@@ -33,7 +33,7 @@ abstract class Universe extends Symbols
* }}}
*
* The reifier transforms it to the following expression:
- *
+ *
* {{{
* <[
* val $mr: scala.reflect.api.Universe = <reference to the Universe that calls the reify>
@@ -66,12 +66,6 @@ abstract class Universe extends Symbols
* * Since reified trees can be compiled outside of the scope they've been created in,
* special measures are taken to ensure that all members accessed in the reifee remain visible
*/
- def reify[T](expr: T): Expr[T] = macro Universe.reify[T]
-}
-
-object Universe {
- def reify[T](cc: scala.reflect.makro.Context{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = {
- import scala.reflect.makro.internal._
- cc.Expr(cc.materializeExpr(cc.prefix.tree, expr.tree))
- }
-}
+ // implementation is magically hardwired to `scala.reflect.reify.Taggers`
+ def reify[T](expr: T): Expr[T] = macro ???
+} \ No newline at end of file
diff --git a/src/library/scala/reflect/makro/Context.scala b/src/library/scala/reflect/makro/Context.scala
index b8fb0dcce5..b0e15fd572 100644
--- a/src/library/scala/reflect/makro/Context.scala
+++ b/src/library/scala/reflect/makro/Context.scala
@@ -28,17 +28,6 @@ trait Context extends Aliases
val prefix: Expr[PrefixType]
/** Alias to the underlying mirror's reify */
- def reify[T](expr: T): Expr[T] = macro Context.reify[T]
-}
-
-object Context {
- def reify[T](cc: Context{ type PrefixType = Context })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = {
- import cc.mirror._
- import scala.reflect.makro.internal._
- // [Eugene] how do I typecheck this without undergoing this tiresome (and, in general, incorrect) procedure?
- val prefix: Tree = Select(cc.prefix.tree, newTermName("mirror"))
- val prefixTpe = cc.typeCheck(TypeApply(Select(prefix, newTermName("asInstanceOf")), List(SingletonTypeTree(prefix)))).tpe
- prefix setType prefixTpe
- cc.Expr(cc.materializeExpr(prefix, expr.tree))
- }
+ // implementation is magically hardwired to `scala.reflect.reify.Taggers`
+ def reify[T](expr: T): Expr[T] = macro ???
}
diff --git a/src/library/scala/reflect/makro/internal/Utils.scala b/src/library/scala/reflect/makro/internal/Utils.scala
deleted file mode 100644
index 3032d8e05d..0000000000
--- a/src/library/scala/reflect/makro/internal/Utils.scala
+++ /dev/null
@@ -1,148 +0,0 @@
-package scala.reflect.makro
-
-import scala.reflect.api.Universe
-import language.implicitConversions
-import language.experimental.macros
-
-/** This package is required by the compiler and <b>should not be used in client code</b>. */
-package object internal {
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeArrayTag[T](u: Universe): ArrayTag[T] = macro materializeArrayTag_impl[T]
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeArrayTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ArrayTag[T]] =
- c.Expr[Nothing](c.materializeArrayTag(u.tree, implicitly[c.TypeTag[T]].tpe))(c.TypeTag.Nothing)
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeErasureTag[T](u: Universe): ErasureTag[T] = macro materializeErasureTag_impl[T]
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeErasureTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ErasureTag[T]] =
- c.Expr[Nothing](c.materializeErasureTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = false))(c.TypeTag.Nothing)
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeClassTag[T](u: Universe): ClassTag[T] = macro materializeClassTag_impl[T]
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeClassTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ClassTag[T]] =
- c.Expr[Nothing](c.materializeClassTag(u.tree, implicitly[c.TypeTag[T]].tpe))(c.TypeTag.Nothing)
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeTypeTag[T](u: Universe): u.TypeTag[T] = macro materializeTypeTag_impl[T]
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.TypeTag[T]] =
- c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = false))(c.TypeTag.Nothing)
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeConcreteTypeTag[T](u: Universe): u.ConcreteTypeTag[T] = macro materializeConcreteTypeTag_impl[T]
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- def materializeConcreteTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.ConcreteTypeTag[T]] =
- c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = true))(c.TypeTag.Nothing)
-
- /** This method is required by the compiler and <b>should not be used in client code</b>. */
- private[scala] implicit def context2utils(c0: Context) : Utils { val c: c0.type } = new { val c: c0.type = c0 } with Utils
-}
-
-package internal {
- private[scala] abstract class Utils {
- val c: Context
-
- import c.mirror._
- import definitions._
-
- val coreTags = Map(
- ByteClass.asType -> newTermName("Byte"),
- ShortClass.asType -> newTermName("Short"),
- CharClass.asType -> newTermName("Char"),
- IntClass.asType -> newTermName("Int"),
- LongClass.asType -> newTermName("Long"),
- FloatClass.asType -> newTermName("Float"),
- DoubleClass.asType -> newTermName("Double"),
- BooleanClass.asType -> newTermName("Boolean"),
- UnitClass.asType -> newTermName("Unit"),
- AnyClass.asType -> newTermName("Any"),
- ObjectClass.asType -> newTermName("Object"),
- AnyValClass.asType -> newTermName("AnyVal"),
- AnyRefClass.asType -> newTermName("AnyRef"),
- NothingClass.asType -> newTermName("Nothing"),
- NullClass.asType -> newTermName("Null"),
- StringClass.asType -> newTermName("String"))
-
- // todo. the following two methods won't be necessary once we implement implicit macro generators for tags
-
- def materializeArrayTag(prefix: Tree, tpe: Type): Tree =
- materializeClassTag(prefix, tpe)
-
- def materializeErasureTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree =
- if (concrete) materializeClassTag(prefix, tpe) else materializeTypeTag(prefix, tpe, concrete = false)
-
- def materializeClassTag(prefix: Tree, tpe: Type): Tree =
- materializeTag(prefix, tpe, ClassTagModule, {
- val erasure = c.reifyErasure(tpe, concrete = true)
- val factory = TypeApply(Select(Ident(ClassTagModule), "apply"), List(TypeTree(tpe)))
- Apply(factory, List(erasure))
- })
-
- def materializeTypeTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = {
- val tagModule = if (concrete) ConcreteTypeTagModule else TypeTagModule
- materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, concrete = concrete))
- }
-
- private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = {
- val result =
- tpe match {
- case coreTpe if coreTags contains coreTpe =>
- val ref = if (tagModule.owner.isPackageClass) Ident(tagModule) else Select(prefix, tagModule.name)
- Select(ref, coreTags(coreTpe))
- case _ =>
- val manifestInScope = nonSyntheticManifestInScope(tpe)
- if (manifestInScope.isEmpty) translatingReificationErrors(materializer)
- else gen.mkMethodCall(staticModule("scala.reflect.package"), newTermName("manifestToConcreteTypeTag"), List(tpe), List(manifestInScope))
- }
- try c.typeCheck(result)
- catch { case terr @ c.TypeError(pos, msg) => failTag(result, terr) }
- }
-
- private def nonSyntheticManifestInScope(tpe: Type) = {
- val ManifestClass = staticClass("scala.reflect.Manifest")
- val ManifestModule = staticModule("scala.reflect.Manifest")
- val manifest = c.inferImplicitValue(appliedType(ManifestClass.asTypeConstructor, List(tpe)))
- val notOk = manifest.isEmpty || (manifest exists (sub => sub.symbol != null && (sub.symbol == ManifestModule || sub.symbol.owner == ManifestModule)))
- if (notOk) EmptyTree else manifest
- }
-
- def materializeExpr(prefix: Tree, expr: Tree): Tree = {
- val result = translatingReificationErrors(c.reifyTree(prefix, expr))
- try c.typeCheck(result)
- catch { case terr @ c.TypeError(pos, msg) => failExpr(result, terr) }
- }
-
- private def translatingReificationErrors(materializer: => Tree): Tree = {
- try materializer
- catch {
- case ReificationError(pos, msg) =>
- c.error(pos.asInstanceOf[c.Position], msg) // this cast is a very small price for the sanity of exception handling
- EmptyTree
- case UnexpectedReificationError(pos, err, cause) if cause != null =>
- throw cause
- }
- }
-
- private def failTag(result: Tree, reason: Any): Nothing = {
- val Apply(TypeApply(fun, List(tpeTree)), _) = c.macroApplication
- val tpe = tpeTree.tpe
- val PolyType(_, MethodType(_, tagTpe)) = fun.tpe
- val tagModule = tagTpe.typeSymbol.companionSymbol
- if (c.compilerSettings.contains("-Xlog-implicits"))
- c.echo(c.enclosingPosition, s"cannot materialize ${tagModule.name}[$tpe] as $result because:\n$reason")
- c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe))
- }
-
- private def failExpr(result: Tree, reason: Any): Nothing = {
- val Apply(_, expr :: Nil) = c.macroApplication
- c.abort(c.enclosingPosition, s"Cannot materialize $expr as $result because:\n$reason")
- }
- }
-}
diff --git a/src/library/scala/reflect/makro/internal/macroImpl.scala b/src/library/scala/reflect/makro/internal/macroImpl.scala
index 9cf4d23072..0dfa8d1654 100644
--- a/src/library/scala/reflect/makro/internal/macroImpl.scala
+++ b/src/library/scala/reflect/makro/internal/macroImpl.scala
@@ -1,5 +1,18 @@
package scala.reflect.makro
package internal
-/** This type is required by the compiler and <b>should not be used in client code</b>. */
-class macroImpl(val referenceToMacroImpl: Any) extends annotation.StaticAnnotation
+/** Links macro definitions with their implementation.
+ * This is necessary to preserve macro def -> macro impl links between compilation runs.
+ *
+ * More precisely, after typechecking right-hand side of a macro def
+ * `typedMacroBody` slaps `macroImpl` annotation onto the macro def
+ * with the result of typechecking as a sole parameter.
+ *
+ * As an unfortunate consequence, this annotation must be defined in scala-library.jar,
+ * because anyone (even those programmers who compile their programs with only scala-library on classpath)
+ * must be able to define macros.
+ *
+ * To lessen the weirdness we define this annotation as `private[scala]`.
+ * It will not prevent pickling, but it will prevent application developers (and scaladocs) from seeing the annotation.
+ */
+private[scala] class macroImpl(val referenceToMacroImpl: Any) extends annotation.StaticAnnotation
diff --git a/src/library/scala/reflect/makro/internal/package.scala b/src/library/scala/reflect/makro/internal/package.scala
new file mode 100644
index 0000000000..4c4acec096
--- /dev/null
+++ b/src/library/scala/reflect/makro/internal/package.scala
@@ -0,0 +1,17 @@
+package scala.reflect.makro
+
+import language.experimental.macros
+import scala.reflect.api.{Universe => ApiUniverse}
+
+// anchors for materialization macros emitted during tag materialization in Implicits.scala
+// implementation is magically hardwired into `scala.reflect.reify.Taggers`
+//
+// todo. once we have implicit macros for tag generation, we can remove these anchors
+// [Eugene++] how do I hide this from scaladoc?
+package object internal {
+ private[scala] def materializeArrayTag[T](u: ApiUniverse): ArrayTag[T] = macro ???
+ private[scala] def materializeErasureTag[T](u: ApiUniverse): ErasureTag[T] = macro ???
+ private[scala] def materializeClassTag[T](u: ApiUniverse): ClassTag[T] = macro ???
+ private[scala] def materializeTypeTag[T](u: ApiUniverse): u.TypeTag[T] = macro ???
+ private[scala] def materializeConcreteTypeTag[T](u: ApiUniverse): u.ConcreteTypeTag[T] = macro ???
+}
diff --git a/test/files/run/macro-invalidusage-partialapplication-with-tparams.check b/test/files/run/macro-invalidusage-partialapplication-with-tparams.check
new file mode 100644
index 0000000000..73f57b0b81
--- /dev/null
+++ b/test/files/run/macro-invalidusage-partialapplication-with-tparams.check
@@ -0,0 +1,3 @@
+reflective compilation has failed:
+
+macros cannot be partially applied
diff --git a/test/files/run/macro-invalidusage-partialapplication-with-tparams.flags b/test/files/run/macro-invalidusage-partialapplication-with-tparams.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/files/run/macro-invalidusage-partialapplication-with-tparams.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala b/test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala
new file mode 100644
index 0000000000..67a19a6d62
--- /dev/null
+++ b/test/files/run/macro-invalidusage-partialapplication-with-tparams/Impls_Macros_1.scala
@@ -0,0 +1,13 @@
+import scala.reflect.makro.{Context => Ctx}
+
+object Impls {
+ def foo[T: c.TypeTag](c: Ctx)(x: c.Expr[T]) = {
+ import c.universe._
+ val body = Apply(Select(Ident(definitions.PredefModule), newTermName("println")), List(Literal(Constant(x.tree.toString))))
+ c.Expr[Unit](body)
+ }
+}
+
+object Macros {
+ def foo[T](x: T) = macro Impls.foo[T]
+} \ No newline at end of file
diff --git a/test/files/run/macro-invalidusage-partialapplication-with-tparams/Test_2.scala b/test/files/run/macro-invalidusage-partialapplication-with-tparams/Test_2.scala
new file mode 100644
index 0000000000..f51cc7e699
--- /dev/null
+++ b/test/files/run/macro-invalidusage-partialapplication-with-tparams/Test_2.scala
@@ -0,0 +1,8 @@
+object Test extends App {
+ import scala.reflect.runtime.universe._
+ import scala.reflect.runtime.{currentMirror => cm}
+ import scala.tools.reflect.ToolBox
+ val tree = Select(Ident("Macros"), newTermName("foo"))
+ try cm.mkToolBox().runExpr(tree)
+ catch { case ex: Throwable => println(ex.getMessage) }
+}