summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-06-06 14:29:05 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-06-08 15:32:03 +0200
commit6355d1a0b825c99560d4ccec1a8769f7421b1a71 (patch)
tree80f448f0da11dcab9cee30f3d8fe867cd66313ed /src/compiler/scala/tools
parentce67870e64afabf75363679bcee597812ad223e9 (diff)
downloadscala-6355d1a0b825c99560d4ccec1a8769f7421b1a71.tar.gz
scala-6355d1a0b825c99560d4ccec1a8769f7421b1a71.tar.bz2
scala-6355d1a0b825c99560d4ccec1a8769f7421b1a71.zip
brings reification up to speed
Along with recovering from reflection refactoring, I implemented some new features (e.g. rollback of macro expansions), and did some stabilizing refactorings (e.g. moved mutable state into a ghetto). Also used the refactoring as a chance to fix free and aux symbols. Encapsulated this notion in a symbol table class, which allowed me to address outstanding issues with symbol table inheritance and inlining.
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Taggings.scala71
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Tags.scala86
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala18
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala11
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala2
10 files changed, 113 insertions, 88 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index cd1a808823..a16b42dc47 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -82,7 +82,6 @@ trait ScalaSettings extends AbsScalaSettings
val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more detail on why some implicits are not applicable.")
val logImplicitConv = BooleanSetting ("-Xlog-implicit-conversions", "Print a message whenever an implicit conversion is inserted.")
val logReflectiveCalls = BooleanSetting("-Xlog-reflective-calls", "Print a message when a reflective method call is generated")
- val logRuntimeSplices = BooleanSetting("-Xlog-runtime-splices", "Print a message when Expr.eval or Expr.value cannot be resolved statically.")
val logFreeTerms = BooleanSetting ("-Xlog-free-terms", "Print a message when reification creates a free term.")
val logFreeTypes = BooleanSetting ("-Xlog-free-types", "Print a message when reification resorts to generating a free type.")
val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index ea66dbedd6..fde27a650a 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -967,7 +967,7 @@ abstract class Erasure extends AddInterfaces
}
// Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
else if (isPrimitiveValueClass(qual.tpe.typeSymbol))
- global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveErasureTag(qual.tpe.widen, tree.pos, true))))
+ global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen))))
else
tree
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 8af12f3f10..db3d8b2785 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -419,7 +419,7 @@ abstract class UnCurry extends InfoTransform
val toArraySym = tree.tpe member nme.toArray
assert(toArraySym != NoSymbol)
def getArrayTag(tp: Type): Tree = {
- val tag = localTyper.resolveArrayTag(tp, tree.pos)
+ val tag = localTyper.resolveArrayTag(tree.pos, tp)
// Don't want bottom types getting any further than this (SI-4024)
if (tp.typeSymbol.isBottomClass) getArrayTag(AnyClass.tpe)
else if (!tag.isEmpty) tag
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index f3afa2d33f..9855284348 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1294,8 +1294,8 @@ trait Implicits {
}
val tagInScope =
- if (full) resolveTypeTag(NoType, tp, pos, concrete = true)
- else resolveArrayTag(tp, pos)
+ if (full) resolveTypeTag(pos, NoType, tp, concrete = true, allowMaterialization = false)
+ else resolveArrayTag(pos, tp, allowMaterialization = false)
if (tagInScope.isEmpty) mot(tp, Nil, Nil)
else {
if (full) {
@@ -1307,7 +1307,7 @@ trait Implicits {
|to proceed put scala-reflect.jar on your compilation classpath and recompile.""".trim.stripMargin)
return SearchFailure
}
- if (resolveErasureTag(tp, pos, concrete = true) == EmptyTree) {
+ if (resolveClassTag(pos, tp, allowMaterialization = true) == EmptyTree) {
context.error(pos, s"""
|to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires a class tag for the corresponding type to be present.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 96fcdd793e..93991fe7d5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -982,7 +982,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
if (typer.context.hasErrors) fail("typecheck against expected type", expanded)
macroLogVerbose("typechecked2:%n%s%n%s".format(typechecked, showRaw(typechecked)))
- typechecked
+ typechecked addAttachment MacroExpansionAttachment(expandee)
} finally {
openMacros = openMacros.tail
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Taggings.scala b/src/compiler/scala/tools/nsc/typechecker/Taggings.scala
deleted file mode 100644
index bbcfa2920b..0000000000
--- a/src/compiler/scala/tools/nsc/typechecker/Taggings.scala
+++ /dev/null
@@ -1,71 +0,0 @@
-package scala.tools.nsc
-package typechecker
-
-trait Taggings {
- self: Analyzer =>
-
- import global._
- import definitions._
-
- trait Tagging {
- self: Typer =>
-
- private def resolveTag(taggedTp: Type, pos: Position) = beforeTyper {
- inferImplicit(
- EmptyTree,
- taggedTp,
- /*reportAmbiguous =*/ true,
- /*isView =*/ false,
- /*context =*/ context,
- /*saveAmbiguousDivergent =*/ true,
- /*pos =*/ pos
- ).tree
- }
-
- /** Finds in scope or materializes an ArrayTag.
- * Should be used instead of ClassTag or ClassManifest every time compiler needs to create an array.
- *
- * @param tp Type we're looking an ArrayTag for, e.g. resolveArrayTag(IntClass.tpe, pos) will look for ArrayTag[Int].
- * @param pos Position for error reporting. Please, provide meaningful value.
- *
- * @returns Tree that represents an `scala.reflect.ArrayTag` for `tp` if everything is okay.
- * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
- */
- def resolveArrayTag(tp: Type, pos: Position): Tree = {
- val taggedTp = appliedType(ArrayTagClass.typeConstructor, List(tp))
- resolveTag(taggedTp, pos)
- }
-
- /** Finds in scope or materializes an ErasureTag (if `concrete` is false) or a ClassTag (if `concrete` is true).
- * Should be used instead of ClassTag or ClassManifest every time compiler needs to persist an erasure.
- *
- * @param tp Type we're looking an ErasureTag for, e.g. resolveErasureTag(IntClass.tpe, pos, true) will look for ClassTag[Int].
- * @param pos Position for error reporting. Please, provide meaningful value.
- * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members.
- * If false then the function will always succeed (abstract types will be erased to their upper bounds).
- *
- * @returns Tree that represents an `scala.reflect.ErasureTag` for `tp` if everything is okay.
- * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
- */
- def resolveErasureTag(tp: Type, pos: Position, concrete: Boolean): Tree = {
- val taggedTp = appliedType(if (concrete) ClassTagClass.typeConstructor else ???, List(tp))
- resolveTag(taggedTp, pos)
- }
-
- /** Finds in scope or materializes a TypeTag (if `concrete` is false) or a ConcreteTypeTag (if `concrete` is true).
- *
- * @param pre Prefix that represents a universe this type tag will be bound to.
- * @param tp Type we're looking a TypeTag for, e.g. resolveTypeTag(reflectMirrorPrefix, IntClass.tpe, pos, false) will look for scala.reflect.mirror.TypeTag[Int].
- * @param pos Position for error reporting. Please, provide meaningful value.
- * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members.
- * If false then the function will always succeed (abstract types will be reified as free types).
- *
- * @returns Tree that represents a `scala.reflect.TypeTag` for `tp` if everything is okay.
- * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
- */
- def resolveTypeTag(pre: Type, tp: Type, pos: Position, concrete: Boolean): Tree = {
- val taggedTp = appliedType(singleType(pre, pre member (if (concrete) ConcreteTypeTagClass else TypeTagClass).name), List(tp))
- resolveTag(taggedTp, pos)
- }
- }
-} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/Tags.scala b/src/compiler/scala/tools/nsc/typechecker/Tags.scala
new file mode 100644
index 0000000000..d371f02d1d
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Tags.scala
@@ -0,0 +1,86 @@
+package scala.tools.nsc
+package typechecker
+
+trait Tags {
+ self: Analyzer =>
+
+ import global._
+ import definitions._
+
+ trait Tag {
+ self: Typer =>
+
+ private def resolveTag(pos: Position, taggedTp: Type, allowMaterialization: Boolean) = beforeTyper {
+ def wrapper (tree: => Tree): Tree = if (allowMaterialization) (context.withMacrosEnabled[Tree](tree)) else (context.withMacrosDisabled[Tree](tree))
+ wrapper(inferImplicit(
+ EmptyTree,
+ taggedTp,
+ /*reportAmbiguous =*/ true,
+ /*isView =*/ false,
+ /*context =*/ context,
+ /*saveAmbiguousDivergent =*/ true,
+ /*pos =*/ pos
+ ).tree)
+ }
+
+ /** Finds in scope or materializes an ArrayTag.
+ * Should be used instead of ClassTag or ClassManifest every time compiler needs to create an array.
+ *
+ * @param pos Position for error reporting. Please, provide meaningful value.
+ * @param tp Type we're looking an ArrayTag for, e.g. resolveArrayTag(pos, IntClass.tpe) will look for ArrayTag[Int].
+ * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no array tag in scope.
+ * If false then materialization macros are prohibited from running.
+ *
+ * @returns Tree that represents an `scala.reflect.ArrayTag` for `tp` if everything is okay.
+ * EmptyTree if `allowMaterialization` is false, and there is no array tag in scope.
+ * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
+ */
+ def resolveArrayTag(pos: Position, tp: Type, allowMaterialization: Boolean = true): Tree = {
+ val taggedTp = appliedType(ArrayTagClass.typeConstructor, List(tp))
+ resolveTag(pos, taggedTp, allowMaterialization)
+ }
+
+ /** Finds in scope or materializes a ClassTag.
+ * Should be used instead of ClassManifest every time compiler needs to persist an erasure.
+ *
+ * Once upon a time, we had an `ErasureTag` which was to `ClassTag` the same that `TypeTag` is for `ConcreteTypeTag`.
+ * However we found out that we don't really need this concept, so it got removed.
+ *
+ * @param pos Position for error reporting. Please, provide meaningful value.
+ * @param tp Type we're looking a ClassTag for, e.g. resolveClassTag(pos, IntClass.tpe) will look for ClassTag[Int].
+ * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no class tag in scope.
+ * If false then materialization macros are prohibited from running.
+ *
+ * @returns Tree that represents an `scala.reflect.ClassTag` for `tp` if everything is okay.
+ * EmptyTree if the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
+ * EmptyTree if `allowMaterialization` is false, and there is no class tag in scope.
+ */
+ def resolveClassTag(pos: Position, tp: Type, allowMaterialization: Boolean = true): Tree = {
+ val taggedTp = appliedType(ClassTagClass.typeConstructor, List(tp))
+ resolveTag(pos, taggedTp, allowMaterialization)
+ }
+
+ /** Finds in scope or materializes a TypeTag (if `concrete` is false) or a ConcreteTypeTag (if `concrete` is true).
+ *
+ * @param pos Position for error reporting. Please, provide meaningful value.
+ * @param pre Prefix that represents a universe this type tag will be bound to.
+ * If `pre` is set to `NoType`, then any type tag in scope will do, regardless of its affiliation.
+ * If `pre` is set to `NoType`, and tag resolution involves materialization, then `mkBasisPrefix` will be used.
+ * @param tp Type we're looking a TypeTag for, e.g. resolveTypeTag(pos, reflectBasisPrefix, IntClass.tpe, false) will look for scala.reflect.basis.TypeTag[Int].
+ * @param concrete If true then the result must not contain unresolved (i.e. not spliced) type parameters and abstract type members.
+ * If false then the function will always succeed (abstract types will be reified as free types).
+ * @param allowMaterialization If true (default) then the resolver is allowed to launch materialization macros when there's no type tag in scope.
+ * If false then materialization macros are prohibited from running.
+ *
+ * @returns Tree that represents a `scala.reflect.TypeTag` for `tp` if everything is okay.
+ * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members.
+ * EmptyTree if `allowMaterialization` is false, and there is no array tag in scope.
+ */
+ def resolveTypeTag(pos: Position, pre: Type, tp: Type, concrete: Boolean, allowMaterialization: Boolean = true): Tree = {
+ val tagSym = if (concrete) ConcreteTypeTagClass else TypeTagClass
+ val tagTp = if (pre == NoType) TypeRef(BaseUniverseClass.asTypeConstructor, tagSym, List(tp)) else singleType(pre, pre member tagSym.name)
+ val taggedTp = appliedType(tagTp, List(tp))
+ resolveTag(pos, taggedTp, allowMaterialization)
+ }
+ }
+} \ 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 cc36ed7428..30202ed3b5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -26,7 +26,7 @@ import util.Statistics._
* @author Martin Odersky
* @version 1.0
*/
-trait Typers extends Modes with Adaptations with Taggings {
+trait Typers extends Modes with Adaptations with Tags {
self: Analyzer =>
import global._
@@ -96,7 +96,7 @@ trait Typers extends Modes with Adaptations with Taggings {
// this is disabled by: -Xoldpatmat, scaladoc or interactive compilation
@inline private def newPatternMatching = opt.virtPatmat && !forScaladoc && !forInteractive // && (phase.id < currentRun.uncurryPhase.id)
- abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tagging with TyperContextErrors {
+ abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tag with TyperContextErrors {
import context0.unit
import typeDebug.{ ptTree, ptBlock, ptLine }
import TyperErrorGen._
@@ -2512,11 +2512,18 @@ trait Typers extends Modes with Adaptations with Taggings {
}
}
- def typedRefinement(stats: List[Tree]) {
+ def typedRefinement(templ: Template) {
+ val stats = templ.body
namer.enterSyms(stats)
// need to delay rest of typedRefinement to avoid cyclic reference errors
unit.toCheck += { () =>
val stats1 = typedStats(stats, NoSymbol)
+ // this code kicks in only after typer, so `stats` will never be filled in time
+ // as a result, most of compound type trees with non-empty stats will fail to reify
+ // [Eugene++] todo. investigate whether something can be done about this
+ val att = templ.attachments.get[CompoundTypeTreeOriginalAttachment].getOrElse(CompoundTypeTreeOriginalAttachment(Nil, Nil))
+ templ.removeAttachment[CompoundTypeTreeOriginalAttachment]
+ templ addAttachment att.copy(stats = stats1)
for (stat <- stats1 if stat.isDef) {
val member = stat.symbol
if (!(context.owner.ancestors forall
@@ -4584,7 +4591,8 @@ trait Typers extends Modes with Adaptations with Taggings {
val decls = newScope
//Console.println("Owner: " + context.enclClass.owner + " " + context.enclClass.owner.id)
val self = refinedType(parents1 map (_.tpe), context.enclClass.owner, decls, templ.pos)
- newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ.body)
+ newTyper(context.make(templ, self.typeSymbol, decls)).typedRefinement(templ)
+ templ addAttachment CompoundTypeTreeOriginalAttachment(parents1, Nil) // stats are set elsewhere
tree setType self
}
}
@@ -4856,7 +4864,7 @@ trait Typers extends Modes with Adaptations with Taggings {
val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.asType, List(tpe))).last
val newArrayApp = atPos(tree.pos) {
- val tag = resolveArrayTag(tagType, tree.pos)
+ val tag = resolveArrayTag(tree.pos, tagType)
if (tag.isEmpty) MissingArrayTagError(tree, tagType)
else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
}
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
index 8658e3225d..534f6de682 100644
--- a/src/compiler/scala/tools/reflect/FastTrack.scala
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -1,6 +1,7 @@
package scala.tools
package reflect
+import scala.reflect.makro.runtime.ContextReifiers
import scala.reflect.reify.Taggers
import scala.tools.nsc.typechecker.{Analyzer, Macros}
@@ -15,6 +16,7 @@ trait FastTrack {
import language.implicitConversions
private implicit def context2taggers(c0: MacroContext) : Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
+ private implicit def context2contextreifiers(c0: MacroContext) : ContextReifiers { val c: c0.type } = new { val c: c0.type = c0 } with ContextReifiers
implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args)
type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree]
@@ -36,10 +38,11 @@ trait FastTrack {
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_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) }
+ MacroInternal_materializeTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = false) }
+ MacroInternal_materializeConcreteTypeTag bindTo { case (c, Apply(TypeApply(_, List(tt)), List(u))) => c.materializeTypeTag(u, EmptyTree, tt.tpe, concrete = true) }
+ ApiUniverseReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExpr(c.prefix.tree, EmptyTree, expr) }
+ MacroContextReify bindTo { case (c, Apply(TypeApply(_, List(tt)), List(expr))) => c.materializeExprForMacroContext(c.prefix.tree, expr) }
+ ReflectRuntimeCurrentMirror bindTo { case (c, _) => scala.reflect.runtime.Macros.currentMirror(c).tree }
registry
}
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 3ef2337e0f..741f1b268f 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -79,7 +79,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
var name = ft.name.toString
val namesakes = freeTerms takeWhile (_ != ft) filter (ft2 => ft != ft2 && ft.name == ft2.name)
if (namesakes.length > 0) name += ("$" + (namesakes.length + 1))
- freeTermNames += (ft -> newTermName(name + nme.MIRROR_FREE_VALUE_SUFFIX))
+ freeTermNames += (ft -> newTermName(name + nme.REIFY_FREE_VALUE_SUFFIX))
})
var expr = new Transformer {
override def transform(tree: Tree): Tree =