From 463ef75e2f8e15d2e835dd3c2467206fd52b6246 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Wed, 27 Feb 2013 15:15:36 +0100 Subject: refactors macro runtimes Following typedMacroBody, macroRuntime along with its friends has also been moved out into a separate component. --- .../macros/compiler/DefaultMacroCompiler.scala | 2 +- .../scala/reflect/macros/contexts/Aliases.scala | 35 +++++++++ .../scala/reflect/macros/contexts/Context.scala | 29 ++++++++ .../scala/reflect/macros/contexts/Enclosures.scala | 36 +++++++++ .../scala/reflect/macros/contexts/Evals.scala | 18 +++++ .../scala/reflect/macros/contexts/ExprUtils.scala | 34 +++++++++ .../scala/reflect/macros/contexts/FrontEnds.scala | 22 ++++++ .../reflect/macros/contexts/Infrastructure.scala | 16 ++++ .../scala/reflect/macros/contexts/Names.scala | 26 +++++++ .../scala/reflect/macros/contexts/Parsers.scala | 24 ++++++ .../scala/reflect/macros/contexts/Reifiers.scala | 77 +++++++++++++++++++ .../scala/reflect/macros/contexts/Synthetics.scala | 66 ++++++++++++++++ .../scala/reflect/macros/contexts/Traces.scala | 8 ++ .../scala/reflect/macros/contexts/Typers.scala | 52 +++++++++++++ .../scala/reflect/macros/runtime/Aliases.scala | 35 --------- .../scala/reflect/macros/runtime/Context.scala | 29 -------- .../scala/reflect/macros/runtime/Enclosures.scala | 36 --------- .../scala/reflect/macros/runtime/Evals.scala | 18 ----- .../scala/reflect/macros/runtime/ExprUtils.scala | 34 --------- .../scala/reflect/macros/runtime/FrontEnds.scala | 20 ----- .../reflect/macros/runtime/Infrastructure.scala | 16 ---- .../macros/runtime/JavaReflectionRuntimes.scala | 31 ++++++++ .../reflect/macros/runtime/MacroRuntimes.scala | 74 ++++++++++++++++++ .../scala/reflect/macros/runtime/Names.scala | 26 ------- .../scala/reflect/macros/runtime/Parsers.scala | 24 ------ .../scala/reflect/macros/runtime/Reifiers.scala | 77 ------------------- .../macros/runtime/ScalaReflectionRuntimes.scala | 33 ++++++++ .../scala/reflect/macros/runtime/Synthetics.scala | 66 ---------------- .../scala/reflect/macros/runtime/Traces.scala | 8 -- .../scala/reflect/macros/runtime/Typers.scala | 52 ------------- .../scala/reflect/macros/runtime/package.scala | 5 ++ src/compiler/scala/reflect/reify/Taggers.scala | 2 +- .../scala/tools/nsc/typechecker/Macros.scala | 87 +++------------------- .../tools/nsc/typechecker/StdAttachments.scala | 2 +- .../scala/tools/reflect/MacroImplementations.scala | 2 +- 35 files changed, 601 insertions(+), 521 deletions(-) create mode 100644 src/compiler/scala/reflect/macros/contexts/Aliases.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Context.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Enclosures.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Evals.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/ExprUtils.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/FrontEnds.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Infrastructure.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Names.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Parsers.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Reifiers.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Synthetics.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Traces.scala create mode 100644 src/compiler/scala/reflect/macros/contexts/Typers.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Aliases.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Context.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Enclosures.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Evals.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/ExprUtils.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/FrontEnds.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Infrastructure.scala create mode 100644 src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala create mode 100644 src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Names.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Parsers.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Reifiers.scala create mode 100644 src/compiler/scala/reflect/macros/runtime/ScalaReflectionRuntimes.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Synthetics.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Traces.scala delete mode 100644 src/compiler/scala/reflect/macros/runtime/Typers.scala create mode 100644 src/compiler/scala/reflect/macros/runtime/package.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala index 749e730c0e..32c6da8007 100644 --- a/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala +++ b/src/compiler/scala/reflect/macros/compiler/DefaultMacroCompiler.scala @@ -2,7 +2,7 @@ package scala.reflect.macros package compiler import scala.tools.nsc.Global -import scala.reflect.macros.runtime.Context +import scala.reflect.macros.contexts.Context abstract class DefaultMacroCompiler extends Resolvers with Validators diff --git a/src/compiler/scala/reflect/macros/contexts/Aliases.scala b/src/compiler/scala/reflect/macros/contexts/Aliases.scala new file mode 100644 index 0000000000..cc64d97d85 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Aliases.scala @@ -0,0 +1,35 @@ +package scala.reflect.macros +package contexts + +trait Aliases { + self: Context => + + override type Symbol = universe.Symbol + override type Type = universe.Type + override type Name = universe.Name + override type TermName = universe.TermName + override type TypeName = universe.TypeName + override type Tree = universe.Tree + override type Position = universe.Position + override type Scope = universe.Scope + override type Modifiers = universe.Modifiers + + override type Expr[+T] = universe.Expr[T] + override val Expr = universe.Expr + def Expr[T: WeakTypeTag](tree: Tree): Expr[T] = universe.Expr[T](mirror, universe.FixedMirrorTreeCreator(mirror, tree)) + + override type WeakTypeTag[T] = universe.WeakTypeTag[T] + override type TypeTag[T] = universe.TypeTag[T] + override val WeakTypeTag = universe.WeakTypeTag + override val TypeTag = universe.TypeTag + def WeakTypeTag[T](tpe: Type): WeakTypeTag[T] = universe.WeakTypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) + def TypeTag[T](tpe: Type): TypeTag[T] = universe.TypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) + override def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag + override def typeTag[T](implicit ttag: TypeTag[T]) = ttag + override def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe + override def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe + + implicit class RichOpenImplicit(oi: universe.analyzer.OpenImplicit) { + def toImplicitCandidate = ImplicitCandidate(oi.info.pre, oi.info.sym, oi.pt, oi.tree) + } +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/contexts/Context.scala b/src/compiler/scala/reflect/macros/contexts/Context.scala new file mode 100644 index 0000000000..bd1d7d5248 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Context.scala @@ -0,0 +1,29 @@ +package scala.reflect.macros +package contexts + +import scala.tools.nsc.Global + +abstract class Context extends scala.reflect.macros.Context + with Aliases + with Enclosures + with Names + with Reifiers + with FrontEnds + with Infrastructure + with Typers + with Parsers + with Evals + with ExprUtils + with Synthetics + with Traces { + + val universe: Global + + val mirror: universe.Mirror = universe.rootMirror + + val callsiteTyper: universe.analyzer.Typer + + val prefix: Expr[PrefixType] + + val expandee: Tree +} diff --git a/src/compiler/scala/reflect/macros/contexts/Enclosures.scala b/src/compiler/scala/reflect/macros/contexts/Enclosures.scala new file mode 100644 index 0000000000..bb88c8d5e1 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Enclosures.scala @@ -0,0 +1,36 @@ +package scala.reflect.macros +package contexts + +import scala.reflect.{ClassTag, classTag} + +trait Enclosures { + self: Context => + + import universe._ + + type MacroRole = analyzer.MacroRole + def APPLY_ROLE = analyzer.APPLY_ROLE + def macroRole: MacroRole + + private lazy val site = callsiteTyper.context + private lazy val enclTrees = site.enclosingContextChain map (_.tree) + private lazy val enclPoses = enclosingMacros map (_.macroApplication.pos) filterNot (_ eq NoPosition) + + private def lenientEnclosure[T <: Tree : ClassTag]: Tree = enclTrees collectFirst { case x: T => x } getOrElse EmptyTree + private def strictEnclosure[T <: Tree : ClassTag]: T = enclTrees collectFirst { case x: T => x } getOrElse (throw new EnclosureException(classTag[T].runtimeClass, enclTrees)) + + // vals are eager to simplify debugging + // after all we wouldn't save that much time by making them lazy + val macroApplication: Tree = expandee + def enclosingPackage: PackageDef = strictEnclosure[PackageDef] + val enclosingClass: Tree = lenientEnclosure[ImplDef] + def enclosingImpl: ImplDef = strictEnclosure[ImplDef] + def enclosingTemplate: Template = strictEnclosure[Template] + val enclosingImplicits: List[ImplicitCandidate] = site.openImplicits.map(_.toImplicitCandidate) + val enclosingMacros: List[Context] = this :: universe.analyzer.openMacros // include self + val enclosingMethod: Tree = lenientEnclosure[DefDef] + def enclosingDef: DefDef = strictEnclosure[DefDef] + val enclosingPosition: Position = if (enclPoses.isEmpty) NoPosition else enclPoses.head.pos + val enclosingUnit: CompilationUnit = universe.currentRun.currentUnit + val enclosingRun: Run = universe.currentRun +} diff --git a/src/compiler/scala/reflect/macros/contexts/Evals.scala b/src/compiler/scala/reflect/macros/contexts/Evals.scala new file mode 100644 index 0000000000..84928ddf86 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Evals.scala @@ -0,0 +1,18 @@ +package scala.reflect.macros +package contexts + +import scala.reflect.runtime.{universe => ru} +import scala.tools.reflect.ToolBox + +trait Evals { + self: Context => + + private lazy val evalMirror = ru.runtimeMirror(universe.analyzer.defaultMacroClassloader) + private lazy val evalToolBox = evalMirror.mkToolBox() + private lazy val evalImporter = ru.mkImporter(universe).asInstanceOf[ru.Importer { val from: universe.type }] + + def eval[T](expr: Expr[T]): T = { + val imported = evalImporter.importTree(expr.tree) + evalToolBox.eval(imported).asInstanceOf[T] + } +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/contexts/ExprUtils.scala b/src/compiler/scala/reflect/macros/contexts/ExprUtils.scala new file mode 100644 index 0000000000..4846325d1e --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/ExprUtils.scala @@ -0,0 +1,34 @@ +package scala.reflect.macros +package contexts + +trait ExprUtils { + self: Context => + + import universe._ + + def literalNull = Expr[Null](Literal(Constant(null)))(TypeTag.Null) + + def literalUnit = Expr[Unit](Literal(Constant(())))(TypeTag.Unit) + + def literalTrue = Expr[Boolean](Literal(Constant(true)))(TypeTag.Boolean) + + def literalFalse = Expr[Boolean](Literal(Constant(false)))(TypeTag.Boolean) + + def literal(x: Boolean) = Expr[Boolean](Literal(Constant(x)))(TypeTag.Boolean) + + def literal(x: Byte) = Expr[Byte](Literal(Constant(x)))(TypeTag.Byte) + + def literal(x: Short) = Expr[Short](Literal(Constant(x)))(TypeTag.Short) + + def literal(x: Int) = Expr[Int](Literal(Constant(x)))(TypeTag.Int) + + def literal(x: Long) = Expr[Long](Literal(Constant(x)))(TypeTag.Long) + + def literal(x: Float) = Expr[Float](Literal(Constant(x)))(TypeTag.Float) + + def literal(x: Double) = Expr[Double](Literal(Constant(x)))(TypeTag.Double) + + def literal(x: String) = Expr[String](Literal(Constant(x)))(TypeTag[String](definitions.StringClass.toTypeConstructor)) + + def literal(x: Char) = Expr[Char](Literal(Constant(x)))(TypeTag.Char) +} diff --git a/src/compiler/scala/reflect/macros/contexts/FrontEnds.scala b/src/compiler/scala/reflect/macros/contexts/FrontEnds.scala new file mode 100644 index 0000000000..fda05de09c --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/FrontEnds.scala @@ -0,0 +1,22 @@ +package scala.reflect.macros +package contexts + +import scala.reflect.macros.runtime.AbortMacroException + +trait FrontEnds { + self: Context => + + def echo(pos: Position, msg: String): Unit = universe.reporter.echo(pos, msg) + + def info(pos: Position, msg: String, force: Boolean): Unit = universe.reporter.info(pos, msg, force) + + def hasWarnings: Boolean = universe.reporter.hasErrors + + def hasErrors: Boolean = universe.reporter.hasErrors + + def warning(pos: Position, msg: String): Unit = callsiteTyper.context.warning(pos, msg) + + def error(pos: Position, msg: String): Unit = callsiteTyper.context.error(pos, msg) + + def abort(pos: Position, msg: String): Nothing = throw new AbortMacroException(pos, msg) +} diff --git a/src/compiler/scala/reflect/macros/contexts/Infrastructure.scala b/src/compiler/scala/reflect/macros/contexts/Infrastructure.scala new file mode 100644 index 0000000000..df7aa4d2be --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Infrastructure.scala @@ -0,0 +1,16 @@ +package scala.reflect.macros +package contexts + +trait Infrastructure { + self: Context => + + def settings: List[String] = { + val us = universe.settings + import us._ + userSetSettings collectFirst { case x: MultiStringSetting if x.name == XmacroSettings.name => x.value } getOrElse Nil + } + + def compilerSettings: List[String] = universe.settings.recreateArgs + + def classPath: List[java.net.URL] = global.classPath.asURLs +} diff --git a/src/compiler/scala/reflect/macros/contexts/Names.scala b/src/compiler/scala/reflect/macros/contexts/Names.scala new file mode 100644 index 0000000000..e535754a98 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Names.scala @@ -0,0 +1,26 @@ +package scala.reflect.macros +package contexts + +trait Names { + self: Context => + + lazy val freshNameCreator = callsiteTyper.context.unit.fresh + + def fresh(): String = + freshName() + + def fresh(name: String): String = + freshName(name) + + def fresh[NameType <: Name](name: NameType): NameType = + freshName[NameType](name) + + def freshName(): String = + freshNameCreator.newName() + + def freshName(name: String): String = + freshNameCreator.newName(name) + + def freshName[NameType <: Name](name: NameType): NameType = + name.mapName(freshNameCreator.newName(_)).asInstanceOf[NameType] +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/contexts/Parsers.scala b/src/compiler/scala/reflect/macros/contexts/Parsers.scala new file mode 100644 index 0000000000..3dab02beba --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Parsers.scala @@ -0,0 +1,24 @@ +package scala.reflect.macros +package contexts + +import scala.language.existentials +import scala.tools.reflect.ToolBox +import scala.tools.reflect.ToolBoxError + +trait Parsers { + self: Context => + + def parse(code: String): Tree = + // todo. provide decent implementation + // see `Typers.typedUseCase` for details + try { + import scala.reflect.runtime.{universe => ru} + val parsed = ru.rootMirror.mkToolBox().parse(code) + val importer = universe.mkImporter(ru) + importer.importTree(parsed) + } catch { + case ToolBoxError(msg, cause) => + // todo. provide a position + throw new ParseException(universe.NoPosition, msg) + } +} diff --git a/src/compiler/scala/reflect/macros/contexts/Reifiers.scala b/src/compiler/scala/reflect/macros/contexts/Reifiers.scala new file mode 100644 index 0000000000..ecef1c7289 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Reifiers.scala @@ -0,0 +1,77 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Gilles Dubochet + */ + +package scala.reflect.macros +package contexts + +trait Reifiers { + self: Context => + + val global: universe.type = universe + import universe._ + import definitions._ + + def reifyTree(universe: Tree, mirror: Tree, tree: Tree): Tree = { + assert(ExprClass != NoSymbol) + val result = scala.reflect.reify.`package`.reifyTree(self.universe)(callsiteTyper, universe, mirror, tree) + logFreeVars(enclosingPosition, result) + result + } + + def reifyType(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean = false): Tree = { + assert(TypeTagsClass != NoSymbol) + val result = scala.reflect.reify.`package`.reifyType(self.universe)(callsiteTyper, universe, mirror, tpe, concrete) + logFreeVars(enclosingPosition, result) + result + } + + def reifyRuntimeClass(tpe: Type, concrete: Boolean = true): Tree = + scala.reflect.reify.`package`.reifyRuntimeClass(universe)(callsiteTyper, tpe, concrete = concrete) + + def reifyEnclosingRuntimeClass: Tree = + scala.reflect.reify.`package`.reifyEnclosingRuntimeClass(universe)(callsiteTyper) + + def unreifyTree(tree: Tree): Tree = { + assert(ExprSplice != NoSymbol) + Select(tree, ExprSplice) + } + + // fixme: if I put utils here, then "global" from utils' early initialization syntax + // and "global" that comes from here conflict with each other when incrementally compiling + // the problem is that both are pickled with the same owner - trait Reifiers + // and this upsets the compiler, so that oftentimes it throws assertion failures + // Martin knows the details + // + // object utils extends { + // val global: self.global.type = self.global + // val typer: global.analyzer.Typer = self.callsiteTyper + // } with scala.reflect.reify.utils.Utils + // import utils._ + + private def logFreeVars(position: Position, reification: Tree): Unit = { + object utils extends { + val global: self.global.type = self.global + val typer: global.analyzer.Typer = self.callsiteTyper + } with scala.reflect.reify.utils.Utils + import utils._ + + def logFreeVars(symtab: SymbolTable): Unit = + // logging free vars only when they are untyped prevents avalanches of duplicate messages + symtab.syms map (sym => symtab.symDef(sym)) foreach { + case FreeTermDef(_, _, binding, _, origin) if universe.settings.logFreeTerms && binding.tpe == null => + reporter.echo(position, "free term: %s %s".format(showRaw(binding), origin)) + case FreeTypeDef(_, _, binding, _, origin) if universe.settings.logFreeTypes && binding.tpe == null => + reporter.echo(position, "free type: %s %s".format(showRaw(binding), origin)) + case _ => + // do nothing + } + + if (universe.settings.logFreeTerms || universe.settings.logFreeTypes) + reification match { + case ReifiedTree(_, _, symtab, _, _, _, _) => logFreeVars(symtab) + case ReifiedType(_, _, symtab, _, _, _) => logFreeVars(symtab) + } + } +} diff --git a/src/compiler/scala/reflect/macros/contexts/Synthetics.scala b/src/compiler/scala/reflect/macros/contexts/Synthetics.scala new file mode 100644 index 0000000000..ada16a8113 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Synthetics.scala @@ -0,0 +1,66 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + */ + +package scala.reflect.macros +package contexts + +import scala.reflect.internal.Flags._ +import scala.reflect.internal.util.BatchSourceFile +import scala.reflect.io.VirtualFile + +trait Synthetics { + self: Context => + + import global._ + import mirror.wrapMissing + + // getClassIfDefined and getModuleIfDefined cannot be used here + // because they don't work for stuff declared in the empty package + // (as specified in SLS, code inside non-empty packages cannot see + // declarations from the empty package, so compiler internals + // default to ignoring contents of the empty package) + // to the contrast, staticModule and staticClass are designed + // to be a part of the reflection API and, therefore, they + // correctly resolve all names + private def topLevelSymbol(name: Name): Symbol = wrapMissing { + if (name.isTermName) mirror.staticModule(name.toString) + else mirror.staticClass(name.toString) + } + + def topLevelDef(name: Name): Tree = + enclosingRun.units.toList.map(_.body).flatMap { + // it's okay to check `stat.symbol` here, because currently macros expand strictly after namer + // which means that by the earliest time one can call this method all top-level definitions will have already been entered + case PackageDef(_, stats) => stats filter (stat => stat.symbol != NoSymbol && stat.symbol == topLevelSymbol(name)) + case _ => Nil // should never happen, but better be safe than sorry + }.headOption getOrElse EmptyTree + + def topLevelRef(name: Name): Tree = { + if (topLevelDef(name).nonEmpty) gen.mkUnattributedRef(name) + else EmptyTree + } + + def introduceTopLevel[T: PackageSpec](packagePrototype: T, definition: universe.ImplDef): RefTree = + introduceTopLevel(packagePrototype, List(definition)).head + + def introduceTopLevel[T: PackageSpec](packagePrototype: T, definitions: universe.ImplDef*): List[RefTree] = + introduceTopLevel(packagePrototype, definitions.toList) + + private def introduceTopLevel[T: PackageSpec](packagePrototype: T, definitions: List[universe.ImplDef]): List[RefTree] = { + val code @ PackageDef(pid, _) = implicitly[PackageSpec[T]].mkPackageDef(packagePrototype, definitions) + universe.currentRun.compileLate(code) + definitions map (definition => Select(pid, definition.name)) + } + + protected def mkPackageDef(name: String, stats: List[Tree]) = gen.mkPackageDef(name, stats) + + protected def mkPackageDef(name: TermName, stats: List[Tree]) = gen.mkPackageDef(name.toString, stats) + + protected def mkPackageDef(tree: RefTree, stats: List[Tree]) = PackageDef(tree, stats) + + protected def mkPackageDef(sym: Symbol, stats: List[Tree]) = { + assert(sym hasFlag PACKAGE, s"expected a package or package class symbol, found: $sym") + gen.mkPackageDef(sym.fullName.toString, stats) + } +} diff --git a/src/compiler/scala/reflect/macros/contexts/Traces.scala b/src/compiler/scala/reflect/macros/contexts/Traces.scala new file mode 100644 index 0000000000..df47f6ba81 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Traces.scala @@ -0,0 +1,8 @@ +package scala.reflect.macros +package contexts + +trait Traces extends util.Traces { + self: Context => + + def globalSettings = universe.settings +} diff --git a/src/compiler/scala/reflect/macros/contexts/Typers.scala b/src/compiler/scala/reflect/macros/contexts/Typers.scala new file mode 100644 index 0000000000..4a1122b913 --- /dev/null +++ b/src/compiler/scala/reflect/macros/contexts/Typers.scala @@ -0,0 +1,52 @@ +package scala.reflect.macros +package contexts + +import scala.reflect.internal.Mode + +trait Typers { + self: Context => + + def openMacros: List[Context] = this :: universe.analyzer.openMacros + + def openImplicits: List[ImplicitCandidate] = callsiteTyper.context.openImplicits.map(_.toImplicitCandidate) + + /** + * @see [[scala.tools.reflect.ToolBox.typeCheck]] + */ + def typeCheck(tree: Tree, 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(tree, pt), reportAmbiguousErrors = false) match { + case universe.analyzer.SilentResultValue(result) => + macroLogVerbose(result) + result + case error @ universe.analyzer.SilentTypeError(_) => + 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 = { + macroLogVerbose("inferring implicit value of type %s, macros = %s".format(pt, !withMacrosDisabled)) + universe.analyzer.inferImplicit(universe.EmptyTree, pt, false, callsiteTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw TypecheckException(pos, msg)) + } + + def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = { + macroLogVerbose("inferring implicit view from %s to %s for %s, macros = %s".format(from, to, tree, !withMacrosDisabled)) + val viewTpe = universe.appliedType(universe.definitions.FunctionClass(1).toTypeConstructor, List(from, to)) + universe.analyzer.inferImplicit(tree, viewTpe, true, callsiteTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw TypecheckException(pos, msg)) + } + + def resetAllAttrs(tree: Tree): Tree = universe.resetAllAttrs(tree) + + def resetLocalAttrs(tree: Tree): Tree = universe.resetLocalAttrs(tree) +} diff --git a/src/compiler/scala/reflect/macros/runtime/Aliases.scala b/src/compiler/scala/reflect/macros/runtime/Aliases.scala deleted file mode 100644 index 1c6703aeee..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Aliases.scala +++ /dev/null @@ -1,35 +0,0 @@ -package scala.reflect.macros -package runtime - -trait Aliases { - self: Context => - - override type Symbol = universe.Symbol - override type Type = universe.Type - override type Name = universe.Name - override type TermName = universe.TermName - override type TypeName = universe.TypeName - override type Tree = universe.Tree - override type Position = universe.Position - override type Scope = universe.Scope - override type Modifiers = universe.Modifiers - - override type Expr[+T] = universe.Expr[T] - override val Expr = universe.Expr - def Expr[T: WeakTypeTag](tree: Tree): Expr[T] = universe.Expr[T](mirror, universe.FixedMirrorTreeCreator(mirror, tree)) - - override type WeakTypeTag[T] = universe.WeakTypeTag[T] - override type TypeTag[T] = universe.TypeTag[T] - override val WeakTypeTag = universe.WeakTypeTag - override val TypeTag = universe.TypeTag - def WeakTypeTag[T](tpe: Type): WeakTypeTag[T] = universe.WeakTypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) - def TypeTag[T](tpe: Type): TypeTag[T] = universe.TypeTag[T](mirror, universe.FixedMirrorTypeCreator(mirror, tpe)) - override def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag - override def typeTag[T](implicit ttag: TypeTag[T]) = ttag - override def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe - override def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe - - implicit class RichOpenImplicit(oi: universe.analyzer.OpenImplicit) { - def toImplicitCandidate = ImplicitCandidate(oi.info.pre, oi.info.sym, oi.pt, oi.tree) - } -} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/runtime/Context.scala b/src/compiler/scala/reflect/macros/runtime/Context.scala deleted file mode 100644 index 76c684f6d7..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Context.scala +++ /dev/null @@ -1,29 +0,0 @@ -package scala.reflect.macros -package runtime - -import scala.tools.nsc.Global - -abstract class Context extends scala.reflect.macros.Context - with Aliases - with Enclosures - with Names - with Reifiers - with FrontEnds - with Infrastructure - with Typers - with Parsers - with Evals - with ExprUtils - with Synthetics - with Traces { - - val universe: Global - - val mirror: universe.Mirror = universe.rootMirror - - val callsiteTyper: universe.analyzer.Typer - - val prefix: Expr[PrefixType] - - val expandee: Tree -} diff --git a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala deleted file mode 100644 index f3f92550de..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala +++ /dev/null @@ -1,36 +0,0 @@ -package scala.reflect.macros -package runtime - -import scala.reflect.{ClassTag, classTag} - -trait Enclosures { - self: Context => - - import universe._ - - type MacroRole = analyzer.MacroRole - def APPLY_ROLE = analyzer.APPLY_ROLE - def macroRole: MacroRole - - private lazy val site = callsiteTyper.context - private lazy val enclTrees = site.enclosingContextChain map (_.tree) - private lazy val enclPoses = enclosingMacros map (_.macroApplication.pos) filterNot (_ eq NoPosition) - - private def lenientEnclosure[T <: Tree : ClassTag]: Tree = enclTrees collectFirst { case x: T => x } getOrElse EmptyTree - private def strictEnclosure[T <: Tree : ClassTag]: T = enclTrees collectFirst { case x: T => x } getOrElse (throw new EnclosureException(classTag[T].runtimeClass, enclTrees)) - - // vals are eager to simplify debugging - // after all we wouldn't save that much time by making them lazy - val macroApplication: Tree = expandee - def enclosingPackage: PackageDef = strictEnclosure[PackageDef] - val enclosingClass: Tree = lenientEnclosure[ImplDef] - def enclosingImpl: ImplDef = strictEnclosure[ImplDef] - def enclosingTemplate: Template = strictEnclosure[Template] - val enclosingImplicits: List[ImplicitCandidate] = site.openImplicits.map(_.toImplicitCandidate) - val enclosingMacros: List[Context] = this :: universe.analyzer.openMacros // include self - val enclosingMethod: Tree = lenientEnclosure[DefDef] - def enclosingDef: DefDef = strictEnclosure[DefDef] - val enclosingPosition: Position = if (enclPoses.isEmpty) NoPosition else enclPoses.head.pos - val enclosingUnit: CompilationUnit = universe.currentRun.currentUnit - val enclosingRun: Run = universe.currentRun -} diff --git a/src/compiler/scala/reflect/macros/runtime/Evals.scala b/src/compiler/scala/reflect/macros/runtime/Evals.scala deleted file mode 100644 index 1f7b5f2ff1..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Evals.scala +++ /dev/null @@ -1,18 +0,0 @@ -package scala.reflect.macros -package runtime - -import scala.reflect.runtime.{universe => ru} -import scala.tools.reflect.ToolBox - -trait Evals { - self: Context => - - private lazy val evalMirror = ru.runtimeMirror(universe.analyzer.macroClassloader) - private lazy val evalToolBox = evalMirror.mkToolBox() - private lazy val evalImporter = ru.mkImporter(universe).asInstanceOf[ru.Importer { val from: universe.type }] - - def eval[T](expr: Expr[T]): T = { - val imported = evalImporter.importTree(expr.tree) - evalToolBox.eval(imported).asInstanceOf[T] - } -} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/runtime/ExprUtils.scala b/src/compiler/scala/reflect/macros/runtime/ExprUtils.scala deleted file mode 100644 index a719beed97..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/ExprUtils.scala +++ /dev/null @@ -1,34 +0,0 @@ -package scala.reflect.macros -package runtime - -trait ExprUtils { - self: Context => - - import universe._ - - def literalNull = Expr[Null](Literal(Constant(null)))(TypeTag.Null) - - def literalUnit = Expr[Unit](Literal(Constant(())))(TypeTag.Unit) - - def literalTrue = Expr[Boolean](Literal(Constant(true)))(TypeTag.Boolean) - - def literalFalse = Expr[Boolean](Literal(Constant(false)))(TypeTag.Boolean) - - def literal(x: Boolean) = Expr[Boolean](Literal(Constant(x)))(TypeTag.Boolean) - - def literal(x: Byte) = Expr[Byte](Literal(Constant(x)))(TypeTag.Byte) - - def literal(x: Short) = Expr[Short](Literal(Constant(x)))(TypeTag.Short) - - def literal(x: Int) = Expr[Int](Literal(Constant(x)))(TypeTag.Int) - - def literal(x: Long) = Expr[Long](Literal(Constant(x)))(TypeTag.Long) - - def literal(x: Float) = Expr[Float](Literal(Constant(x)))(TypeTag.Float) - - def literal(x: Double) = Expr[Double](Literal(Constant(x)))(TypeTag.Double) - - def literal(x: String) = Expr[String](Literal(Constant(x)))(TypeTag[String](definitions.StringClass.toTypeConstructor)) - - def literal(x: Char) = Expr[Char](Literal(Constant(x)))(TypeTag.Char) -} diff --git a/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala b/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala deleted file mode 100644 index a6a198e1b4..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala +++ /dev/null @@ -1,20 +0,0 @@ -package scala.reflect.macros -package runtime - -trait FrontEnds { - self: Context => - - def echo(pos: Position, msg: String): Unit = universe.reporter.echo(pos, msg) - - def info(pos: Position, msg: String, force: Boolean): Unit = universe.reporter.info(pos, msg, force) - - def hasWarnings: Boolean = universe.reporter.hasErrors - - def hasErrors: Boolean = universe.reporter.hasErrors - - def warning(pos: Position, msg: String): Unit = callsiteTyper.context.warning(pos, msg) - - def error(pos: Position, msg: String): Unit = callsiteTyper.context.error(pos, msg) - - def abort(pos: Position, msg: String): Nothing = throw new AbortMacroException(pos, msg) -} diff --git a/src/compiler/scala/reflect/macros/runtime/Infrastructure.scala b/src/compiler/scala/reflect/macros/runtime/Infrastructure.scala deleted file mode 100644 index 7781693822..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Infrastructure.scala +++ /dev/null @@ -1,16 +0,0 @@ -package scala.reflect.macros -package runtime - -trait Infrastructure { - self: Context => - - def settings: List[String] = { - val us = universe.settings - import us._ - userSetSettings collectFirst { case x: MultiStringSetting if x.name == XmacroSettings.name => x.value } getOrElse Nil - } - - def compilerSettings: List[String] = universe.settings.recreateArgs - - def classPath: List[java.net.URL] = global.classPath.asURLs -} diff --git a/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala new file mode 100644 index 0000000000..3ef11fad9d --- /dev/null +++ b/src/compiler/scala/reflect/macros/runtime/JavaReflectionRuntimes.scala @@ -0,0 +1,31 @@ +package scala.reflect.macros +package runtime + +import scala.reflect.runtime.ReflectionUtils +import scala.reflect.macros.{Context => ApiContext} + +trait JavaReflectionRuntimes { + self: scala.tools.nsc.typechecker.Analyzer => + + trait JavaReflectionResolvers { + self: MacroRuntimeResolver => + + import global._ + + def resolveJavaReflectionRuntime(classLoader: ClassLoader): MacroRuntime = { + val implClass = Class.forName(className, true, classLoader) + val implMeths = implClass.getDeclaredMethods.find(_.getName == methName) + // relies on the fact that macro impls cannot be overloaded + // so every methName can resolve to at maximum one method + val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") } + macroLogVerbose(s"successfully loaded macro impl as ($implClass, $implMeth)") + args => { + val implObj = + if (isBundle) implClass.getConstructor(classOf[ApiContext]).newInstance(args.c) + else ReflectionUtils.staticSingletonInstance(implClass) + val implArgs = if (isBundle) args.others else args.c +: args.others + implMeth.invoke(implObj, implArgs.asInstanceOf[Seq[AnyRef]]: _*) + } + } + } +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala new file mode 100644 index 0000000000..0f89163803 --- /dev/null +++ b/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala @@ -0,0 +1,74 @@ +package scala.reflect.macros +package runtime + +import scala.collection.mutable.{Map => MutableMap} +import scala.reflect.internal.Flags._ +import scala.reflect.runtime.ReflectionUtils +import scala.tools.nsc.util.ScalaClassLoader +import scala.tools.nsc.util.AbstractFileClassLoader + +trait MacroRuntimes extends JavaReflectionRuntimes with ScalaReflectionRuntimes { + self: scala.tools.nsc.typechecker.Analyzer => + + import global._ + import definitions._ + + /** Produces a function that can be used to invoke macro implementation for a given macro definition: + * 1) Looks up macro implementation symbol in this universe. + * 2) Loads its enclosing class from the macro classloader. + * 3) Loads the companion of that enclosing class from the macro classloader. + * 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. + */ + private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, MacroRuntime] + def macroRuntime(macroDef: Symbol): MacroRuntime = { + macroLogVerbose(s"looking for macro implementation: $macroDef") + if (fastTrack contains macroDef) { + macroLogVerbose("macro expansion is serviced by a fast track") + fastTrack(macroDef) + } else { + macroRuntimesCache.getOrElseUpdate(macroDef, new MacroRuntimeResolver(macroDef).resolveRuntime()) + } + } + + /** 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. + * + * When -Xmacro-jit is enabled, we sometimes fallback to on-the-fly compilation of macro implementations, + * which compiles implementations into a virtual directory (very much like REPL does) and then conjures + * a classloader mapped to that virtual directory. + */ + lazy val defaultMacroClassloader: ClassLoader = findMacroClassLoader() + + /** Abstracts away resolution of macro runtimes. + */ + type MacroRuntime = MacroArgs => Any + class MacroRuntimeResolver(val macroDef: Symbol) extends JavaReflectionResolvers + with ScalaReflectionResolvers { + val binding = loadMacroImplBinding(macroDef) + val isBundle = binding.isBundle + val className = binding.className + val methName = binding.methName + + def resolveRuntime(): MacroRuntime = { + if (className == Predef_???.owner.javaClassName && methName == Predef_???.name.encoded) { + args => throw new AbortMacroException(args.c.enclosingPosition, "macro implementation is missing") + } else { + try { + macroLogVerbose(s"resolving macro implementation as $className.$methName (isBundle = $isBundle)") + macroLogVerbose(s"classloader is: ${ReflectionUtils.show(defaultMacroClassloader)}") + // resolveScalaReflectionRuntime(defaultMacroClassloader) + resolveJavaReflectionRuntime(defaultMacroClassloader) + } catch { + case ex: Exception => + macroLogVerbose(s"macro runtime failed to load: ${ex.toString}") + macroDef setFlag IS_ERROR + null + } + } + } + } +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/runtime/Names.scala b/src/compiler/scala/reflect/macros/runtime/Names.scala deleted file mode 100644 index 635e8bcd45..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Names.scala +++ /dev/null @@ -1,26 +0,0 @@ -package scala.reflect.macros -package runtime - -trait Names { - self: Context => - - lazy val freshNameCreator = callsiteTyper.context.unit.fresh - - def fresh(): String = - freshName() - - def fresh(name: String): String = - freshName(name) - - def fresh[NameType <: Name](name: NameType): NameType = - freshName[NameType](name) - - def freshName(): String = - freshNameCreator.newName() - - def freshName(name: String): String = - freshNameCreator.newName(name) - - def freshName[NameType <: Name](name: NameType): NameType = - name.mapName(freshNameCreator.newName(_)).asInstanceOf[NameType] -} \ No newline at end of file diff --git a/src/compiler/scala/reflect/macros/runtime/Parsers.scala b/src/compiler/scala/reflect/macros/runtime/Parsers.scala deleted file mode 100644 index 566bcde73d..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Parsers.scala +++ /dev/null @@ -1,24 +0,0 @@ -package scala.reflect.macros -package runtime - -import scala.language.existentials -import scala.tools.reflect.ToolBox -import scala.tools.reflect.ToolBoxError - -trait Parsers { - self: Context => - - def parse(code: String): Tree = - // todo. provide decent implementation - // see `Typers.typedUseCase` for details - try { - import scala.reflect.runtime.{universe => ru} - val parsed = ru.rootMirror.mkToolBox().parse(code) - val importer = universe.mkImporter(ru) - importer.importTree(parsed) - } catch { - case ToolBoxError(msg, cause) => - // todo. provide a position - throw new ParseException(universe.NoPosition, msg) - } -} diff --git a/src/compiler/scala/reflect/macros/runtime/Reifiers.scala b/src/compiler/scala/reflect/macros/runtime/Reifiers.scala deleted file mode 100644 index 7ec3457c6a..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Reifiers.scala +++ /dev/null @@ -1,77 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Gilles Dubochet - */ - -package scala.reflect.macros -package runtime - -trait Reifiers { - self: Context => - - val global: universe.type = universe - import universe._ - import definitions._ - - def reifyTree(universe: Tree, mirror: Tree, tree: Tree): Tree = { - assert(ExprClass != NoSymbol) - val result = scala.reflect.reify.`package`.reifyTree(self.universe)(callsiteTyper, universe, mirror, tree) - logFreeVars(enclosingPosition, result) - result - } - - def reifyType(universe: Tree, mirror: Tree, tpe: Type, concrete: Boolean = false): Tree = { - assert(TypeTagsClass != NoSymbol) - val result = scala.reflect.reify.`package`.reifyType(self.universe)(callsiteTyper, universe, mirror, tpe, concrete) - logFreeVars(enclosingPosition, result) - result - } - - def reifyRuntimeClass(tpe: Type, concrete: Boolean = true): Tree = - scala.reflect.reify.`package`.reifyRuntimeClass(universe)(callsiteTyper, tpe, concrete = concrete) - - def reifyEnclosingRuntimeClass: Tree = - scala.reflect.reify.`package`.reifyEnclosingRuntimeClass(universe)(callsiteTyper) - - def unreifyTree(tree: Tree): Tree = { - assert(ExprSplice != NoSymbol) - Select(tree, ExprSplice) - } - - // fixme: if I put utils here, then "global" from utils' early initialization syntax - // and "global" that comes from here conflict with each other when incrementally compiling - // the problem is that both are pickled with the same owner - trait Reifiers - // and this upsets the compiler, so that oftentimes it throws assertion failures - // Martin knows the details - // - // object utils extends { - // val global: self.global.type = self.global - // val typer: global.analyzer.Typer = self.callsiteTyper - // } with scala.reflect.reify.utils.Utils - // import utils._ - - private def logFreeVars(position: Position, reification: Tree): Unit = { - object utils extends { - val global: self.global.type = self.global - val typer: global.analyzer.Typer = self.callsiteTyper - } with scala.reflect.reify.utils.Utils - import utils._ - - def logFreeVars(symtab: SymbolTable): Unit = - // logging free vars only when they are untyped prevents avalanches of duplicate messages - symtab.syms map (sym => symtab.symDef(sym)) foreach { - case FreeTermDef(_, _, binding, _, origin) if universe.settings.logFreeTerms && binding.tpe == null => - reporter.echo(position, "free term: %s %s".format(showRaw(binding), origin)) - case FreeTypeDef(_, _, binding, _, origin) if universe.settings.logFreeTypes && binding.tpe == null => - reporter.echo(position, "free type: %s %s".format(showRaw(binding), origin)) - case _ => - // do nothing - } - - if (universe.settings.logFreeTerms || universe.settings.logFreeTypes) - reification match { - case ReifiedTree(_, _, symtab, _, _, _, _) => logFreeVars(symtab) - case ReifiedType(_, _, symtab, _, _, _) => logFreeVars(symtab) - } - } -} diff --git a/src/compiler/scala/reflect/macros/runtime/ScalaReflectionRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/ScalaReflectionRuntimes.scala new file mode 100644 index 0000000000..1999e525ff --- /dev/null +++ b/src/compiler/scala/reflect/macros/runtime/ScalaReflectionRuntimes.scala @@ -0,0 +1,33 @@ +package scala.reflect.macros +package runtime + +import scala.reflect.runtime.{universe => ru} + +trait ScalaReflectionRuntimes { + self: scala.tools.nsc.typechecker.Analyzer => + + trait ScalaReflectionResolvers { + self: MacroRuntimeResolver => + + import global._ + + def resolveScalaReflectionRuntime(classLoader: ClassLoader): MacroRuntime = { + val macroMirror: ru.JavaMirror = ru.runtimeMirror(classLoader) + val implContainerSym = macroMirror.classSymbol(Class.forName(className, true, classLoader)) + val implMethSym = implContainerSym.typeSignature.member(ru.TermName(methName)).asMethod + macroLogVerbose(s"successfully loaded macro impl as ($implContainerSym, $implMethSym)") + args => { + val implContainer = + if (isBundle) { + val implCtorSym = implContainerSym.typeSignature.member(ru.nme.CONSTRUCTOR).asMethod + macroMirror.reflectClass(implContainerSym).reflectConstructor(implCtorSym)(args.c) + } else { + macroMirror.reflectModule(implContainerSym.module.asModule).instance + } + val implMeth = macroMirror.reflect(implContainer).reflectMethod(implMethSym) + val implArgs = if (isBundle) args.others else args.c +: args.others + implMeth(implArgs: _*) + } + } + } +} diff --git a/src/compiler/scala/reflect/macros/runtime/Synthetics.scala b/src/compiler/scala/reflect/macros/runtime/Synthetics.scala deleted file mode 100644 index 1156769a80..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Synthetics.scala +++ /dev/null @@ -1,66 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - */ - -package scala.reflect.macros -package runtime - -import scala.reflect.internal.Flags._ -import scala.reflect.internal.util.BatchSourceFile -import scala.reflect.io.VirtualFile - -trait Synthetics { - self: Context => - - import global._ - import mirror.wrapMissing - - // getClassIfDefined and getModuleIfDefined cannot be used here - // because they don't work for stuff declared in the empty package - // (as specified in SLS, code inside non-empty packages cannot see - // declarations from the empty package, so compiler internals - // default to ignoring contents of the empty package) - // to the contrast, staticModule and staticClass are designed - // to be a part of the reflection API and, therefore, they - // correctly resolve all names - private def topLevelSymbol(name: Name): Symbol = wrapMissing { - if (name.isTermName) mirror.staticModule(name.toString) - else mirror.staticClass(name.toString) - } - - def topLevelDef(name: Name): Tree = - enclosingRun.units.toList.map(_.body).flatMap { - // it's okay to check `stat.symbol` here, because currently macros expand strictly after namer - // which means that by the earliest time one can call this method all top-level definitions will have already been entered - case PackageDef(_, stats) => stats filter (stat => stat.symbol != NoSymbol && stat.symbol == topLevelSymbol(name)) - case _ => Nil // should never happen, but better be safe than sorry - }.headOption getOrElse EmptyTree - - def topLevelRef(name: Name): Tree = { - if (topLevelDef(name).nonEmpty) gen.mkUnattributedRef(name) - else EmptyTree - } - - def introduceTopLevel[T: PackageSpec](packagePrototype: T, definition: universe.ImplDef): RefTree = - introduceTopLevel(packagePrototype, List(definition)).head - - def introduceTopLevel[T: PackageSpec](packagePrototype: T, definitions: universe.ImplDef*): List[RefTree] = - introduceTopLevel(packagePrototype, definitions.toList) - - private def introduceTopLevel[T: PackageSpec](packagePrototype: T, definitions: List[universe.ImplDef]): List[RefTree] = { - val code @ PackageDef(pid, _) = implicitly[PackageSpec[T]].mkPackageDef(packagePrototype, definitions) - universe.currentRun.compileLate(code) - definitions map (definition => Select(pid, definition.name)) - } - - protected def mkPackageDef(name: String, stats: List[Tree]) = gen.mkPackageDef(name, stats) - - protected def mkPackageDef(name: TermName, stats: List[Tree]) = gen.mkPackageDef(name.toString, stats) - - protected def mkPackageDef(tree: RefTree, stats: List[Tree]) = PackageDef(tree, stats) - - protected def mkPackageDef(sym: Symbol, stats: List[Tree]) = { - assert(sym hasFlag PACKAGE, s"expected a package or package class symbol, found: $sym") - gen.mkPackageDef(sym.fullName.toString, stats) - } -} diff --git a/src/compiler/scala/reflect/macros/runtime/Traces.scala b/src/compiler/scala/reflect/macros/runtime/Traces.scala deleted file mode 100644 index 0238e9f84e..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Traces.scala +++ /dev/null @@ -1,8 +0,0 @@ -package scala.reflect.macros -package runtime - -trait Traces extends util.Traces { - self: Context => - - def globalSettings = universe.settings -} diff --git a/src/compiler/scala/reflect/macros/runtime/Typers.scala b/src/compiler/scala/reflect/macros/runtime/Typers.scala deleted file mode 100644 index f92d99a3f2..0000000000 --- a/src/compiler/scala/reflect/macros/runtime/Typers.scala +++ /dev/null @@ -1,52 +0,0 @@ -package scala.reflect.macros -package runtime - -import scala.reflect.internal.Mode - -trait Typers { - self: Context => - - def openMacros: List[Context] = this :: universe.analyzer.openMacros - - def openImplicits: List[ImplicitCandidate] = callsiteTyper.context.openImplicits.map(_.toImplicitCandidate) - - /** - * @see [[scala.tools.reflect.ToolBox.typeCheck]] - */ - def typeCheck(tree: Tree, 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(tree, pt), reportAmbiguousErrors = false) match { - case universe.analyzer.SilentResultValue(result) => - macroLogVerbose(result) - result - case error @ universe.analyzer.SilentTypeError(_) => - 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 = { - macroLogVerbose("inferring implicit value of type %s, macros = %s".format(pt, !withMacrosDisabled)) - universe.analyzer.inferImplicit(universe.EmptyTree, pt, false, callsiteTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw TypecheckException(pos, msg)) - } - - def inferImplicitView(tree: Tree, from: Type, to: Type, silent: Boolean = true, withMacrosDisabled: Boolean = false, pos: Position = enclosingPosition): Tree = { - macroLogVerbose("inferring implicit view from %s to %s for %s, macros = %s".format(from, to, tree, !withMacrosDisabled)) - val viewTpe = universe.appliedType(universe.definitions.FunctionClass(1).toTypeConstructor, List(from, to)) - universe.analyzer.inferImplicit(tree, viewTpe, true, callsiteTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw TypecheckException(pos, msg)) - } - - def resetAllAttrs(tree: Tree): Tree = universe.resetAllAttrs(tree) - - def resetLocalAttrs(tree: Tree): Tree = universe.resetLocalAttrs(tree) -} diff --git a/src/compiler/scala/reflect/macros/runtime/package.scala b/src/compiler/scala/reflect/macros/runtime/package.scala new file mode 100644 index 0000000000..9ef8200760 --- /dev/null +++ b/src/compiler/scala/reflect/macros/runtime/package.scala @@ -0,0 +1,5 @@ +package scala.reflect.macros + +package object runtime { + type Context = scala.reflect.macros.contexts.Context +} \ No newline at end of file diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala index 9659134e5b..0bffe55403 100644 --- a/src/compiler/scala/reflect/reify/Taggers.scala +++ b/src/compiler/scala/reflect/reify/Taggers.scala @@ -1,7 +1,7 @@ package scala.reflect.reify import scala.reflect.macros.{ReificationException, UnexpectedReificationException, TypecheckException} -import scala.reflect.macros.runtime.Context +import scala.reflect.macros.contexts.Context abstract class Taggers { val c: Context diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 40f284c94c..8d650b3653 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -10,9 +10,10 @@ import scala.reflect.ClassTag import scala.reflect.internal.util.Statistics import scala.reflect.macros.util._ import scala.util.control.ControlThrowable -import scala.reflect.macros.runtime.AbortMacroException +import scala.reflect.macros.runtime.{AbortMacroException, MacroRuntimes} import scala.reflect.runtime.{universe => ru} import scala.reflect.macros.compiler.DefaultMacroCompiler +import scala.tools.reflect.FastTrack /** * Code to deal with macros, namely with: @@ -39,7 +40,7 @@ import scala.reflect.macros.compiler.DefaultMacroCompiler * (Expr(elems)) * (TypeTag(Int)) */ -trait Macros extends scala.tools.reflect.FastTrack with Traces with Helpers { +trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { self: Analyzer => import global._ @@ -77,7 +78,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces with Helpers { * Includes a path to load the implementation via Java reflection, * and various accounting information necessary when composing an argument list for the reflective invocation. */ - private case class MacroImplBinding( + case class MacroImplBinding( // Is this macro impl a bundle (a trait extending Macro) or a vanilla def? val isBundle: Boolean, // Java class name of the class that contains the macro implementation @@ -99,9 +100,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces with Helpers { // these trees don't refer to a macro impl, so we can pickle them as is targs: List[Tree]) - private final val IMPLPARAM_TAG = 0 // actually it's zero and above, this is just a lower bound for >= checks - private final val IMPLPARAM_OTHER = -1 - private final val IMPLPARAM_EXPR = -2 + final val IMPLPARAM_TAG = 0 // actually it's zero and above, this is just a lower bound for >= checks + final val IMPLPARAM_OTHER = -1 + final val IMPLPARAM_EXPR = -2 /** Macro def -> macro impl bindings are serialized into a `macroImpl` annotation * with synthetic content that carries the payload described in `MacroImplBinding`. @@ -120,7 +121,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces with Helpers { * "versionFormat" = , * "className" = "Macros$")) */ - private object MacroImplBinding { + object MacroImplBinding { val versionFormat = 3 def pickleAtom(obj: Any): Tree = @@ -220,12 +221,12 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces with Helpers { } } - private def bindMacroImpl(macroDef: Symbol, macroImplRef: Tree): Unit = { + def bindMacroImpl(macroDef: Symbol, macroImplRef: Tree): Unit = { val pickle = MacroImplBinding.pickle(macroImplRef) macroDef withAnnotation AnnotationInfo(MacroImplAnnotation.tpe, List(pickle), Nil) } - private def loadMacroImplBinding(macroDef: Symbol): MacroImplBinding = { + def loadMacroImplBinding(macroDef: Symbol): MacroImplBinding = { val Some(AnnotationInfo(_, List(pickle), _)) = macroDef.getAnnotation(MacroImplAnnotation) MacroImplBinding.unpickle(pickle) } @@ -309,73 +310,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces with Helpers { } } - /** 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. - */ - lazy val macroClassloader: ClassLoader = findMacroClassLoader() - - /** Reflective mirror built from `macroClassloader`. - */ - private lazy val macroMirror: ru.JavaMirror = ru.runtimeMirror(macroClassloader) - - /** Produces a function that can be used to invoke macro implementation for a given macro definition: - * 1) Looks up macro implementation symbol in this universe. - * 2) Loads its enclosing class from the macro classloader. - * 3) Loads the companion of that enclosing class from the macro classloader. - * 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. - */ - type MacroRuntime = MacroArgs => Any - private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, MacroRuntime]() - private def macroRuntime(macroDef: Symbol): MacroRuntime = { - macroLogVerbose(s"looking for macro implementation: $macroDef") - if (fastTrack contains macroDef) { - macroLogVerbose("macro expansion is serviced by a fast track") - fastTrack(macroDef) - } else { - macroRuntimesCache.getOrElseUpdate(macroDef, { - val binding = loadMacroImplBinding(macroDef) - val isBundle = binding.isBundle - val className = binding.className - val methName = binding.methName - macroLogVerbose(s"resolved implementation as $className.$methName") - - if (binding.className == Predef_???.owner.javaClassName && binding.methName == Predef_???.name.encoded) { - args => throw new AbortMacroException(args.c.enclosingPosition, "macro implementation is missing") - } else { - try { - macroLogVerbose(s"loading implementation class: $className") - macroLogVerbose(s"classloader is: ${ReflectionUtils.show(macroClassloader)}") - val implContainerSym = macroMirror.classSymbol(Class.forName(className, true, macroClassloader)) - val implMethSym = implContainerSym.typeSignature.member(ru.TermName(methName)).asMethod - macroLogVerbose(s"successfully loaded macro impl as ($implContainerSym, $implMethSym)") - args => { - val implContainer = - if (isBundle) { - val implCtorSym = implContainerSym.typeSignature.member(ru.nme.CONSTRUCTOR).asMethod - macroMirror.reflectClass(implContainerSym).reflectConstructor(implCtorSym)(args.c) - } else { - macroMirror.reflectModule(implContainerSym.module.asModule).instance - } - val implMeth = macroMirror.reflect(implContainer).reflectMethod(implMethSym) - val implArgs = if (isBundle) args.others else args.c +: args.others - implMeth(implArgs: _*) - } - } catch { - case ex: Exception => - macroLogVerbose(s"macro runtime failed to load: ${ex.toString}") - macroDef setFlag IS_ERROR - null - } - } - }) - } - } - - private def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext = { + def macroContext(typer: Typer, prefixTree: Tree, expandeeTree: Tree): MacroContext = { new { val universe: self.global.type = self.global val callsiteTyper: universe.analyzer.Typer = typer.asInstanceOf[global.analyzer.Typer] diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index a208924acb..c616ded704 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -10,7 +10,7 @@ trait StdAttachments { * At times we need to store this info, because macro expansion can be delayed until its targs are inferred. * After a macro application has been successfully expanded, this attachment is destroyed. */ - type UnaffiliatedMacroContext = scala.reflect.macros.runtime.Context + type UnaffiliatedMacroContext = scala.reflect.macros.contexts.Context type MacroContext = UnaffiliatedMacroContext { val universe: self.global.type } case class MacroRuntimeAttachment(delayed: Boolean, typerContext: Context, macroContext: Option[MacroContext]) diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala index 109c148b7e..8e1bcb5f87 100644 --- a/src/compiler/scala/tools/reflect/MacroImplementations.scala +++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala @@ -1,6 +1,6 @@ package scala.tools.reflect -import scala.reflect.macros.runtime.Context +import scala.reflect.macros.contexts.Context import scala.collection.mutable.ListBuffer import scala.collection.mutable.Stack import scala.reflect.internal.util.OffsetPosition -- cgit v1.2.3