diff options
author | Martin Odersky <odersky@gmail.com> | 2009-09-21 12:50:04 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-09-21 12:50:04 +0000 |
commit | d5b02c8652d7edbdfb0b5a02570d370d3bad299f (patch) | |
tree | f57063402f8a83cd3f7caf437afedbdb279be400 /src/compiler | |
parent | ced5ee337f45d0209ec3e7c69a6e04e956257ec0 (diff) | |
download | scala-d5b02c8652d7edbdfb0b5a02570d370d3bad299f.tar.gz scala-d5b02c8652d7edbdfb0b5a02570d370d3bad299f.tar.bz2 scala-d5b02c8652d7edbdfb0b5a02570d370d3bad299f.zip |
new arrays are done.
Diffstat (limited to 'src/compiler')
16 files changed, 221 insertions, 269 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index a27169503e..56b8253fa7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -655,10 +655,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable */ class Run { -// settings.newArrays.value = true -// settings.print.value = List("era") - if (settings.verbose.value) println("compiling with newArrays = "+settings.newArrays.value) - var isDefined = false private val firstPhase = { diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala index f87fdf093d..392fce46a3 100644 --- a/src/compiler/scala/tools/nsc/ScriptRunner.scala +++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala @@ -326,7 +326,7 @@ object ScriptRunner ObjectRunner.run( classpath, scriptMain(settings), - scriptArgs.toArray) + scriptArgs) true } catch { diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 233a3368bd..abf7026f3a 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -274,15 +274,10 @@ abstract class TreeGen DefDef(accessor setFlag lateDEFERRED, EmptyTree) def mkRuntimeCall(meth: Name, args: List[Tree]): Tree = { - assert(!settings.newArrays.value || meth.toString != "boxArray") + assert(meth.toString != "boxArray") // !!! can be removed once arrays are in. Apply(Select(mkAttributedRef(ScalaRunTimeModule), meth), args) } - // !!! todo: remove - def mkPredefCall(meth: Name, args: List[Tree]): Tree = { - Apply(Select(mkAttributedRef(PredefModule), meth), args) - } - /** Make a synchronized block on 'monitor'. */ def mkSynchronized(monitor: Tree, body: Tree): Tree = Apply(Select(monitor, Object_synchronized), List(body)) diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 2f8d6ae9f6..d7b6c16041 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -865,8 +865,7 @@ abstract class GenICode extends SubComponent { } else { ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos) if (tree.symbol == definitions.ArrayClass) - generatedType = REFERENCE( - if (settings.newArrays.value) definitions.ObjectClass else definitions.BoxedAnyArrayClass) + generatedType = REFERENCE(definitions.ObjectClass) else generatedType = REFERENCE(ctx.clazz.symbol) } diff --git a/src/compiler/scala/tools/nsc/io/Process.scala b/src/compiler/scala/tools/nsc/io/Process.scala index 6a1029fa02..e6626e0abe 100644 --- a/src/compiler/scala/tools/nsc/io/Process.scala +++ b/src/compiler/scala/tools/nsc/io/Process.scala @@ -42,7 +42,7 @@ object Process @experimental private[Process] class ProcessBuilder(val pb: JProcessBuilder) { - def this(cmd: String*) = this(new JProcessBuilder(cmd.toArray: _*)) + def this(cmd: String*) = this(new JProcessBuilder(cmd: _*)) def start() = new Process(() => pb.start()) def withOnlyEnv(env: Map[String, String]): this.type = { diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index 7d624d8289..6131d145f2 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -227,6 +227,11 @@ trait Definitions { } val MaxTupleArity, MaxProductArity, MaxFunctionArity = 22 + /** The maximal dimensions of a generic array creation. + * I.e. new Array[Array[Array[Array[Array[T]]]]] creates a 5 times + * nested array. More is not allowed. + */ + val MaxArrayDims = 5 lazy val TupleClass = mkArityArray("Tuple", MaxTupleArity) lazy val ProductClass = mkArityArray("Product", MaxProductArity) lazy val FunctionClass = mkArityArray("Function", MaxFunctionArity, 0) @@ -673,17 +678,15 @@ trait Definitions { def isValueClass(sym: Symbol): Boolean = (sym eq UnitClass) || (boxedClass contains sym) - /** Is symbol a value class? */ + /** Is symbol a numeric value class? */ def isNumericValueClass(sym: Symbol): Boolean = (sym ne BooleanClass) && (boxedClass contains sym) - // !!! todo comment & rename! - def isValueType(sym: Symbol) = + // !!! todo merge with isValueClass + def isValueType(sym: Symbol) = { + assert(isValueClass(sym) || !unboxMethod.contains(sym)) isValueClass(sym) || unboxMethod.contains(sym) - - /** Is symbol a value or array class? */ - def isUnboxedClass(sym: Symbol): Boolean = - isValueType(sym) || !settings.newArrays.value && sym == ArrayClass + } def signature(tp: Type): String = { def erasure(tp: Type): Type = tp match { @@ -751,6 +754,29 @@ trait Definitions { String_+ = newMethod( StringClass, "+", anyparam, StringClass.typeConstructor) setFlag FINAL + val forced = List( // force initialization of every symbol that is enetred as a side effect + AnnotationDefaultAttr, + RepeatedParamClass, + JavaRepeatedParamClass, + ByNameParamClass, + UnitClass, + ByteClass, + ShortClass, + CharClass, + IntClass, + LongClass, + FloatClass, + DoubleClass, + BooleanClass, + AnyClass, + AnyRefClass, + AnyValClass, + NullClass, + NothingClass, + SingletonClass, + EqualsPatternClass + ) + // #2264 var tmp = AnnotationDefaultAttr tmp = RepeatedParamClass // force initalization diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 885ff0d8ee..5f9a2b6bd3 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -548,7 +548,7 @@ trait Symbols { /** Is this symbol a sealed class?*/ final def isSealed: Boolean = - isClass && (hasFlag(SEALED) || isUnboxedClass(this)) + isClass && (hasFlag(SEALED) || isValueClass(this)) /** Is this symbol locally defined? I.e. not accessed from outside `this' instance */ final def isLocal: Boolean = owner.isTerm diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 45acc4f763..8136893fcb 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -337,7 +337,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { } } - def boxArray(t: Tree) = { + def boxArray(t: Tree) = t +/* was: assert(!settings.newArrays.value) val sym = currentOwner.newValue(ad.pos, mkTerm()) setInfo ObjectClass.tpe BLOCK( @@ -345,6 +346,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { IF (NULL ANY_== REF(sym)) THEN NULL ELSE gen.mkRuntimeCall(nme.boxArray, List(REF(sym))) ) } +*/ /* ### BOXING PARAMS & UNBOXING RESULTS ### */ diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 0efd87a0ac..37f28ec08e 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -33,25 +33,47 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. // -------- erasure on types -------------------------------------------------------- - /** If `tp` is of the form Array[...Array[T]...] where `T` is an abstract type - * then the number of Array constructors enclosing `T`, otherwise 0 - */ - def genericArrayLevel(tp: Type): Int = tp match { - case TypeRef(_, ArrayClass, List(arg)) => - arg match { - case TypeRef(_, argsym, _) if (argsym.isAbstractType && !(argsym.owner hasFlag JAVA)) => - 1 - case _ => - val l = genericArrayLevel(arg) - if (l > 0) l + 1 else 0 - } - case ExistentialType(tparams, restp) => - genericArrayLevel(restp) - case _ => - 0 + /** An extractor objec for generic arrays */ + object GenericArray { + + /** Is `tp` an unbounded generic type (i.e. which could be instantiated + * with primitive as well as class types)?. + */ + private def genericCore(tp: Type): Type = tp match { + case TypeRef(_, argsym, _) if (argsym.isAbstractType && !(argsym.owner hasFlag JAVA)) => + tp + case ExistentialType(tparams, restp) => + genericCore(restp) + case _ => + NoType + } + + /** If `tp` is of the form Array[...Array[T]...] where `T` is an abstract type + * then Some(N, T) where N is the number of Array constructors enclosing `T`, + * otherwise None. Existentials on any level are ignored. + */ + def unapply(tp: Type): Option[(Int, Type)] = tp match { + case TypeRef(_, ArrayClass, List(arg)) => + genericCore(arg) match { + case NoType => + unapply(arg) match { + case Some((level, core)) => Some((level + 1, core)) + case None => None + } + case core => + Some(1, core) + } + case ExistentialType(tparams, restp) => + unapply(restp) + case _ => + None + } } - def isTopLevelGenericArray(tp: Type): Boolean = genericArrayLevel(tp) == 1 + private def unboundedGenericArrayLevel(tp: Type): Int = tp match { + case GenericArray(level, core) if !(core <:< AnyRefClass.tpe) => level + case _ => 0 + } /** <p> * The erasure <code>|T|</code> of a type <code>T</code>. This is: @@ -104,8 +126,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. false } if (sym == ArrayClass) - if (!settings.newArrays.value && isGeneric(tp)) erasedTypeRef(BoxedArrayClass) - else if (settings.newArrays.value && isTopLevelGenericArray(tp)) ObjectClass.tpe + if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe + else if (args.head.typeSymbol == NothingClass || args.head.typeSymbol == NullClass) arrayType(ObjectClass.tpe) else typeRef(apply(pre), sym, args map this) else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass) erasedTypeRef(ObjectClass) else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) @@ -401,11 +423,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. case UnitClass => if (treeInfo isPureExpr tree) REF(BoxedUnit_UNIT) else BLOCK(tree, REF(BoxedUnit_UNIT)) - case ArrayClass => - assert(!settings.newArrays.value) - boxArray(tree) case x => - (REF(boxMethod(x)) APPLY tree) setPos (tree.pos) setType (ObjectClass.tpe) + assert(x != ArrayClass) + (REF(boxMethod(x)) APPLY tree) setPos (tree.pos) setType ObjectClass.tpe }) } @@ -435,57 +455,16 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. case UnitClass => if (treeInfo isPureExpr tree) UNIT else BLOCK(tree, UNIT) - case ArrayClass => - assert(!settings.newArrays.value) - val tree1 = adaptToType(tree, BoxedArrayClass.tpe) - gen.mkRuntimeCall(nme.arrayValue, List(tree1, Literal(pt.typeArgs.head))) - case _ => + case x => + assert(x != ArrayClass) (REF(unboxMethod(pt.typeSymbol)) APPLY tree) setType pt }) } - /** <p> - * Generate a cast operation from <code>tree.tpe</code> to <code>pt</code>. - * The following cases need to be treated specially: - * </p> - * <table> - * <tr> - * <td><code>Object -> Array</code></td> - * <td>(might be a boxedarray)</td> - * </tr> - * <tr> - * <td><code>Object -> Boxed*Array</code></td> - * <td>(might be an array, which nees to be boxed)</td> - * </tr> - * <tr> - * <td><code>Object -> Seq, Iterable</code></td> - * <td>(might be an array, which needs to be boxed)</td> - * </tr> - * </table> + /** Generate a synthetic cast operation from <code>tree.tpe</code> to <code>pt</code>. */ - private def cast(tree: Tree, pt: Type): Tree = { - if (settings.newArrays.value) return tree AS_ATTR pt - assert(pt eq pt.normalize) - def asPt(t: Tree) = t AS_ATTR pt - def once(within: (() => Tree) => Tree) = - typedPos(tree.pos)(gen.evalOnce(tree, context.owner, context.unit)(within andThen asPt)) - - if (tree.tpe.typeSymbol == ObjectClass) { - if (pt.typeSymbol == ArrayClass) once (x => - (IF (x() IS_OBJ BoxedArrayClass.tpe) - THEN (unbox(x() AS_ATTR BoxedArrayClass.tpe, pt)) - 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 asPt(tree) - } else asPt(tree) - } + private def cast(tree: Tree, pt: Type): Tree = + tree AS_ATTR pt /** Is symbol a member of unboxed arrays (which will be expanded directly * later)? @@ -512,14 +491,14 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug if (tree.tpe <:< pt) tree - else if (isUnboxedClass(tree.tpe.typeSymbol) && !isUnboxedClass(pt.typeSymbol)) + else if (isValueClass(tree.tpe.typeSymbol) && !isValueClass(pt.typeSymbol)) adaptToType(box(tree), pt) else if (tree.tpe.isInstanceOf[MethodType] && tree.tpe.paramTypes.isEmpty) { if (!tree.symbol.isStable) assert(false, "adapt "+tree+":"+tree.tpe+" to "+pt) adaptToType(Apply(tree, List()) setPos tree.pos setType tree.tpe.resultType, pt) } else if (pt <:< tree.tpe) cast(tree, pt) - else if (isUnboxedClass(pt.typeSymbol) && !isUnboxedClass(tree.tpe.typeSymbol)) + else if (isValueClass(pt.typeSymbol) && !isValueClass(tree.tpe.typeSymbol)) adaptToType(unbox(tree, pt), pt) else cast(tree, pt) @@ -584,17 +563,6 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. private def adaptMember(tree: Tree): Tree = { //Console.println("adaptMember: " + tree); tree match { - // newArrays: we do not need to handle ofDim for ne generic arrays here; has been treated in RefChecks - case Apply(Select(New(tpt), name), args) if (tpt.tpe.typeSymbol == BoxedArrayClass) => - assert(!settings.newArrays.value) - assert(name == nme.CONSTRUCTOR); - val translated: Tree = - if (args.length >= 2) REF(ArrayModule) DOT nme.ofDim - else NEW(BoxedAnyArrayClass) DOT name - - typedPos(tree.pos) { - Typed(Apply(translated, args), tpt) - } case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if tree.symbol == Any_asInstanceOf => val qual1 = typedQualifier(qual) val qualClass = qual1.tpe.typeSymbol @@ -605,16 +573,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List())) else */ - if (isValueType(targClass)) { - unbox(qual1, targ.tpe) - } else if (targClass == ArrayClass && (qualClass isNonBottomSubClass BoxedArrayClass)) { - assert(!settings.newArrays.value) - unbox(qual1, targ.tpe) - } else if (!settings.newArrays.value && targClass == ArrayClass && qualClass == ObjectClass || isSeqClass(targClass)) { - cast(qual1, targ.tpe) - } else { - tree - } + if (isValueType(targClass)) unbox(qual1, targ.tpe) + else tree case Select(qual, name) if (name != nme.CONSTRUCTOR) => if (tree.symbol == NoSymbol) tree @@ -626,15 +586,12 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name)))) else { var qual1 = typedQualifier(qual); - if ((isValueType(qual1.tpe.typeSymbol) && !isUnboxedValueMember(tree.symbol)) || - (qual1.tpe.typeSymbol == ArrayClass && !isUnboxedArrayMember(tree.symbol) && !settings.newArrays.value)) - qual1 = box(qual1); + if ((isValueType(qual1.tpe.typeSymbol) && !isUnboxedValueMember(tree.symbol))) + qual1 = box(qual1) else if (!isValueType(qual1.tpe.typeSymbol) && isUnboxedValueMember(tree.symbol)) qual1 = unbox(qual1, tree.symbol.owner.tpe) - else if (tree.symbol.owner == ArrayClass && (BoxedArrayClass isSubClass qual1.tpe.typeSymbol) && !settings.newArrays.value) - qual1 = cast(qual1, BoxedArrayClass.tpe) - if (isUnboxedClass(tree.symbol.owner) && !isUnboxedClass(qual1.tpe.typeSymbol)) + if (isValueClass(tree.symbol.owner) && !isValueClass(qual1.tpe.typeSymbol)) tree.symbol = NoSymbol else if (qual1.tpe.isInstanceOf[MethodType] && qual1.tpe.paramTypes.isEmpty) { assert(qual1.symbol.isStable, qual1.symbol); @@ -948,10 +905,10 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. treeCopy.DefDef(tree, mods, name, List(), vparamss, tpt, rhs) case TypeDef(_, _, _, _) => EmptyTree - case TypeApply(fun, args @ List(arg)) + case TypeApply(fun, args @ List(arg)) // !!! todo: simplify by having GenericArray also extract trees if ((fun.symbol == Any_isInstanceOf || fun.symbol == Object_isInstanceOf) && - genericArrayLevel(arg.tpe) > 0) => - val level = genericArrayLevel(arg.tpe) + unboundedGenericArrayLevel(arg.tpe) > 0) => + val level = unboundedGenericArrayLevel(arg.tpe) def isArrayTest(arg: Tree) = gen.mkRuntimeCall("isArray", List(arg, Literal(Constant(level)))) typedPos(tree.pos) { @@ -969,23 +926,11 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. // leave all other type tests/type casts, remove all other type applications fun case Apply(fn @ Select(qual, name), args) - if (settings.newArrays.value && fn.symbol.owner == ArrayClass && isTopLevelGenericArray(qual.tpe.widen)) => + if (fn.symbol.owner == ArrayClass && (unboundedGenericArrayLevel(qual.tpe.widen) == 1)) => // convert calls to apply/update/length on generic arrays to // calls of ScalaRunTime.array_xxx method calls typedPos(tree.pos) { gen.mkRuntimeCall("array_"+name, qual :: args) } case Apply(fn, args) => - if (!settings.newArrays.value) { - def isGenericArray(tpe: Type): Boolean = erasure(tpe).typeSymbol == BoxedArrayClass - if (fn.hasSymbol && - fn.symbol.name == nme.arraycopy && - fn.symbol.owner.name == nme.System.toTypeName && - fn.symbol.owner.owner == JavaLangPackage.tpe.typeSymbol && - args.length == 5 && - (isGenericArray(args(0).tpe) || isGenericArray(args(2).tpe))) - unit.warning(tree.pos, - "System.arraycopy should be applied only to arrays with fixed element types;\n" + - "use Array.copy instead") - } if (fn.symbol == Any_asInstanceOf) fn match { case TypeApply(Select(qual, _), List(targ)) => @@ -1024,16 +969,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. } } case _ => - if (isSeqClass(targ.tpe.typeSymbol) && !settings.newArrays.value) { - atPos(tree.pos) { - gen.evalOnce(qual, currentOwner, unit) { q => - gen.mkOr( - mkIsInstanceOf(q)(targ.tpe), - atPos(tree.pos) { REF(isArrayMethod) APPLY (q()) } - ) - } - } - } else tree + tree } case _ => tree } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index e10a8d8365..1cd7842fd4 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -23,11 +23,14 @@ import scala.tools.nsc.util.Position * if argument is not a reference to a def parameter: * convert argument `e' to (expansion of) `() => e' * - for every repeated Scala parameter `x: T*' --> x: Seq[T]. - * - for every repeated Java parameter `x: T*' --> x: Array[T]. - * - for every argument list that corresponds to a repeated parameter + * - for every repeated Java parameter `x: T...' --> x: Array[T], except: + * if T is an unbounded abstract type, replace --> x: Array[Object] + * - for every argument list that corresponds to a repeated Scala parameter * (a_1, ..., a_n) => (Seq(a_1, ..., a_n)) + * - for every argument list that corresponds to a repeated Java parameter + * (a_1, ..., a_n) => (Array(a_1, ..., a_n)) * - for every argument list that is an escaped sequence - * (a_1:_*) => (a_1)g + * (a_1:_*) => (a_1) (possibly converted to sequence or array, as needed) * - convert implicit method types to method types * - convert non-trivial catches in try statements to matches * - convert non-local returns to throws with enclosing try statements. @@ -49,6 +52,11 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { // OTOH, should be a problem as calls to normalize only occur on types with kind * in principle (in well-typed programs) private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp + private def isUnboundedGeneric(tp: Type) = tp match { + case t @ TypeRef(_, sym, _) => sym.isAbstractType && !(t <:< AnyRefClass.tpe) + case _ => false + } + private val uncurry: TypeMap = new TypeMap { def apply(tp0: Type): Type = { val tp = expandAlias(tp0) @@ -69,7 +77,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { case TypeRef(pre, sym, args) if (sym == RepeatedParamClass) => apply(appliedType(SeqClass.typeConstructor, args)) case TypeRef(pre, sym, args) if (sym == JavaRepeatedParamClass) => - apply(appliedType(ArrayClass.typeConstructor, args)) + apply(arrayType( + if (isUnboundedGeneric(args.head)) ObjectClass.tpe else args.head)) case _ => expandAlias(mapOver(tp)) } @@ -131,11 +140,17 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { freeLocalsTraverser(unit.body) unit.body = transform(unit.body) } + + private var nprinted = 0 + override def transform(tree: Tree): Tree = try { //debug postTransform(mainTransform(tree)) } catch { case ex: Throwable => - Console.println("exception when traversing " + tree) + if (nprinted < 10) { + Console.println("exception when traversing " + tree) + nprinted += 1 + } throw ex } @@ -357,70 +372,65 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { } } - def transformArgs(pos: Position, args: List[Tree], formals: List[Type], isJava: Boolean) = { + def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = { + val isJava = fun hasFlag JAVA val args1 = formals.lastOption match { case Some(lastFormal) if isRepeatedParamType(lastFormal) => - def callMethod(tree: Tree, nme: Name): Tree = { - assert(!settings.newArrays.value) - val sym = tree.tpe member nme - assert(sym != NoSymbol) - val arguments = - if (sym.tpe.paramTypes.isEmpty) List() // !!! no manifest required - else List(localTyper.getManifestTree(tree.pos, tree.tpe.typeArgs.head, false)) // call with manifest + def mkArrayValue(ts: List[Tree], elemtp: Type) = + ArrayValue(TypeTree(elemtp), ts) setType arrayType(elemtp) + + // when calling into scala varargs, make sure it's a sequence. + def arrayToSequence(tree: Tree, elemtp: Type) = { atPhase(phase.next) { localTyper.typedPos(pos) { - Apply(gen.mkAttributedSelect(tree, sym), arguments) + val predef = gen.mkAttributedRef(PredefModule) + val meth = + if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol) || + isValueClass(elemtp.typeSymbol)) + Select(predef, "wrapArray") + else + TypeApply(Select(predef, "genericWrapArray"), List(TypeTree(elemtp))) + Apply(meth, List(tree)) } } } - def mkArrayValue(ts: List[Tree]) = { - val elemTp = lastFormal.typeArgs.head - val arr = ArrayValue(TypeTree(elemTp), ts) setType arrayType(elemTp) - if (isJava || inPattern) arr - else if (settings.newArrays.value) - atPhase(phase.next) { - localTyper.typedPos(pos) { - val predef = gen.mkAttributedRef(PredefModule) - val meth = - if ((elemTp <:< AnyRefClass.tpe) || isValueClass(elemTp.typeSymbol)) - Select(predef, "wrapArray") - else - TypeApply(Select(predef, "genericWrapArray"), List(TypeTree(elemTp))) - Apply(meth, List(arr)) - } - } - else callMethod(arr, nme.toSequence) // println("need to callMethod("+arr+", nme.toSequence)"); arr } - } setType formals.last - // when calling into java varargs, make sure it's an array - see bug #1360 - def forceToArray(arg: Tree) = { - val Typed(tree, _) = arg - if (isJava && tree.tpe.typeSymbol != ArrayClass && - (tree.tpe.typeSymbol isSubClass TraversableClass)) { - if (settings.newArrays.value) { - val toArraySym = tree.tpe member nme.toArray - assert(toArraySym != NoSymbol) - atPhase(phase.next) { - localTyper.typedPos(pos) { - Apply( - gen.mkAttributedSelect(tree, toArraySym), - List(localTyper.getManifestTree(tree.pos, tree.tpe.typeArgs.head, false))) - } - } - } else callMethod(tree, nme.toArray) - } else tree + def sequenceToArray(tree: Tree) = { + val toArraySym = tree.tpe member nme.toArray + assert(toArraySym != NoSymbol) + atPhase(phase.next) { + localTyper.typedPos(pos) { + Apply( + gen.mkAttributedSelect(tree, toArraySym), + List(localTyper.getManifestTree(tree.pos, tree.tpe.typeArgs.head, false))) + } + } } - if (args.isEmpty) - List(mkArrayValue(args)) - else { - val suffix: Tree = - if (treeInfo isWildcardStarArg args.last) forceToArray(args.last) - else mkArrayValue(args drop (formals.length - 1)) - args.take(formals.length - 1) ::: List(suffix) + var suffix: Tree = + if (!args.isEmpty && (treeInfo isWildcardStarArg args.last)) { + val Typed(tree, _) = args.last; + if (isJava && !(tree.tpe.typeSymbol == ArrayClass) && (tree.tpe.typeSymbol isSubClass TraversableClass)) sequenceToArray(tree) + else tree + } else { + val lastElemType = lastFormal.typeArgs.head + val tree = mkArrayValue(args drop (formals.length - 1), lastElemType) + if (isJava || inPattern) tree + else arrayToSequence(tree, lastElemType) + } + atPhase(phase.next) { + if (isJava && + suffix.tpe.typeSymbol == ArrayClass && + isValueClass(suffix.tpe.typeArgs.head.typeSymbol) && + fun.tpe.paramTypes.last.typeSymbol == ArrayClass && + fun.tpe.paramTypes.last.typeArgs.head.typeSymbol == ObjectClass) + suffix = localTyper.typedPos(pos) { + gen.mkRuntimeCall("toObjectArray", List(suffix)) + } } + args.take(formals.length - 1) ::: List(suffix setType formals.last) case _ => args } @@ -539,7 +549,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { if (fn.symbol.name == nme.unapply) args else if (fn.symbol.name == nme.unapplySeq) - transformArgs(tree.pos, args, analyzer.unapplyTypeListFromReturnTypeSeq(fn.tpe), false) + transformArgs(tree.pos, fn.symbol, args, analyzer.unapplyTypeListFromReturnTypeSeq(fn.tpe)) else { assert(false,"internal error: UnApply node has wrong symbol"); null }) treeCopy.UnApply(tree, fn1, args1) @@ -556,8 +566,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { } else { withNeedLift(true) { val formals = fn.tpe.paramTypes; - val isJava = fn.symbol hasFlag JAVA // in case we need a varargs transformation - treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, args, formals, isJava))) + treeCopy.Apply(tree, transform(fn), transformTrees(transformArgs(tree.pos, fn.symbol, args, formals))) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index dbc90e569b..49e4b0758b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -602,14 +602,14 @@ self: Analyzer => 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 = + def manifestFactoryCall(constructor: String, tparg: Type, args: Tree*): Tree = if (args contains EmptyTree) EmptyTree else typed { atPos(tree.pos.focus) { Apply( TypeApply( Select(gen.mkAttributedRef(if (full) FullManifestModule else PartialManifestModule), constructor), - List(TypeTree(tp)) + List(TypeTree(tparg)) ), args.toList ) @@ -623,7 +623,7 @@ self: Analyzer => def mot(tp0: Type): Tree = tp0.normalize match { case ThisType(_) | SingleType(_, _) => - manifestFactoryCall("singleType", gen.mkAttributedQualifier(tp0)) + manifestFactoryCall("singleType", tp, gen.mkAttributedQualifier(tp0)) case ConstantType(value) => manifestOfType(tp0.deconst, full) case TypeRef(pre, sym, args) => @@ -631,15 +631,17 @@ self: Analyzer => typed { atPos(tree.pos.focus) { Select(gen.mkAttributedRef(FullManifestModule), sym.name.toString) }} - } else if (sym.isClass) { + } else if (sym == ArrayClass && args.length == 1) { + manifestFactoryCall("arrayType", args.head, findSubManifest(args.head)) + } else if (sym.isClass) { val suffix = gen.mkClassOf(tp0) :: (args map findSubManifest) manifestFactoryCall( - "classType", + "classType", tp, (if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix else findSubManifest(pre) :: suffix): _*) } else if (sym.isAbstractType && !sym.isTypeParameterOrSkolem && !sym.isExistential) { manifestFactoryCall( - "abstractType", + "abstractType", tp, findSubManifest(pre) :: Literal(sym.name.toString) :: findManifest(tp0.bounds.hi) :: (args map findSubManifest): _*) } else { EmptyTree // a manifest should have been found by normal searchImplicit @@ -647,7 +649,7 @@ self: Analyzer => case RefinedType(parents, decls) => // refinement is not generated yet if (parents.length == 1) findManifest(parents.head) - else manifestFactoryCall("intersectionType", parents map (findSubManifest(_)): _*) + else manifestFactoryCall("intersectionType", tp, parents map (findSubManifest(_)): _*) case ExistentialType(tparams, result) => mot(result) case _ => diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 20f6a1ff45..f7829208b1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -860,7 +860,7 @@ trait Infer { def isInProperSubClassOrObject(sym1: Symbol, sym2: Symbol) = sym2 == NoSymbol || isProperSubClassOrObject(sym1.owner, sym2.owner) - def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type, sym1: Symbol, sym2: Symbol): Boolean = + def isStrictlyMoreSpecific(ftpe1: Type, ftpe2: Type, sym1: Symbol, sym2: Symbol): Boolean = { // ftpe1 / ftpe2 are OverloadedTypes (possibly with one single alternative) if they // denote the type of an "apply" member method (see "followApply") ftpe1.isError || { @@ -871,8 +871,11 @@ trait Infer { (!phase.erasedTypes || covariantReturnOverride(ftpe1, ftpe2))) 1 else 0) val subClassCount = (if (isInProperSubClassOrObject(sym1, sym2)) 1 else 0) - (if (isInProperSubClassOrObject(sym2, sym1)) 1 else 0) + //println("is more specific? "+sym1+sym1.locationString+"/"+sym2+sym2.locationString+":"+ + // specificCount+"/"+subClassCount+"/"+) specificCount + subClassCount > 0 } + } /* ftpe1.isError || { if (isAsSpecific(ftpe1, ftpe2)) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 7cca32a779..be0c65c49b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -916,7 +916,7 @@ abstract class RefChecks extends InfoTransform { List(ValDef(_, pname, tpt, _)), Match(_, CaseDef(pat1, _, _) :: _)))) if ((pname startsWith nme.CHECK_IF_REFUTABLE_STRING) && - isIrrefutable(pat1, tpt.tpe)) => + isIrrefutable(pat1, tpt.tpe) && (qual.tpe <:< tree.tpe)) => result = qual case Apply(Select(New(tpt), name), args) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2d519f8da8..792e24049f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -142,12 +142,6 @@ trait Typers { self: Analyzer => */ val HKmode = 0x4000 // @M: could also use POLYmode | TAPPmode - /** The mode <code>JAVACALLmode</code> is set when we are typing a call to a Java method - * needed temporarily for vararg conversions - * !!!VARARG-CONVERSION!!! - */ - val JAVACALLmode = 0x8000 - /** The mode <code>TYPEPATmode</code> is set when we are typing a type in a pattern */ val TYPEPATmode = 0x10000 @@ -162,7 +156,6 @@ trait Typers { self: Analyzer => private def argMode(fun: Tree, mode: Int) = if (treeInfo.isSelfOrSuperConstrCall(fun)) mode | SCCmode - else if (fun.symbol hasFlag JAVA) mode | JAVACALLmode // !!!VARARG-CONVERSION!!! else mode abstract class Typer(context0: Context) { @@ -710,6 +703,23 @@ trait Typers { self: Analyzer => ex }} + /** Utility method: Try op1 on tree. If that gives an error try op2 instead. + */ + def tryBoth(tree: Tree)(op1: (Typer, Tree) => Tree)(op2: (Typer, Tree) => Tree): Tree = + silent(op1(_, tree.duplicate)) match { + case result1: Tree => + result1 + case ex1: TypeError => + silent(op2(_, tree)) match { + case result2: Tree => +// println("snd succeeded: "+result2) + result2 + case ex2: TypeError => + reportTypeError(tree.pos, ex1) + setError(tree) + } + } + /** Perform the following adaptations of expression, pattern or type `tree' wrt to * given mode `mode' and given prototype `pt': * (-1) For expressions with annotated types, let AnnotationCheckers decide what to do @@ -907,20 +917,7 @@ trait Typers { self: Analyzer => assert((mode & HKmode) == 0) //@M instantiate(tree, mode, pt) } else if (tree.tpe <:< pt) { - def isStructuralType(tpe: Type): Boolean = tpe match { - case RefinedType(ps, decls) => - decls.toList exists (x => x.isTerm && x.allOverriddenSymbols.isEmpty) - case _ => - false - } - if (isStructuralType(pt) && tree.tpe.typeSymbol == ArrayClass && !settings.newArrays.value) { - // all Arrays used as structural refinement typed values must be boxed - // this does not solve the case where the type to be adapted to comes - // from a type variable that was bound by a strctural but is instantiated - typed(Apply(Select(gen.mkAttributedRef(ScalaRunTimeModule), nme.forceBoxedArray), List(tree))) - } - else - tree + tree } else { if ((mode & PATTERNmode) != 0) { if ((tree.symbol ne null) && tree.symbol.isModule) @@ -1883,33 +1880,8 @@ trait Typers { self: Analyzer => val prefix = List.map2(args take nonVarCount, adaptedFormals take nonVarCount) ((arg, formal) => typedArg(arg, mode, 0, formal)) - - // if array is passed into java vararg and formal's element is not an array, - // convert it to vararg by adding : _* - // this is a gross hack to enable vararg transition; remove it as soon as possible. - // !!!VARARG-CONVERSION!!! - def hasArrayElement(tpe: Type) = - tpe.typeArgs.length == 1 && tpe.typeArgs.head.typeSymbol == ArrayClass - var args0 = args - if ((mode & JAVACALLmode) != 0 && - (args.length == originalFormals.length) && - !hasArrayElement(adaptedFormals(nonVarCount)) && - !settings.XnoVarargsConversion.value) { - val lastarg = typedArg(args(nonVarCount), mode, REGPATmode, WildcardType) - if ((lastarg.tpe.typeSymbol == ArrayClass || lastarg.tpe.typeSymbol == NullClass) && - !treeInfo.isWildcardStarArg(lastarg)) { - if (lastarg.tpe.typeSymbol == ArrayClass) - unit.warning( - lastarg.pos, - "I'm seeing an array passed into a Java vararg.\n"+ - "I assume that the elements of this array should be passed as individual arguments to the vararg.\n"+ - "Therefore I follow the array with a `: _*', to mark it as a vararg argument.\n"+ - "If that's not what you want, compile this file with option -Xno-varargs-conversion.") - args0 = args.init ::: List(gen.wildcardStar(args.last)) - } - } val suffix = - List.map2(args0 drop nonVarCount, adaptedFormals drop nonVarCount) ((arg, formal) => + List.map2(args drop nonVarCount, adaptedFormals drop nonVarCount) ((arg, formal) => typedArg(arg, mode, REGPATmode, formal)) prefix ::: suffix } else { @@ -3600,8 +3572,13 @@ trait Typers { self: Analyzer => case Typed(expr, tpt) => if (treeInfo.isWildcardStarArg(tree)) { - val expr1 = typed(expr, mode & stickyModes, seqType(pt)) - expr1.tpe.baseType(SeqClass) match { + val expr0 = typed(expr, mode & stickyModes, WildcardType) + val (expr1, baseClass) = + if (expr0.tpe.typeSymbol == ArrayClass) + (adapt(expr0, mode & stickyModes, arrayType(pt)), ArrayClass) + else + (adapt(expr0, mode & stickyModes, seqType(pt)), SeqClass) + expr1.tpe.baseType(baseClass) match { case TypeRef(_, _, List(elemtp)) => treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp case _ => @@ -3659,11 +3636,18 @@ trait Typers { self: Analyzer => case Apply(fun, args) => typedApply(fun, args) match { case Apply(Select(New(tpt), name), args) - if (settings.newArrays.value && tpt.tpe.typeSymbol == ArrayClass && args.length == 1 && erasure.isTopLevelGenericArray(tpt.tpe)) => + if (tpt.tpe != null && + tpt.tpe.typeSymbol == ArrayClass && + args.length == 1 && + erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor // convert new Array[T](len) to evidence[ClassManifest[T]].newArray(len) + // convert new Array^N[T](len) for N > 1 to evidence[ClassManifest[T]].newArrayN(len) + val Some((level, manifType)) = erasure.GenericArray.unapply(tpt.tpe) + if (level > MaxArrayDims) + error(tree.pos, "cannot create a generic multi-dimensional array of more than "+MaxArrayDims+" dimensions") val newArrayApp = atPos(tree.pos) { - val manif = getManifestTree(tree.pos, tpt.tpe.typeArgs.head, false) - Apply(Select(manif, nme.newArray), args) + val manif = getManifestTree(tree.pos, manifType, false) + Apply(Select(manif, if (level == 1) "newArray" else "newArray"+level), args) } typed(newArrayApp, mode, pt) case tree1 => diff --git a/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala index 6876d74b81..37c8488804 100755 --- a/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala @@ -62,7 +62,7 @@ class JavaCharArrayReader(buf: RandomAccessSeq[Char], start: Int, /* startline: def next: Char = { //cline = nextline //ccol = nextcol - val buf = this.buf.asInstanceOf[runtime.BoxedCharArray].value + val buf = this.buf.asInstanceOf[collection.mutable.WrappedArray[Char]].array if(!hasNext) { ch = SU return SU // there is an endless stream of SU's at the end diff --git a/src/compiler/scala/tools/nsc/util/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala index 2d8d963ca3..d11f9a3db1 100644 --- a/src/compiler/scala/tools/nsc/util/SourceFile.scala +++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala @@ -176,7 +176,7 @@ extends BatchSourceFile(name, contents) this( name, components.toList, - Array.concat(components.toList.map(comp => + Array.concat(components.map(comp => CompoundSourceFile.stripSU(comp.content).toArray):_*)) } |