diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-07-03 00:40:13 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-07-03 00:40:13 -0700 |
commit | bc2e6fe8bf20b2aa985ea78a2c610ac33497da38 (patch) | |
tree | 5c8fd6a4121994ce6a62addf9566e13aa4e7e9f1 /src/compiler | |
parent | 035224a17def57b25f7a8ed69d050451b8e7103d (diff) | |
parent | 96dd73146f4317feeb59a242d692977f87c5211d (diff) | |
download | scala-bc2e6fe8bf20b2aa985ea78a2c610ac33497da38.tar.gz scala-bc2e6fe8bf20b2aa985ea78a2c610ac33497da38.tar.bz2 scala-bc2e6fe8bf20b2aa985ea78a2c610ac33497da38.zip |
Merge pull request #810 from scalamacros/pullrequest/manifests-and-ticket6005
two pullrequests from this morning, combined to merge changes to starrs
Diffstat (limited to 'src/compiler')
10 files changed, 97 insertions, 75 deletions
diff --git a/src/compiler/scala/reflect/makro/runtime/ExprUtils.scala b/src/compiler/scala/reflect/makro/runtime/ExprUtils.scala index 4775138e5a..e301dfc2a4 100644 --- a/src/compiler/scala/reflect/makro/runtime/ExprUtils.scala +++ b/src/compiler/scala/reflect/makro/runtime/ExprUtils.scala @@ -29,7 +29,7 @@ trait ExprUtils { def literal(x: Double) = Expr[Double](Literal(Constant(x)))(TypeTag.Double) - def literal(x: String) = Expr[String](Literal(Constant(x)))(TypeTag.String) + def literal(x: String) = Expr[String](Literal(Constant(x)))(TypeTag[String](definitions.StringClass.asTypeConstructor)) def literal(x: Char) = Expr[Char](Literal(Constant(x)))(TypeTag.Char) } diff --git a/src/compiler/scala/reflect/reify/Taggers.scala b/src/compiler/scala/reflect/reify/Taggers.scala index b70c3f44a3..e4c3d02f22 100644 --- a/src/compiler/scala/reflect/reify/Taggers.scala +++ b/src/compiler/scala/reflect/reify/Taggers.scala @@ -11,20 +11,19 @@ abstract class Taggers { import treeBuild._ val coreTags = Map( - ByteClass.asType -> nme.Byte, - ShortClass.asType -> nme.Short, - CharClass.asType -> nme.Char, - IntClass.asType -> nme.Int, - LongClass.asType -> nme.Long, - FloatClass.asType -> nme.Float, - DoubleClass.asType -> nme.Double, - BooleanClass.asType -> nme.Boolean, - UnitClass.asType -> nme.Unit, - AnyClass.asType -> nme.Any, - ObjectClass.asType -> nme.Object, - NothingClass.asType -> nme.Nothing, - NullClass.asType -> nme.Null, - StringClass.asType -> nme.String) + ByteTpe -> nme.Byte, + ShortTpe -> nme.Short, + CharTpe -> nme.Char, + IntTpe -> nme.Int, + LongTpe -> nme.Long, + FloatTpe -> nme.Float, + DoubleTpe -> nme.Double, + BooleanTpe -> nme.Boolean, + UnitTpe -> nme.Unit, + AnyTpe -> nme.Any, + ObjectTpe -> nme.Object, + NothingTpe -> nme.Nothing, + NullTpe -> nme.Null) def materializeClassTag(prefix: Tree, tpe: Type): Tree = { val tagModule = ClassTagModule diff --git a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala index 3a98d308a7..9b0777580b 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenSymbols.scala @@ -23,10 +23,8 @@ trait GenSymbols { def symtab: SymbolTable = state.symtab /** Reify a reference to a symbol */ - def reifySymRef(sym0: Symbol): Tree = { - assert(sym0 != null, "sym is null") - val sym = sym0.dealias - + def reifySymRef(sym: Symbol): Tree = { + assert(sym != null, "sym is null") if (sym == NoSymbol) mirrorSelect(nme.NoSymbol) else if (sym.isRootPackage) diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index b97bf6b0cd..f48df8df65 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -161,11 +161,9 @@ trait GenTrees { if (tree.symbol.isLocalToReifee || tree.tpe.isLocalToReifee) reifyProduct(tree) else { - val sym0 = tree.symbol - val sym = sym0.dealias - val tpe0 = tree.tpe - val tpe = tpe0.dealias - if (reifyDebug) println("reifying bound type %s (underlying type is %s, dealiased is %s)".format(sym0, tpe0, tpe)) + val sym = tree.symbol + val tpe = tree.tpe + if (reifyDebug) println("reifying bound type %s (underlying type is %s)".format(sym, tpe)) if (tpe.isSpliceable) { val spliced = spliceType(tpe) @@ -187,7 +185,7 @@ trait GenTrees { if (reifyDebug) println("tpe is locatable: reify as Ident(%s)".format(sym)) mirrorBuildCall(nme.Ident, reify(sym)) } else { - if (reifyDebug) println("tpe is an alias, but not a locatable: reify as TypeTree(%s)".format(tpe)) + if (reifyDebug) println("tpe is not locatable: reify as TypeTree(%s)".format(tpe)) mirrorBuildCall(nme.TypeTree, reify(tpe)) } } diff --git a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala index f4e2200edc..82951a2434 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTypes.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTypes.scala @@ -11,9 +11,8 @@ trait GenTypes { * Reify a type. * For internal use only, use ``reified'' instead. */ - def reifyType(tpe0: Type): Tree = { - assert(tpe0 != null, "tpe is null") - val tpe = tpe0.dealias + def reifyType(tpe: Type): Tree = { + assert(tpe != null, "tpe is null") if (tpe.isErroneous) CannotReifyErroneousReifee(tpe) @@ -29,9 +28,9 @@ trait GenTypes { if (spliced != EmptyTree) return spliced - val tsym = tpe.typeSymbol + val tsym = tpe.typeSymbolDirect if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic) - Select(Select(reify(tpe.typeSymbol), nme.asTypeSymbol), nme.asTypeConstructor) + Select(Select(reify(tsym), nme.asTypeSymbol), nme.asTypeConstructor) else tpe match { case tpe @ NoType => reifyMirrorObject(tpe) @@ -107,13 +106,11 @@ trait GenTypes { } private def spliceAsManifest(tpe: Type): Tree = { - val ManifestClass = rootMirror.staticClass("scala.reflect.Manifest") - val ManifestModule = rootMirror.staticModule("scala.reflect.Manifest") - def isSynthetic(manifest: Tree) = manifest exists (sub => sub.symbol != null && (sub.symbol == ManifestModule || sub.symbol.owner == ManifestModule)) + def isSynthetic(manifest: Tree) = manifest exists (sub => sub.symbol != null && (sub.symbol == FullManifestModule || sub.symbol.owner == FullManifestModule)) def searchForManifest(typer: analyzer.Typer): Tree = analyzer.inferImplicit( EmptyTree, - appliedType(ManifestClass.asTypeConstructor, List(tpe)), + appliedType(FullManifestClass.asTypeConstructor, List(tpe)), reportAmbiguous = false, isView = false, context = typer.context, diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 60cc9e5fb8..49f5fca19d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -106,7 +106,7 @@ trait ContextErrors { def errMsg = { val paramName = param.name val paramTp = param.tpe - paramTp.typeSymbol match { + paramTp.typeSymbolDirect match { case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp) case _ => "could not find implicit value for "+ diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 68782379a6..da045e1a48 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1224,7 +1224,9 @@ trait Implicits { * reflect.Manifest for type 'tp'. An EmptyTree is returned if * no manifest is found. todo: make this instantiate take type params as well? */ - private def manifestOfType(tp: Type, full: Boolean): SearchResult = { + private def manifestOfType(tp: Type, flavor: Symbol): SearchResult = { + val full = flavor == FullManifestClass + val opt = flavor == OptManifestClass /** Creates a tree that calls the factory method called constructor in object reflect.Manifest */ def manifestFactoryCall(constructor: String, tparg: Type, args: Tree*): Tree = @@ -1256,7 +1258,7 @@ trait Implicits { if (containsExistential(tp1)) EmptyTree else manifestFactoryCall("singleType", tp, gen.mkAttributedQualifier(tp1)) case ConstantType(value) => - manifestOfType(tp1.deconst, full) + manifestOfType(tp1.deconst, FullManifestClass) case TypeRef(pre, sym, args) => if (isPrimitiveValueClass(sym) || isPhantomClass(sym)) { findSingletonManifest(sym.name.toString) @@ -1299,22 +1301,13 @@ trait Implicits { mot(tp1.skolemizeExistential, from, to) case _ => EmptyTree -/* !!! the following is almost right, but we have to splice nested manifest - * !!! types into this type. This requires a substantial extension of - * !!! reifiers. - val reifier = new Reifier() - val rtree = reifier.reifyTopLevel(tp1) - manifestFactoryCall("apply", tp, rtree) -*/ } } - val tagInScope = - if (full) resolveTypeTag(pos, NoType, tp, concrete = true, allowMaterialization = false) - else resolveClassTag(pos, tp, allowMaterialization = false) - if (tagInScope.isEmpty) mot(tp, Nil, Nil) - else { - if (full) { + if (full) { + val tagInScope = resolveTypeTag(pos, NoType, tp, concrete = true, allowMaterialization = false) + if (tagInScope.isEmpty) mot(tp, Nil, Nil) + else { if (ReflectRuntimeUniverse == NoSymbol) { // todo. write a test for this context.error(pos, s""" @@ -1330,44 +1323,62 @@ trait Implicits { |to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""".trim.stripMargin) return SearchFailure } + val cm = typed(Ident(ReflectRuntimeCurrentMirror)) + val interop = gen.mkMethodCall(ReflectRuntimeUniverse, nme.typeTagToManifest, List(tp), List(cm, tagInScope)) + wrapResult(interop) + } + } else { + mot(tp, Nil, Nil) match { + case SearchFailure if opt => wrapResult(gen.mkAttributedRef(NoManifest)) + case result => result } - - val interop = - if (full) { - val cm = typed(Ident(ReflectRuntimeCurrentMirror)) - gen.mkMethodCall(ReflectRuntimeUniverse, nme.typeTagToManifest, List(tp), List(cm, tagInScope)) - } else gen.mkMethodCall(ReflectBasis, nme.classTagToClassManifest, List(tp), List(tagInScope)) - wrapResult(interop) } } def wrapResult(tree: Tree): SearchResult = if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter) - /** The tag corresponding to type `pt`, provided `pt` is a flavor of a tag. + /** Materializes implicits of magic types (currently, manifests and tags). + * Will be replaced by implicit macros once we fix them. */ - private def implicitTagOrOfExpectedType(pt: Type): SearchResult = pt.dealias match { - case TypeRef(pre, sym, arg :: Nil) if ManifestSymbols(sym) => - manifestOfType(arg, sym == FullManifestClass) match { - case SearchFailure if sym == OptManifestClass => wrapResult(gen.mkAttributedRef(NoManifest)) - case result => result - } - case TypeRef(pre, sym, arg :: Nil) if TagSymbols(sym) => - tagOfType(pre, arg, sym) - case tp@TypeRef(_, sym, _) if sym.isAbstractType => - implicitTagOrOfExpectedType(tp.bounds.lo) // #3977: use tp (==pt.dealias), not pt (if pt is a type alias, pt.bounds.lo == pt) - case _ => + private def materializeImplicit(pt: Type): SearchResult = { + def fallback = { searchImplicit(implicitsOfExpectedType, false) // shouldn't we pass `pt` to `implicitsOfExpectedType`, or is the recursive case // for an abstract type really only meant for tags? + } + + pt match { + case TypeRef(_, sym, _) if sym.isAbstractType => + materializeImplicit(pt.dealias.bounds.lo) // #3977: use pt.dealias, not pt (if pt is a type alias, pt.bounds.lo == pt) + case pt @ TypeRef(pre, sym, arg :: Nil) => + sym match { + case sym if ManifestSymbols(sym) => manifestOfType(arg, sym) + case sym if TagSymbols(sym) => tagOfType(pre, arg, sym) + // as of late ClassManifest is an alias of ClassTag + // hence we need to take extra care when performing dealiasing + // because it might destroy the flavor of the manifest requested by the user + // when the user wants ClassManifest[T], we should invoke `manifestOfType` not `tagOfType` + // hence we don't do `pt.dealias` as we did before, but rather do `pt.betaReduce` + // unlike `dealias`, `betaReduce` performs at most one step of dealiasing + // while dealias pops all aliases in a single invocation + case sym if sym.isAliasType => materializeImplicit(pt.betaReduce) + case _ => fallback + } + case _ => + fallback + } } /** The result of the implicit search: * First search implicits visible in current context. * If that fails, search implicits in expected type `pt`. - * // [Eugene] the following two lines should be deleted after we migrate delegate tag materialization to implicit macros + * // [Eugene] the following lines should be deleted after we migrate delegate tag materialization to implicit macros * If that fails, and `pt` is an instance of a ClassTag, try to construct a class tag. * If that fails, and `pt` is an instance of a TypeTag, try to construct a type tag. + * If that fails, and `pt` is an instance of a ClassManifest, try to construct a class manifest. + * If that fails, and `pt` is an instance of a Manifest, try to construct a manifest. + * If that fails, and `pt` is an instance of a OptManifest, try to construct a class manifest and return NoManifest if construction fails. * If all fails return SearchFailure */ def bestImplicit: SearchResult = { @@ -1387,7 +1398,7 @@ trait Implicits { val failstart = Statistics.startTimer(oftypeFailNanos) val succstart = Statistics.startTimer(oftypeSucceedNanos) - result = implicitTagOrOfExpectedType(pt) + result = materializeImplicit(pt) if (result == SearchFailure) { context.updateBuffer(previousErrs) @@ -1434,7 +1445,16 @@ trait Implicits { } object ImplicitNotFoundMsg { - def unapply(sym: Symbol): Option[(Message)] = sym.implicitNotFoundMsg map (m => (new Message(sym, m))) + def unapply(sym: Symbol): Option[(Message)] = sym.implicitNotFoundMsg match { + case Some(m) => Some(new Message(sym, m)) + case None if sym.isAliasType => + // perform exactly one step of dealiasing + // this is necessary because ClassManifests are now aliased to ClassTags + // but we don't want to intimidate users by showing unrelated error messages + unapply(sym.info.resultType.betaReduce.typeSymbolDirect) + case _ => None + } + // check the message's syntax: should be a string literal that may contain occurrences of the string "${X}", // where `X` refers to a type parameter of `sym` def check(sym: Symbol): Option[String] = diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index d157666e47..322b9ebb25 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -1221,7 +1221,10 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { case ex: Throwable => None } - } getOrElse realex.getMessage + } getOrElse { + val msg = realex.getMessage + if (msg != null) msg else realex.getClass.getName + } fail(typer, expandee, msg = "exception during macro expansion: " + message) } } diff --git a/src/compiler/scala/tools/reflect/StdTags.scala b/src/compiler/scala/tools/reflect/StdTags.scala index c782181f21..18cbf9c4b7 100644 --- a/src/compiler/scala/tools/reflect/StdTags.scala +++ b/src/compiler/scala/tools/reflect/StdTags.scala @@ -12,7 +12,14 @@ import scala.reflect.runtime.{universe => ru} object StdTags { // root mirror is fine for these guys, since scala-library.jar is guaranteed to be reachable from the root mirror - lazy val tagOfString = ru.TypeTag.String + lazy val tagOfString = ru.TypeTag[String]( + ru.rootMirror, + new TypeCreator { + def apply[U <: BaseUniverse with Singleton](m: MirrorOf[U]): U # Type = { + val u = m.universe + u.definitions.StringClass.asTypeConstructor + } + }) lazy val tagOfListOfString = ru.TypeTag[List[String]]( ru.rootMirror, new TypeCreator { diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index b4178102b9..589c5c7eb0 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -216,7 +216,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => (singleton, jmeth) } - def runExpr(expr: Tree, freeTypes: Map[TypeName, Type] = Map[TypeName, Type]()): Any = { + def runExpr(expr: Tree): Any = { val freeTerms = expr.freeTerms // need to calculate them here, because later on they will be erased val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order |