summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-12-20 23:34:20 +0000
committerPaul Phillips <paulp@improving.org>2010-12-20 23:34:20 +0000
commit3bfd81869ccffd0657a1b82eb483e0f26a283a46 (patch)
tree669c49e2d0d3302cb04b20dffe91c77292526306 /src/compiler
parent3cfee5b1450a42c31a857c5dd10f68387d88e669 (diff)
downloadscala-3bfd81869ccffd0657a1b82eb483e0f26a283a46.tar.gz
scala-3bfd81869ccffd0657a1b82eb483e0f26a283a46.tar.bz2
scala-3bfd81869ccffd0657a1b82eb483e0f26a283a46.zip
This commit is about not calling .length or .si...
This commit is about not calling .length or .size on Lists. Sometimes it is unavoidable; not often. I created some methods for the compiler which should probably be in the collections, which do things like test if two sequences have the same length in a more efficient manner than calling length on each. Also, wouldn't it be wonderful to have some mechanism for finding these issues in a more automated way. Like say an annotation: LinearSeqLike { @badjuju("Calling length on linear seqs is O(n)") def length: Int = whee } Or since I imagine everyone thinks they're calling length with lists of 2 or 3, an optional runtime check which yelled if it sees you calling length on a 600 element list, or worse: var i = 0 while (i < myList.length) { // you don't want to see what this does f(myList(i)) ; i += 1; } Uniformity of interface without uniformity of behavior leaves us with traps. No review.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterLoop.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala10
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala6
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala94
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala135
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala2
13 files changed, 156 insertions, 135 deletions
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
index ebfecc7204..55f361cf1f 100644
--- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
@@ -633,7 +633,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
vname + ": " + vtype
}
- if (strs.size == 0) "Set no variables."
+ if (strs.isEmpty) "Set no variables."
else "Variables set:\n" + strs.mkString("\n")
}
diff --git a/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala b/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala
index 27f5b27303..cc2c2b3517 100644
--- a/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala
+++ b/src/compiler/scala/tools/nsc/backend/WorklistAlgorithm.scala
@@ -40,8 +40,8 @@ trait WorklistAlgorithm {
def run(initWorklist: => Unit) = {
initWorklist
- while (!(worklist.length == 0))
- processElement(dequeue);
+ while (worklist.nonEmpty)
+ processElement(dequeue)
}
/**
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 50bb26d491..56f130a183 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1058,10 +1058,11 @@ abstract class GenICode extends SubComponent {
generatedType = UNIT
genStat(tree, ctx)
- case ArrayValue(tpt @ TypeTree(), elems) =>
+ case ArrayValue(tpt @ TypeTree(), _elems) =>
var ctx1 = ctx
val elmKind = toTypeKind(tpt.tpe)
generatedType = ARRAY(elmKind)
+ val elems = _elems.toIndexedSeq
ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos)
ctx1.bb.emit(CREATE_ARRAY(elmKind, 1))
@@ -1962,7 +1963,7 @@ abstract class GenICode extends SubComponent {
}
def exitScope = {
- if (bb.size > 0) {
+ if (bb.nonEmpty) {
scope.locals foreach { lv => bb.emit(SCOPE_EXIT(lv)) }
}
scope = scope.outer
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala
index aaf8037768..2151fdaaf2 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Linearizers.scala
@@ -60,7 +60,7 @@ trait Linearizers { self: ICodes =>
}
def processElement(b: BasicBlock) =
- if (b.size > 0) {
+ if (b.nonEmpty) {
add(b);
b.lastInstruction match {
case JUMP(whereto) =>
@@ -118,7 +118,7 @@ trait Linearizers { self: ICodes =>
}
def dfs(b: BasicBlock): Unit =
- if (b.size > 0 && add(b))
+ if (b.nonEmpty && add(b))
b.successors foreach dfs;
/**
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 8a09009ad2..41782ffdcb 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -1638,8 +1638,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid {
* Synthetic locals are skipped. All variables are method-scoped.
*/
private def genLocalVariableTable(m: IMethod, jcode: JCode) {
- var vars = m.locals filterNot (_.sym.isSynthetic)
- if (vars.length == 0) return
+ val vars = m.locals filterNot (_.sym.isSynthetic)
+ if (vars.isEmpty) return
val pool = jclass.getConstantPool
val pc = jcode.getPC()
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index 68412098e3..6221d808a2 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -215,10 +215,8 @@ abstract class DeadCodeElimination extends SubComponent {
}
}
- if (bb.size > 0)
- bb.close
- else
- log("empty block encountered")
+ if (bb.nonEmpty) bb.close
+ else log("empty block encountered")
}
}
@@ -256,9 +254,9 @@ abstract class DeadCodeElimination extends SubComponent {
}
private def withClosed[a](bb: BasicBlock)(f: => a): a = {
- if (bb.size > 0) bb.close
+ if (bb.nonEmpty) bb.close
val res = f
- if (bb.size > 0) bb.open
+ if (bb.nonEmpty) bb.open
res
}
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 540ed5b7f2..5b57331684 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -687,10 +687,10 @@ trait ParallelMatching extends ast.TreeDSL
object ExpandedMatrix {
def unapply(x: ExpandedMatrix) = Some((x.rows, x.targets))
def apply(rowz: List[(Row, FinalState)]) =
- new ExpandedMatrix(rowz map (_._1), rowz map (_._2))
+ new ExpandedMatrix(rowz map (_._1), rowz map (_._2) toIndexedSeq)
}
- class ExpandedMatrix(val rows: List[Row], val targets: List[FinalState]) {
+ class ExpandedMatrix(val rows: List[Row], val targets: IndexedSeq[FinalState]) {
require(rows.size == targets.size)
override def toString() = {
@@ -818,7 +818,7 @@ trait ParallelMatching extends ast.TreeDSL
def ppn(x: Any) = pp(x, newlines = true)
override def toString() =
- if (tvars.size == 0) "Rep(%d) = %s".format(rows.size, ppn(rows))
+ if (tvars.isEmpty) "Rep(%d) = %s".format(rows.size, ppn(rows))
else "Rep(%dx%d)%s%s".format(tvars.size, rows.size, ppn(tvars), ppn(rows))
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 0efe87eb33..6681076e94 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -428,7 +428,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable =>
* Amounts to substitution except for higher-kinded types. (See overridden method in TypeRef) -- @M
*/
def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
- if(formals.length == actuals.length) this.subst(formals, actuals) else ErrorType
+ if (sameLength(formals, actuals)) this.subst(formals, actuals) else ErrorType
/** If this type is an existential, turn all existentially bound variables to type skolems.
* @param owner The owner of the created type skolems
@@ -1782,9 +1782,9 @@ A type's typeSymbol should never be inspected directly.
if (isHigherKinded) {
val substTps = formals.intersect(typeParams)
- if (substTps.length == typeParams.length)
+ if (sameLength(substTps, typeParams))
typeRef(pre, sym, actuals)
- else if(formals.length == actuals.length) // partial application (needed in infer when bunching type arguments from classes and methods together)
+ else if (sameLength(formals, actuals)) // partial application (needed in infer when bunching type arguments from classes and methods together)
typeRef(pre, sym, dummyArgs).subst(formals, actuals)
else ErrorType
}
@@ -1795,7 +1795,7 @@ A type's typeSymbol should never be inspected directly.
private var normalized: Type = null
@inline private def betaReduce: Type = {
- assert(sym.info.typeParams.length == typeArgs.length, this)
+ assert(sameLength(sym.info.typeParams, typeArgs), this)
// isHKSubType0 introduces synthetic type params so that betaReduce can first apply sym.info to typeArgs before calling asSeenFrom
// asSeenFrom then skips synthetic type params, which are used to reduce HO subtyping to first-order subtyping, but which can't be instantiated from the given prefix and class
// appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) // this crashes pos/depmet_implicit_tpbetareduce.scala
@@ -1810,14 +1810,14 @@ A type's typeSymbol should never be inspected directly.
}
override def dealias: Type =
- if (sym.isAliasType && sym.info.typeParams.length == args.length) {
+ if (sym.isAliasType && sameLength(sym.info.typeParams, args)) {
betaReduce.dealias
} else this
def normalize0: Type =
if (pre eq WildcardType) WildcardType // arises when argument-dependent types are approximated (see def depoly in implicits)
else if (isHigherKinded) etaExpand // eta-expand, subtyping relies on eta-expansion of higher-kinded types
- else if (sym.isAliasType && sym.info.typeParams.length == args.length)
+ else if (sym.isAliasType && sameLength(sym.info.typeParams, args))
betaReduce.normalize // beta-reduce, but don't do partial application -- cycles have been checked in typeRef
else if (sym.isRefinementClass)
sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers
@@ -1841,11 +1841,14 @@ A type's typeSymbol should never be inspected directly.
override def normalize: Type = {
if (phase.erasedTypes) normalize0
- else if (normalized == null || typeParamsDirect.length != normalizeTyparCount) {
- normalizeTyparCount = typeParamsDirect.length
- normalized = normalize0
+ else {
+ val len = typeParamsDirect.length
+ if (normalized == null || len != normalizeTyparCount) {
+ normalizeTyparCount = len
+ normalized = normalize0
+ }
normalized
- } else normalized
+ }
}
override def decls: Scope = {
@@ -1910,7 +1913,7 @@ A type's typeSymbol should never be inspected directly.
if (isFunctionType(this))
return normalize.typeArgs.init.mkString("(", ", ", ")") + " => " + normalize.typeArgs.last
else if (isTupleTypeOrSubtype(this))
- return normalize.typeArgs.mkString("(", ", ", if (normalize.typeArgs.length == 1) ",)" else ")")
+ return normalize.typeArgs.mkString("(", ", ", if (hasLength(normalize.typeArgs, 1)) ",)" else ")")
else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic)) {
val normed = normalize;
if (normed ne this) return normed.toString
@@ -2003,9 +2006,9 @@ A type's typeSymbol should never be inspected directly.
}
override def resultType(actuals: List[Type]) =
- if(isTrivial) dropNonContraintAnnotations(resultType)
+ if (isTrivial) dropNonContraintAnnotations(resultType)
else {
- if(actuals.length == params.length) {
+ if (sameLength(actuals, params)) {
val idm = new InstantiateDependentMap(params, actuals)
val res = idm(resultType)
// println("resultTypeDep "+(params, actuals, resultType, idm.existentialsNeeded, "\n= "+ res))
@@ -2165,10 +2168,10 @@ A type's typeSymbol should never be inspected directly.
if (!(quantified exists (_.isSingletonExistential)) && !settings.debug.value)
// try to represent with wildcards first
underlying match {
- case TypeRef(pre, sym, args) if (!args.isEmpty) =>
+ case TypeRef(pre, sym, args) if args.nonEmpty =>
val wargs = wildcardArgsString(quantified.toSet, args)
- if (wargs.length == args.length)
- return TypeRef(pre, sym, List()).toString+wargs.mkString("[", ", ", "]")
+ if (sameLength(wargs, args))
+ return TypeRef(pre, sym, List()) + wargs.mkString("[", ", ", "]")
case _ =>
}
var ustr = underlying.toString
@@ -2274,7 +2277,7 @@ A type's typeSymbol should never be inspected directly.
*/
class TypeVar(val origin: Type, val constr0: TypeConstraint, override val typeArgs: List[Type], override val params: List[Symbol]) extends Type {
// params are needed to keep track of variance (see mapOverArgs in SubstMap)
- assert(typeArgs.isEmpty || typeArgs.length == params.length)
+ assert(typeArgs.isEmpty || sameLength(typeArgs, params))
// var tid = { tidCount += 1; tidCount } //DEBUG
/** The constraint associated with the variable */
@@ -2291,7 +2294,7 @@ A type's typeSymbol should never be inspected directly.
* ?CC's hibounds contains List and Iterable
*/
def applyArgs(newArgs: List[Type]): TypeVar =
- if(newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...)
+ if (newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...)
else TypeVar(origin, constr, newArgs, params) // @M TODO: interaction with undoLog??
// newArgs.length may differ from args.length (could've been empty before)
// example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A]
@@ -2375,7 +2378,7 @@ A type's typeSymbol should never be inspected directly.
* Checks subtyping of higher-order type vars, and uses variances as defined in the
* type parameter we're trying to infer (the result will be sanity-checked later)
*/
- def unifyFull(tp: Type) = (typeArgs.length == tp.typeArgs.length) && { // this is a higher-kinded type var with same arity as tp
+ def unifyFull(tp: Type) = sameLength(typeArgs, tp.typeArgs) && { // this is a higher-kinded type var with same arity as tp
// side effect: adds the type constructor itself as a bound
addBound(tp.typeConstructor)
if (isLowerBound) isSubArgs(tp.typeArgs, typeArgs, params)
@@ -2652,7 +2655,7 @@ A type's typeSymbol should never be inspected directly.
def transform(tp: Type): Type =
tp.resultType.asSeenFrom(pre, sym1.owner).instantiateTypeParams(sym1.typeParams, args)
- if (sym1.isAliasType && sym1.info.typeParams.length == args.length) {
+ if (sym1.isAliasType && sameLength(sym1.info.typeParams, args)) {
if (!sym1.lockOK)
throw new TypeError("illegal cyclic reference involving " + sym1)
// note: we require that object is initialized,
@@ -3153,7 +3156,7 @@ A type's typeSymbol should never be inspected directly.
if ((args eq args1) && (atp eq atp1))
Some(annot)
- else if (args1.length == args.length)
+ else if (sameLength(args1, args))
Some(AnnotationInfo(atp1, args1, assocs).setPos(annot.pos))
else
None
@@ -3162,8 +3165,8 @@ A type's typeSymbol should never be inspected directly.
/** Map over a set of annotation arguments. If any
* of the arguments cannot be mapped, then return Nil. */
def mapOverAnnotArgs(args: List[Tree]): List[Tree] = {
- val args1 = args.flatMap(mapOver(_))
- if (args1.length != args.length)
+ val args1 = args flatMap (x => mapOver(x))
+ if (!sameLength(args1, args))
Nil
else if (allEq(args, args1))
args
@@ -3368,7 +3371,7 @@ A type's typeSymbol should never be inspected directly.
pre.baseType(symclazz) match {
case TypeRef(_, basesym, baseargs) =>
//Console.println("instantiating " + sym + " from " + basesym + " with " + basesym.typeParams + " and " + baseargs+", pre = "+pre+", symclazz = "+symclazz);//DEBUG
- if (basesym.typeParams.length == baseargs.length) {
+ if (sameLength(basesym.typeParams, baseargs)) {
instParam(basesym.typeParams, baseargs)
} else {
throw new TypeError(
@@ -3393,7 +3396,7 @@ A type's typeSymbol should never be inspected directly.
/** A base class to compute all substitutions */
abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap {
- assert(from.length == to.length, "Unsound substitution from "+ from +" to "+ to)
+ assert(sameLength(from, to), "Unsound substitution from "+ from +" to "+ to)
/** Are `sym' and `sym1' the same.
* Can be tuned by subclasses.
@@ -4282,7 +4285,7 @@ A type's typeSymbol should never be inspected directly.
// assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length)))
// @M looks like it might suffer from same problem as #2210
return (
- (tparams1.length == tparams2.length) && // corresponds does not check length of two sequences before checking the predicate
+ (sameLength(tparams1, tparams2)) && // corresponds does not check length of two sequences before checking the predicate
(tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) &&
res1 =:= res2.substSym(tparams2, tparams1)
)
@@ -4293,7 +4296,8 @@ A type's typeSymbol should never be inspected directly.
case ExistentialType(tparams2, res2) =>
// @M looks like it might suffer from same problem as #2210
return (
- (tparams1.length == tparams2.length) && // corresponds does not check length of two sequences before checking the predicate -- faster & needed to avoid crasher in #2956
+ // corresponds does not check length of two sequences before checking the predicate -- faster & needed to avoid crasher in #2956
+ sameLength(tparams1, tparams2) &&
(tparams1 corresponds tparams2)(_.info =:= _.info.substSym(tparams2, tparams1)) &&
res1 =:= res2.substSym(tparams2, tparams1)
)
@@ -4364,6 +4368,19 @@ A type's typeSymbol should never be inspected directly.
*/
def isSameTypes(tps1: List[Type], tps2: List[Type]): Boolean = (tps1 corresponds tps2)(_ =:= _)
+ /** True if two lists have the same length. Since calling length on linear sequences
+ * is O(n), it is an inadvisable way to test length equality.
+ */
+ final def sameLength(xs1: List[_], xs2: List[_]) = compareLengths(xs1, xs2) == 0
+ @tailrec final def compareLengths(xs1: List[_], xs2: List[_]): Int =
+ if (xs1.isEmpty) { if (xs2.isEmpty) 0 else -1 }
+ else if (xs2.isEmpty) 1
+ else compareLengths(xs1.tail, xs2.tail)
+
+ /** Again avoiding calling length, but the lengthCompare interface is clunky.
+ */
+ final def hasLength(xs: List[_], len: Int) = xs.lengthCompare(len) == 0
+
private val pendingSubTypes = new mutable.HashSet[SubTypePair]
private var basetypeRecursions: Int = 0
private val pendingBaseTypes = new mutable.HashSet[Type]
@@ -4443,7 +4460,7 @@ A type's typeSymbol should never be inspected directly.
|| // @M! normalize reduces higher-kinded case to PolyType's
((tp1.normalize.withoutAnnotations , tp2.normalize.withoutAnnotations) match {
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => // @assume tp1.isHigherKinded && tp2.isHigherKinded (as they were both normalized to PolyType)
- tparams1.length == tparams2.length && {
+ sameLength(tparams1, tparams2) && {
if (tparams1.head.owner.isMethod) { // fast-path: polymorphic method type -- type params cannot be captured
(tparams1 corresponds tparams2)((p1, p2) => p2.info.substSym(tparams2, tparams1) <:< p1.info) &&
res1 <:< res2.substSym(tparams2, tparams1)
@@ -4611,7 +4628,7 @@ A type's typeSymbol should never be inspected directly.
case mt1 @ MethodType(params1, res1) =>
val params2 = mt2.params
val res2 = mt2.resultType
- (params1.length == params2.length &&
+ (sameLength(params1, params2) &&
matchingParams(params1, params2, mt1.isJava, mt2.isJava) &&
(res1 <:< res2) &&
mt1.isImplicit == mt2.isImplicit)
@@ -4715,9 +4732,10 @@ A type's typeSymbol should never be inspected directly.
/** A function implementing `tp1' matches `tp2' */
final def matchesType(tp1: Type, tp2: Type, alwaysMatchSimple: Boolean): Boolean = {
- def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean =
- tparams1.length == tparams2.length &&
+ def matchesQuantified(tparams1: List[Symbol], tparams2: List[Symbol], res1: Type, res2: Type): Boolean = (
+ sameLength(tparams1, tparams2) &&
matchesType(res1, res2.substSym(tparams2, tparams1), alwaysMatchSimple)
+ )
def lastTry =
tp2 match {
case ExistentialType(_, res2) if alwaysMatchSimple =>
@@ -4733,7 +4751,7 @@ A type's typeSymbol should never be inspected directly.
case mt1 @ MethodType(params1, res1) =>
tp2 match {
case mt2 @ MethodType(params2, res2) =>
- params1.length == params2.length && // useful pre-screening optimization
+ sameLength(params1, params2) && // useful pre-screening optimization
matchingParams(params1, params2, mt1.isJava, mt2.isJava) &&
matchesType(res1, res2, alwaysMatchSimple) &&
mt1.isImplicit == mt2.isImplicit
@@ -5008,7 +5026,7 @@ A type's typeSymbol should never be inspected directly.
if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest
}
val ts0 = elimSub0(ts)
- if (ts0.length <= 1) ts0
+ if (ts0.isEmpty || ts0.tail.isEmpty) ts0
else {
val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.underlying))
if (ts1 eq ts0) ts0
@@ -5188,7 +5206,7 @@ A type's typeSymbol should never be inspected directly.
}
val res = lub0(ts)
if (printLubs) {
- indent = indent.substring(0, indent.length() - 2)
+ indent = indent dropRight 2
println(indent + "lub of " + ts + " is " + res)//debug
}
if (ts forall (_.isNotNull)) res.notNull else res
@@ -5438,7 +5456,7 @@ A type's typeSymbol should never be inspected directly.
*/
private def matchingBounds(tps: List[Type], tparams: List[Symbol]): List[List[Type]] =
tps map {
- case PolyType(tparams1, _) if (tparams1.length == tparams.length) =>
+ case PolyType(tparams1, _) if sameLength(tparams1, tparams) =>
tparams1 map (tparam => tparam.info.substSym(tparams1, tparams))
case _ =>
throw new NoCommonType(tps)
@@ -5451,7 +5469,7 @@ A type's typeSymbol should never be inspected directly.
*/
private def matchingInstTypes(tps: List[Type], tparams: List[Symbol]): List[Type] =
tps map {
- case PolyType(tparams1, restpe) if (tparams1.length == tparams.length) =>
+ case PolyType(tparams1, restpe) if sameLength(tparams1, tparams) =>
restpe.substSym(tparams1, tparams)
case _ =>
throw new NoCommonType(tps)
@@ -5513,7 +5531,7 @@ A type's typeSymbol should never be inspected directly.
log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs)
}
- if (hkargs.length != hkparams.length) {
+ if (!sameLength(hkargs, hkparams)) {
if(arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded
else {error = true; (List((arg, param)), Nil, Nil)} // shortcut: always set error, whether explainTypesOrNot
} else {
@@ -5603,7 +5621,7 @@ A type's typeSymbol should never be inspected directly.
Console.println(indent + tp1 + " " + op + " " + arg2 + "?" /* + "("+tp1.getClass+","+arg2.asInstanceOf[AnyRef].getClass+")"*/)
indent = indent + " "
val result = p(tp1, arg2)
- indent = indent.substring(0, indent.length() - 2)
+ indent = indent dropRight 2
Console.println(indent + result)
result
}
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index a12997226e..aa4044ad92 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -484,7 +484,7 @@ abstract class LambdaLift extends InfoTransform {
override def transformUnit(unit: CompilationUnit) {
computeFreeVars
atPhase(phase.next)(super.transformUnit(unit))
- assert(liftedDefs.size == 0, liftedDefs.keys.toList)
+ assert(liftedDefs.isEmpty, liftedDefs.keys.toList)
}
} // class LambdaLifter
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 9f07bd6b0d..6ed1a8f7b5 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -910,22 +910,23 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
field.info // ensure that nested objects are tranformed
// For checkinit consider normal value getters
// but for lazy values only take into account lazy getters
- (needsInitFlag(field) || field.hasFlag(LAZY) && field.isMethod) && !field.isDeferred
+ (needsInitFlag(field) || field.isLazy && field.isMethod) && !field.isDeferred
}
-
/**
* Return the number of bits used by superclass fields.
*/
def usedBits(clazz0: Symbol): Int = {
- def needsBitmap(field: Symbol) =
- field.owner != clazz0 &&
- fieldWithBitmap(field)
- val fs = for {
- cl <- clazz0.info.baseClasses.tail.filter(cl => !cl.isTrait && !cl.hasFlag(JAVA))
- field <- cl.info.decls.iterator.toList if needsBitmap(field) && !localBitmapField(field)
- } yield field
- fs.length
+ def needsBitmap(field: Symbol) = field.owner != clazz0 && fieldWithBitmap(field)
+ var bits = 0
+ for {
+ cl <- clazz0.info.baseClasses.tail
+ if !cl.isTrait && !cl.hasFlag(JAVA)
+ field <- cl.info.decls.iterator
+ if needsBitmap(field) && !localBitmapField(field)
+ } bits += 1
+
+ bits
}
/** Fill the map from fields to offset numbers.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index c695f70871..7bf1e8e0df 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -856,7 +856,7 @@ self: Analyzer =>
}
case RefinedType(parents, decls) =>
// refinement is not generated yet
- if (parents.length == 1) findManifest(parents.head)
+ if (hasLength(parents, 1)) findManifest(parents.head)
else if (full) manifestFactoryCall("intersectionType", tp, parents map (findSubManifest(_)): _*)
else mot(erasure.erasure.intersectionDominator(parents))
case ExistentialType(tparams, result) =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 26fb5148bf..107d3a07a7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -48,13 +48,15 @@ trait Infer {
}
def actualTypes(actuals: List[Type], nformals: Int): List[Type] =
- if (nformals == 1 && actuals.length != 1)
- List(if (actuals.length == 0) UnitClass.tpe else tupleType(actuals))
+ if (nformals == 1 && !hasLength(actuals, 1))
+ List(if (actuals.isEmpty) UnitClass.tpe else tupleType(actuals))
else actuals
- def actualArgs(pos: Position, actuals: List[Tree], nformals: Int): List[Tree] =
- if (nformals == 1 && actuals.length != 1 && actuals.length <= definitions.MaxTupleArity && !phase.erasedTypes)
- List(atPos(pos)(gen.mkTuple(actuals))) else actuals
+ def actualArgs(pos: Position, actuals: List[Tree], nformals: Int): List[Tree] = {
+ val inRange = nformals == 1 && !hasLength(actuals, 1) && actuals.lengthCompare(MaxTupleArity) <= 0
+ if (inRange && !phase.erasedTypes) List(atPos(pos)(gen.mkTuple(actuals)))
+ else actuals
+ }
/** A fresh type variable with given type parameter as origin.
*
@@ -319,18 +321,19 @@ trait Infer {
} else if (sym.isAbstractType) {
isPlausiblyCompatible(tp, pt.bounds.lo)
} else {
- val l = args.length - 1
- l == params.length &&
- sym == FunctionClass(l) && {
- var curargs = args
- var curparams = params
- while (curparams.nonEmpty) {
- if (!isPlausiblySubType(curargs.head, curparams.head.tpe))
+ val len = args.length - 1
+ hasLength(params, len) &&
+ sym == FunctionClass(len) && {
+ val ps = mt.paramTypes.iterator
+ val as = args.iterator
+ while (ps.hasNext && as.hasNext) {
+ if (!isPlausiblySubType(as.next, ps.next))
return false
- curargs = curargs.tail
- curparams = curparams.tail
}
- isPlausiblySubType(restpe, curargs.head)
+ ps.isEmpty && as.hasNext && {
+ val lastArg = as.next
+ as.isEmpty && isPlausiblySubType(restpe, lastArg)
+ }
}
}
case _ =>
@@ -736,7 +739,7 @@ trait Infer {
* tupled and n-ary methods, but thiws is something for a future major revision.
*/
def isUnitForVarArgs(args: List[AnyRef], params: List[Symbol]): Boolean =
- args.isEmpty && params.length == 2 && isVarArgsList(params)
+ args.isEmpty && hasLength(params, 2) && isVarArgsList(params)
/** Is there an instantiation of free type variables <code>undetparams</code>
* such that function type <code>ftpe</code> is applicable to
@@ -775,7 +778,7 @@ trait Infer {
case tp => tp
}, formals.length)
- argtpes0.length != tupleArgTpes.length &&
+ !sameLength(argtpes0, tupleArgTpes) &&
!isUnitForVarArgs(argtpes0, params) &&
isApplicable(undetparams, ftpe, tupleArgTpes, pt)
}
@@ -796,21 +799,21 @@ trait Infer {
}
// very similar logic to doTypedApply in typechecker
- if (argtpes0.length > formals.length) tryTupleApply
- else if (argtpes0.length == formals.length) {
+ val lencmp = compareLengths(argtpes0, formals)
+ if (lencmp > 0) tryTupleApply
+ else if (lencmp == 0) {
if (!argtpes0.exists(_.isInstanceOf[NamedType])) {
// fast track if no named arguments are used
typesCompatible(argtpes0)
- } else {
+ }
+ else {
// named arguments are used
val (argtpes1, argPos, namesOK) = checkNames(argtpes0, params)
- if (!namesOK) false
// when using named application, the vararg param has to be specified exactly once
- else if (!isIdentity(argPos) && (formals.length != params.length)) false
- else {
- // nb. arguments and names are OK, check if types are compatible
+ ( namesOK && (isIdentity(argPos) || sameLength(formals, params)) &&
+ // nb. arguments and names are OK, check if types are compatible
typesCompatible(reorderArgs(argtpes1, argPos))
- }
+ )
}
} else {
// not enough arguments, check if applicable using defaults
@@ -1582,16 +1585,17 @@ trait Infer {
// if there are multiple, drop those that use a default
// (keep those that use vararg / tupling conversion)
val applicable =
- if (allApplicable.length <= 1) allApplicable
+ if (allApplicable.lengthCompare(1) <= 0) allApplicable
else allApplicable filter (alt => {
val mtypes = followApply(alt.tpe) match {
- case OverloadedType(_, alts) =>
- // for functional values, the `apply' method might be overloaded
- alts map (_.tpe)
- case t => List(t)
+ // for functional values, the `apply' method might be overloaded
+ case OverloadedType(_, alts) => alts map (_.tpe)
+ case t => List(t)
}
- mtypes.exists(t => t.params.length < argtpes.length || // tupling (*)
- hasExactlyNumParams(t, argtpes.length)) // same nb or vararg
+ mtypes exists (t =>
+ compareLengths(t.params, argtpes) < 0 || // tupling (*)
+ hasExactlyNumParams(t, argtpes.length) // same nb or vararg
+ )
// (*) more arguments than parameters, but still applicable: tuplig conversion works.
// todo: should not return "false" when paramTypes = (Unit) no argument is given
// (tupling would work)
@@ -1659,44 +1663,43 @@ trait Infer {
* @param tree ...
* @param nparams ...
*/
- def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Unit = tree.tpe match {
- case OverloadedType(pre, alts) =>
- val sym0 = tree.symbol filter { alt => alt.typeParams.length == argtypes.length }
- if (sym0 == NoSymbol) {
- error(
- tree.pos,
- if (alts exists (alt => alt.typeParams.length > 0))
- "wrong number of type parameters for " + treeSymTypeMsg(tree)
- else treeSymTypeMsg(tree) + " does not take type parameters")
- return
- }
- if (sym0.isOverloaded) {
- val sym = sym0 filter { alt => isWithinBounds(pre, alt.owner, alt.typeParams, argtypes) }
+ def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Unit = {
+ val OverloadedType(pre, alts) = tree.tpe
+ val sym0 = tree.symbol filter (alt => sameLength(alt.typeParams, argtypes))
+ def fail(msg: String): Unit = error(tree.pos, msg)
+
+ if (sym0 == NoSymbol) return fail(
+ if (alts exists (_.typeParams.nonEmpty))
+ "wrong number of type parameters for " + treeSymTypeMsg(tree)
+ else treeSymTypeMsg(tree) + " does not take type parameters"
+ )
+
+ val (resSym, resTpe) = {
+ if (!sym0.isOverloaded)
+ (sym0, pre.memberType(sym0))
+ else {
+ val sym = sym0 filter (alt => isWithinBounds(pre, alt.owner, alt.typeParams, argtypes))
if (sym == NoSymbol) {
- if (!(argtypes exists (_.isErroneous))) {
- error(
- tree.pos,
- "type arguments " + argtypes.mkString("[", ",", "]") +
- " conform to the bounds of none of the overloaded alternatives of\n "+sym0+
- ": "+sym0.info)
- return
- }
+ if (argtypes forall (x => !x.isErroneous)) fail(
+ "type arguments " + argtypes.mkString("[", ",", "]") +
+ " conform to the bounds of none of the overloaded alternatives of\n "+sym0+
+ ": "+sym0.info
+ )
+ return
}
- if (sym.isOverloaded) {
- val tparams = new AsSeenFromMap(pre, sym.alternatives.head.owner).mapOver(
- sym.alternatives.head.typeParams)
- val bounds = tparams map (_.tpeHK) // see e.g., #1236
- val tpe =
- PolyType(tparams,
- OverloadedType(AntiPolyType(pre, bounds), sym.alternatives))
- sym.setInfo(tpe)
- tree.setSymbol(sym).setType(tpe)
- } else {
- tree.setSymbol(sym).setType(pre.memberType(sym))
+ else if (sym.isOverloaded) {
+ val xs = sym.alternatives
+ val tparams = new AsSeenFromMap(pre, xs.head.owner) mapOver xs.head.typeParams
+ val bounds = tparams map (_.tpeHK) // see e.g., #1236
+ val tpe = PolyType(tparams, OverloadedType(AntiPolyType(pre, bounds), xs))
+
+ (sym setInfo tpe, tpe)
}
- } else {
- tree.setSymbol(sym0).setType(pre.memberType(sym0))
+ else (sym, pre.memberType(sym))
}
+ }
+ // Side effects tree with symbol and type
+ tree setSymbol resSym setType resTpe
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 80b264821a..7066e57ba9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -179,7 +179,7 @@ trait Unapplies extends ast.TreeDSL
case _ => nme.unapply
}
val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), paramName, classType(cdef, tparams), EmptyTree))
- val ifNull = if (constrParamss(cdef).head.size == 0) FALSE else REF(NoneModule)
+ val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule)
val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef.symbol) }, ifNull)(Ident(paramName))
atPos(cdef.pos.focus)(