diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-06-06 14:29:05 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-06-08 15:32:03 +0200 |
commit | 6355d1a0b825c99560d4ccec1a8769f7421b1a71 (patch) | |
tree | 80f448f0da11dcab9cee30f3d8fe867cd66313ed /src/compiler/scala/tools | |
parent | ce67870e64afabf75363679bcee597812ad223e9 (diff) | |
download | scala-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')
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 = |