From 3bfd81869ccffd0657a1b82eb483e0f26a283a46 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 20 Dec 2010 23:34:20 +0000 Subject: 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. --- src/compiler/scala/tools/nsc/InterpreterLoop.scala | 2 +- .../tools/nsc/backend/WorklistAlgorithm.scala | 4 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 5 +- .../tools/nsc/backend/icode/Linearizers.scala | 4 +- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 4 +- .../nsc/backend/opt/DeadCodeElimination.scala | 10 +- .../tools/nsc/matching/ParallelMatching.scala | 6 +- src/compiler/scala/tools/nsc/symtab/Types.scala | 94 ++++++++------ .../scala/tools/nsc/transform/LambdaLift.scala | 2 +- src/compiler/scala/tools/nsc/transform/Mixin.scala | 21 ++-- .../scala/tools/nsc/typechecker/Implicits.scala | 2 +- .../scala/tools/nsc/typechecker/Infer.scala | 135 +++++++++++---------- .../scala/tools/nsc/typechecker/Unapplies.scala | 2 +- src/library/scala/collection/MapLike.scala | 3 +- src/library/scala/collection/SeqLike.scala | 5 +- src/library/scala/collection/generic/Sizing.scala | 4 +- src/library/scala/collection/mutable/Builder.scala | 2 +- 17 files changed, 162 insertions(+), 143 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 undetparams * such that function type ftpe 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)( diff --git a/src/library/scala/collection/MapLike.scala b/src/library/scala/collection/MapLike.scala index 2d2eb5c104..67ca1273c3 100644 --- a/src/library/scala/collection/MapLike.scala +++ b/src/library/scala/collection/MapLike.scala @@ -10,9 +10,8 @@ package scala.collection import generic._ -import mutable.{Builder, StringBuilder, MapBuilder} +import mutable.{ Builder, MapBuilder } import annotation.migration -import PartialFunction._ /** A template trait for maps, which associate keys with values. * diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 6d849cadc9..68adc13c14 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -839,7 +839,8 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * sorted according to the ordering `ord`. */ def sorted[B >: A](implicit ord: Ordering[B]): Repr = { - val arr = new ArraySeq[A](this.length) + val len = this.length + val arr = new ArraySeq[A](len) var i = 0 for (x <- this) { arr(i) = x @@ -847,7 +848,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => } java.util.Arrays.sort(arr.array, ord.asInstanceOf[Ordering[Object]]) val b = newBuilder - b.sizeHint(this) + b.sizeHint(len) for (x <- arr) b += x b.result } diff --git a/src/library/scala/collection/generic/Sizing.scala b/src/library/scala/collection/generic/Sizing.scala index bf801302ae..17181dc9dd 100644 --- a/src/library/scala/collection/generic/Sizing.scala +++ b/src/library/scala/collection/generic/Sizing.scala @@ -1,9 +1,7 @@ package scala.collection.generic - - /** A trait for objects which have a size. */ trait Sizing { def size: Int -} \ No newline at end of file +} diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala index 701e39e36f..a2bac43ed2 100644 --- a/src/library/scala/collection/mutable/Builder.scala +++ b/src/library/scala/collection/mutable/Builder.scala @@ -54,7 +54,7 @@ trait Builder[-Elem, +To] extends Growable[Elem] { /** Gives a hint that one expects the `result` of this builder * to have the same size as the given collection, plus some delta. This will * provide a hint only if the collection is known to have a cheap - * `size` method. Currently this is assumed ot be the case if and only if + * `size` method. Currently this is assumed to be the case if and only if * the collection is of type `IndexedSeqLike`. * Some builder classes * will optimize their representation based on the hint. However, -- cgit v1.2.3