summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-09-21 12:50:04 +0000
committerMartin Odersky <odersky@gmail.com>2009-09-21 12:50:04 +0000
commitd5b02c8652d7edbdfb0b5a02570d370d3bad299f (patch)
treef57063402f8a83cd3f7caf437afedbdb279be400 /src/compiler
parentced5ee337f45d0209ec3e7c69a6e04e956257ec0 (diff)
downloadscala-d5b02c8652d7edbdfb0b5a02570d370d3bad299f.tar.gz
scala-d5b02c8652d7edbdfb0b5a02570d370d3bad299f.tar.bz2
scala-d5b02c8652d7edbdfb0b5a02570d370d3bad299f.zip
new arrays are done.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala3
-rw-r--r--src/compiler/scala/tools/nsc/io/Process.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala40
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala184
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala127
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala88
-rwxr-xr-xsrc/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/SourceFile.scala2
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):_*))
}