From a04195e63727872f04ad01900a18f6ca9ec5cf2b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 27 Aug 2009 14:45:35 +0000 Subject: added manifests to most parts of standard libra... added manifests to most parts of standard library which deal with arrays. One test is temporarily disabled, as it shows a deep problem with multi-dimensional arrays (which was present all along). --- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 2 +- .../scala/tools/nsc/symtab/Definitions.scala | 4 ++++ src/compiler/scala/tools/nsc/symtab/StdNames.scala | 1 + .../scala/tools/nsc/transform/Erasure.scala | 28 ++++++++++------------ .../scala/tools/nsc/transform/UnCurry.scala | 10 +------- .../scala/tools/nsc/typechecker/Implicits.scala | 15 +++++------- .../tools/nsc/typechecker/NamesDefaults.scala | 4 ++-- .../scala/tools/nsc/typechecker/RefChecks.scala | 21 ++++++++++------ .../scala/tools/nsc/typechecker/Typers.scala | 22 +++++++++++++---- 9 files changed, 60 insertions(+), 47 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index aa057c43b5..66b358383d 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -512,7 +512,7 @@ abstract class TreeBuilder { if (contextBounds.isEmpty) vparamss else { val mods = Modifiers(if (owner.isTypeName) PARAMACCESSOR | LOCAL | PRIVATE else PARAM) - def makeEvidenceParam(tpt: Tree) = ValDef(mods | IMPLICIT, freshName("man$"), tpt, EmptyTree) + def makeEvidenceParam(tpt: Tree) = ValDef(mods | IMPLICIT, freshName(nme.EVIDENCE_PARAM_PREFIX), tpt, EmptyTree) vparamss ::: List(contextBounds map makeEvidenceParam) } diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 71f005a98a..87c874465a 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -649,6 +649,10 @@ trait Definitions { addModuleMethod(DoubleClass, "NegativeInfinity", java.lang.Double.NEGATIVE_INFINITY) } + /** Is symbol a phantom class for which no runtime representation exists? */ + def isPhantomClass(sym: Symbol) = + sym == AnyClass || sym == AnyValClass || sym == NullClass || sym == NothingClass + /** Is symbol a value class? */ def isValueClass(sym: Symbol): Boolean = (sym eq UnitClass) || (boxedClass contains sym) diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 5426a76643..894291d4dc 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -82,6 +82,7 @@ trait StdNames { val INTERPRETER_VAR_PREFIX = "res" val INTERPRETER_IMPORT_WRAPPER = "$iw" val INTERPRETER_SYNTHVAR_PREFIX = "synthvar$" + val EVIDENCE_PARAM_PREFIX = "evidence$" def LOCAL(clazz: Symbol) = newTermName(LOCALDUMMY_PREFIX_STRING + clazz.name+">") def TUPLE_FIELD(index: Int) = newTermName(TUPLE_FIELD_PREFIX_STRING + index) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index c3de8d6bd9..6618480d58 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -21,10 +21,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. // @S: XXX: why is this here? earsure is a typer, if you comment this // out erasure still works, uses its own typed methods. lazy val typerXXX = this.typer - import typerXXX.{typed} // methods to type trees + import typerXXX.{typed, typedPos} // methods to type trees import CODE._ - def typedPos(pos: Position)(tree: Tree) = typed { atPos(pos)(tree) } val phaseName: String = "erasure" @@ -387,7 +386,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. }) } - /** generate ScalaRuntime.boxArray(tree) */ + /** generate ScalaRuntime.boxArray(tree) + * !!! todo: optimize this in case the runtime type is known + */ private def boxArray(tree: Tree): Tree = tree match { case LabelDef(name, params, rhs) => val rhs1 = boxArray(rhs) @@ -451,12 +452,12 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. ELSE (x()) ) ) - else if (pt.typeSymbol isNonBottomSubClass BoxedArrayClass) once (x => - (IF (x() IS_OBJ BoxedArrayClass.tpe) THEN (x()) ELSE boxArray(x())) - ) - else if (isSeqClass(pt.typeSymbol)) once (x => - (IF (x() IS_OBJ pt) THEN (x()) ELSE (boxArray(x()))) - ) + else if (pt.typeSymbol isNonBottomSubClass BoxedArrayClass) + once (x => + (IF (x() IS_OBJ BoxedArrayClass.tpe) THEN (x()) ELSE boxArray(x()))) + else if (isSeqClass(pt.typeSymbol)) + once (x => + (IF (x() IS_OBJ pt) THEN (x()) ELSE (boxArray(x())))) else asPt(tree) } else asPt(tree) } @@ -560,12 +561,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. tree match { case Apply(Select(New(tpt), name), args) if (tpt.tpe.typeSymbol == BoxedArrayClass) => assert(name == nme.CONSTRUCTOR); - val translated: Tree = - if (args.length >= 2) REF(ArrayModule) DOT nme.ofDim - else NEW(BoxedAnyArrayClass) DOT name - - atPos(tree.pos) { - Typed(Apply(translated, args), tpt) + assert(args.length < 2) + typedPos(tree.pos) { + Typed(Apply(NEW(BoxedAnyArrayClass) DOT name, args), tpt) } case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if tree.symbol == Any_asInstanceOf => val qual1 = typedQualifier(qual) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 7af0c4f56c..9b2b9e2248 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -392,15 +392,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { if (traversableTpe != NoType && toArray != NoSymbol) { val arguments = if (toArray.tpe.paramTypes.isEmpty) List() // !!! old style toArray - else { // new style, with manifest - val manifestOpt = localTyper.findManifest(tree.tpe.typeArgs.head, false) - if (manifestOpt.tree.isEmpty) { - unit.error(tree.pos, "cannot find class manifest for element type of "+tree.tpe) - List(Literal(Constant(null))) - } else { - List(manifestOpt.tree) - } - } + else List(localTyper.getManifestTree(tree.pos, tree.tpe.typeArgs.head, false)) // new style, with manifest atPhase(phase.next) { localTyper.typed { atPos(pos) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 9d3cccab37..7ebaa27872 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -599,7 +599,7 @@ self: Analyzer => * reflect.Manifest for type 'tp'. An EmptyTree is returned if * no manifest is found. todo: make this instantiate take type params as well? */ - def manifestOfType(tp: Type, full: Boolean): Tree = { + private def manifestOfType(tp: Type, full: Boolean): Tree = { /** Creates a tree that calls the factory method called constructor in object reflect.Manifest */ def manifestFactoryCall(constructor: String, args: Tree*): Tree = @@ -627,25 +627,22 @@ self: Analyzer => case ConstantType(value) => manifestOfType(tp0.deconst, full) case TypeRef(pre, sym, args) => - if (isValueClass(sym)) { + if (isValueClass(sym) || isPhantomClass(sym)) { typed { atPos(tree.pos.focus) { Select(gen.mkAttributedRef(FullManifestModule), sym.name.toString) }} - } - else if (sym.isClass) { + } else if (sym.isClass) { val suffix = gen.mkClassOf(tp0) :: (args map findSubManifest) manifestFactoryCall( "classType", (if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix else findSubManifest(pre) :: suffix): _*) - } - else if (sym.isTypeParameterOrSkolem || sym.isExistential) { - EmptyTree // a manifest should have been found by normal searchImplicit - } - else { + } else if (sym.isAbstractType && !sym.isTypeParameterOrSkolem && !sym.isExistential) { manifestFactoryCall( "abstractType", findSubManifest(pre) :: Literal(sym.name.toString) :: findManifest(tp0.bounds.hi) :: (args map findSubManifest): _*) + } else { + EmptyTree // a manifest should have been found by normal searchImplicit } case RefinedType(parents, decls) => // refinement is not generated yet diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index d86c9f3b44..25af71be19 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -31,7 +31,7 @@ trait NamesDefaults { self: Analyzer => /** @param pos maps indicies from old to new */ - def reorderArgs[T](args: List[T], pos: Int => Int): List[T] = { + def reorderArgs[T: ClassManifest](args: List[T], pos: Int => Int): List[T] = { val res = new Array[T](args.length) // (hopefully) faster than zipWithIndex (0 /: args) { case (index, arg) => res(pos(index)) = arg; index + 1 } @@ -39,7 +39,7 @@ trait NamesDefaults { self: Analyzer => } /** @param pos maps indicies from new to old (!) */ - def reorderArgsInv[T](args: List[T], pos: Int => Int): List[T] = { + def reorderArgsInv[T: ClassManifest](args: List[T], pos: Int => Int): List[T] = { val argsArray = args.toArray val res = new ListBuffer[T] for (i <- 0 until argsArray.length) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 42d0dd80fb..3dec50e03d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -708,13 +708,7 @@ abstract class RefChecks extends InfoTransform { List(transform(cdef)) } } else { - val vdef = - localTyper.typed { - atPos(tree.pos) { - gen.mkModuleVarDef(sym) - } - } - + val vdef = localTyper.typedPos(tree.pos) { gen.mkModuleVarDef(sym) } val ddef = atPhase(phase.next) { localTyper.typed { @@ -930,6 +924,19 @@ abstract class RefChecks extends InfoTransform { if (tpt.tpe.typeSymbol == ArrayClass && args.length >= 2) => unit.deprecationWarning(tree.pos, "new Array(...) with multiple dimensions has been deprecated; use Array.ofDim(...) instead") + val manif = { + var etpe = tpt.tpe + for (_ <- args) { etpe = etpe.typeArgs.headOption.getOrElse(NoType) } + if (etpe == NoType) { + unit.error(tree.pos, "too many dimensions for array creation") + Literal(Constant(null)) + } else { + localTyper.getManifestTree(tree.pos, etpe, false) + } + } + result = localTyper.typedPos(tree.pos) { + Apply(Apply(Select(gen.mkAttributedRef(ArrayModule), nme.ofDim), args), List(manif)) + } currentApplication = tree case Apply(fn, args) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index cbb9129b30..372f8965e4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -180,7 +180,7 @@ trait Typers { self: Analyzer => def applyImplicitArgs(fun: Tree): Tree = fun.tpe match { case MethodType(params, _) => var positional = true - val argResults = params map (_.tpe) map (inferImplicit(fun, _, true, false, context)) + val argResults = params map (p => inferImplicit(fun, p.tpe, true, false, context)) val args = argResults.zip(params) flatMap { case (arg, param) => if (arg != SearchFailure) { @@ -188,8 +188,10 @@ trait Typers { self: Analyzer => else List(atPos(arg.tree.pos)(new AssignOrNamedArg(Ident(param.name), (arg.tree)))) } else { if (!param.hasFlag(DEFAULTPARAM)) - context.error(fun.pos, "could not find implicit value for parameter "+ - param.name +":"+ param.tpe +".") + context.error( + fun.pos, "could not find implicit value for "+ + (if (param.name startsWith nme.EVIDENCE_PARAM_PREFIX) "evidence parameter of type " + else "parameter "+param.name+": ")+param.tpe) positional = false Nil } @@ -956,7 +958,7 @@ trait Typers { self: Analyzer => if (coercion != EmptyTree) { if (settings.debug.value) log("inferred view from "+tree.tpe+" to "+pt+" = "+coercion+":"+coercion.tpe) return newTyper(context.makeImplicit(context.reportAmbiguousErrors)).typed( - Apply(coercion, List(tree)) setPos tree.pos, mode, pt) + Apply(coercion, List(tree)) setPos tree.pos, mode, pt) } } } @@ -3778,6 +3780,8 @@ trait Typers { self: Analyzer => ret } + def typedPos(pos: Position)(tree: Tree) = typed(atPos(pos)(tree)) + /** Types expression tree with given prototype pt. * * @param tree ... @@ -3851,6 +3855,16 @@ trait Typers { self: Analyzer => EmptyTree, appliedType((if (full) FullManifestClass else PartialManifestClass).typeConstructor, List(tp)), true, false, context) + + def getManifestTree(pos: Position, tp: Type, full: Boolean): Tree = { + val manifestOpt = findManifest(tp, false) + if (manifestOpt.tree.isEmpty) { + error(pos, "cannot find "+(if (full) "" else "class ")+"manifest for element type of "+tp) + Literal(Constant(null)) + } else { + manifestOpt.tree + } + } /* def convertToTypeTree(tree: Tree): Tree = tree match { case TypeTree() => tree -- cgit v1.2.3