diff options
Diffstat (limited to 'src')
14 files changed, 110 insertions, 72 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 6e07e6b04b..0cdef9e79a 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -404,6 +404,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val JavaSerializableClass = requiredClass[java.io.Serializable] modifyInfo fixupAsAnyTrait lazy val ComparableClass = requiredClass[java.lang.Comparable[_]] modifyInfo fixupAsAnyTrait lazy val JavaCloneableClass = requiredClass[java.lang.Cloneable] + lazy val JavaNumberClass = requiredClass[java.lang.Number] lazy val RemoteInterfaceClass = requiredClass[java.rmi.Remote] lazy val RemoteExceptionClass = requiredClass[java.rmi.RemoteException] diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 71795a02aa..019e887c4e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -257,11 +257,23 @@ trait Members { var succ = bb do { succ = nextBlock(succ); - bb.removeLastInstruction - succ.toList foreach { i => bb.emit(i, i.pos) } - code.removeBlock(succ) + val lastInstr = bb.lastInstruction + /* Ticket SI-5672 + * Besides removing the control-flow instruction at the end of `bb` (usually a JUMP), we have to pop any values it pushes. + * Examples: + * `SWITCH` consisting of just the default case, or + * `CJUMP(targetBlock, targetBlock, _, _)` ie where success and failure targets coincide (this one consumes two stack values). + */ + val oldTKs = lastInstr.consumedTypes + assert(lastInstr.consumed == oldTKs.size, "Someone forgot to override consumedTypes() in " + lastInstr) + + bb.removeLastInstruction + for(tk <- oldTKs.reverse) { bb.emit(DROP(tk), lastInstr.pos) } + succ.toList foreach { i => bb.emit(i, i.pos) } + code.removeBlock(succ) + exh foreach { e => e.covered = e.covered - succ } + nextBlock -= bb - exh foreach { e => e.covered = e.covered - succ } } while (nextBlock.isDefinedAt(succ)) bb.close } else diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 576cc72f82..3179fc5c56 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -436,6 +436,8 @@ trait Opcodes { self: ICodes => override def consumed = 1 override def produced = 0 + override val consumedTypes = List(INT) + def flatTagsCount: Int = { var acc = 0; var rest = tags; while(rest.nonEmpty) { acc += rest.head.length; rest = rest.tail }; acc } // a one-liner } @@ -470,6 +472,8 @@ trait Opcodes { self: ICodes => override def consumed = 2 override def produced = 0 + + override val consumedTypes = List(kind, kind) } /** This class represents a CZJUMP instruction @@ -489,6 +493,8 @@ trait Opcodes { self: ICodes => override def consumed = 1 override def produced = 0 + + override val consumedTypes = List(kind) } @@ -499,6 +505,8 @@ trait Opcodes { self: ICodes => case class RETURN(kind: TypeKind) extends Instruction { override def consumed = if (kind == UNIT) 0 else 1 override def produced = 0 + + // TODO override val consumedTypes = List(kind) } /** This class represents a THROW instruction diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala index f8fffdc726..8ed13e0da2 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Index.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Index.scala @@ -44,7 +44,7 @@ class Index(universe: doc.Universe, index: doc.Index) extends HtmlPage { </div> { browser } <div id="content" class="ui-layout-center"> - <iframe id="template" src={ relativeLinkTo{List("package.html")} }/> + <iframe id="template" name="template" src={ relativeLinkTo{List("package.html")} }/> </div> </body> diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index eb3a1ffb5b..affa9cd63b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -690,34 +690,44 @@ trait ContextErrors { setError(tree) } - def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = { + // side-effect on the tree, break the overloaded type cycle in infer + @inline + private def setErrorOnLastTry(lastTry: Boolean, tree: Tree) = if (lastTry) setError(tree) + + def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type, lastTry: Boolean) = { issueNormalTypeError(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) // since inferMethodAlternative modifies the state of the tree // we have to set the type of tree to ErrorType only in the very last - // fallback action that is done in the inference (tracking it manually is error prone). + // fallback action that is done in the inference. // This avoids entering infinite loop in doTypeApply. - if (implicitly[Context].reportErrors) setError(tree) + setErrorOnLastTry(lastTry, tree) } def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol, - firstCompeting: Symbol, argtpes: List[Type], pt: Type) = { - val msg0 = - "argument types " + argtpes.mkString("(", ",", ")") + - (if (pt == WildcardType) "" else " and expected result type " + pt) - val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, msg0) - // discover last attempt in a similar way as for NoBestMethodAlternativeError - if (implicitly[Context].ambiguousErrors) setError(tree) - issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg)) + firstCompeting: Symbol, argtpes: List[Type], pt: Type, lastTry: Boolean) = { + + if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) { + val msg0 = + "argument types " + argtpes.mkString("(", ",", ")") + + (if (pt == WildcardType) "" else " and expected result type " + pt) + val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, msg0) + issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg)) + setErrorOnLastTry(lastTry, tree) + } else setError(tree) // do not even try further attempts because they should all fail + // even if this is not the last attempt (because of the SO's possibility on the horizon) + } - def NoBestExprAlternativeError(tree: Tree, pt: Type) = + def NoBestExprAlternativeError(tree: Tree, pt: Type, lastTry: Boolean) = { issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(tree.symbol.tpe, pt, isPossiblyMissingArgs(tree.symbol.tpe, pt)))) + setErrorOnLastTry(lastTry, tree) + } - def AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type) = { + def AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type, lastTry: Boolean) = { val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, "expected type " + pt) - setError(tree) issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(tree, pos, msg)) + setErrorOnLastTry(lastTry, tree) } // checkBounds diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 0924789948..f4f081252f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -438,8 +438,8 @@ trait Contexts { self: Analyzer => def enclosingContextChain: List[Context] = this :: outer.enclosingContextChain - override def toString = "Context(%s@%s unit=%s scope=%s errors=%b)".format( - owner.fullName, tree.shortClass, unit, scope.##, hasErrors + override def toString = "Context(%s@%s unit=%s scope=%s errors=%b, reportErrors=%b, throwErrors=%b)".format( + owner.fullName, tree.shortClass, unit, scope.##, hasErrors, reportErrors, throwErrors ) /** Is `sub` a subclass of `base` or a companion object of such a subclass? */ @@ -598,16 +598,16 @@ trait Contexts { self: Analyzer => * it is accessible, and if it is imported there is not already a local symbol * with the same names. Local symbols override imported ones. This fixes #2866. */ - private def isQualifyingImplicit(sym: Symbol, pre: Type, imported: Boolean) = + private def isQualifyingImplicit(name: Name, sym: Symbol, pre: Type, imported: Boolean) = sym.isImplicit && isAccessible(sym, pre) && !(imported && { - val e = scope.lookupEntry(sym.name) + val e = scope.lookupEntry(name) (e ne null) && (e.owner == scope) }) private def collectImplicits(syms: List[Symbol], pre: Type, imported: Boolean = false): List[ImplicitInfo] = - for (sym <- syms if isQualifyingImplicit(sym, pre, imported)) yield + for (sym <- syms if isQualifyingImplicit(sym.name, sym, pre, imported)) yield new ImplicitInfo(sym.name, pre, sym) private def collectImplicitImports(imp: ImportInfo): List[ImplicitInfo] = { @@ -621,7 +621,7 @@ trait Contexts { self: Analyzer => var impls = collect(sels1) filter (info => info.name != from) if (to != nme.WILDCARD) { for (sym <- imp.importedSymbol(to).alternatives) - if (isQualifyingImplicit(sym, pre, imported = true)) + if (isQualifyingImplicit(to, sym, pre, imported = true)) impls = new ImplicitInfo(to, pre, sym) :: impls } impls diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 8f025336bb..a671b8d6b5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -554,7 +554,11 @@ trait Implicits { val itree = atPos(pos.focus) { if (info.pre == NoPrefix) Ident(info.name) - else Select(gen.mkAttributedQualifier(info.pre), info.name) + else { + // SI-2405 Not info.name, which might be an aliased import + val implicitMemberName = info.sym.name + Select(gen.mkAttributedQualifier(info.pre), implicitMemberName) + } } printTyping("typedImplicit1 %s, pt=%s, from implicit %s:%s".format( typeDebug.ptTree(itree), wildPt, info.name, info.tpe) @@ -929,7 +933,7 @@ trait Implicits { } case None => if (pre.isStable) { - val companion = sym.companionModule + val companion = companionSymbolOf(sym, context) companion.moduleClass match { case mc: ModuleClassSymbol => val infos = diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 1c1adee343..839cdee301 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1449,10 +1449,10 @@ trait Infer { * If no alternative matches `pt`, take the parameterless one anyway. */ def inferExprAlternative(tree: Tree, pt: Type) = tree.tpe match { - case OverloadedType(pre, alts) => tryTwice { - val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) - val secondTry = alts0.isEmpty - val alts1 = if (secondTry) alts else alts0 + case OverloadedType(pre, alts) => tryTwice { isSecondTry => + val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) + val noAlternatives = alts0.isEmpty + val alts1 = if (noAlternatives) alts else alts0 //println("trying "+alts1+(alts1 map (_.tpe))+(alts1 map (_.locationString))+" for "+pt) def improves(sym1: Symbol, sym2: Symbol): Boolean = @@ -1480,10 +1480,10 @@ trait Infer { } } // todo: missing test case - NoBestExprAlternativeError(tree, pt) + NoBestExprAlternativeError(tree, pt, isSecondTry) } else if (!competing.isEmpty) { - if (secondTry) { NoBestExprAlternativeError(tree, pt); setError(tree) } - else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt) + if (noAlternatives) NoBestExprAlternativeError(tree, pt, isSecondTry) + else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt, isSecondTry) } else { // val applicable = alts1 filter (alt => // global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) @@ -1562,10 +1562,10 @@ trait Infer { * assignment expression. */ def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], - argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match { + argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false, lastInferAttempt: Boolean = true): Unit = tree.tpe match { case OverloadedType(pre, alts) => val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 - tryTwice { + tryTwice { isSecondTry => debuglog("infer method alt "+ tree.symbol +" with alternatives "+ (alts map pre.memberType) +", argtpes = "+ argtpes +", pt = "+ pt) @@ -1587,13 +1587,10 @@ trait Infer { if (improves(alt, best)) alt else best) val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) if (best == NoSymbol) { - if (pt == WildcardType) NoBestMethodAlternativeError(tree, argtpes, pt) - else inferMethodAlternative(tree, undetparams, argtpes, WildcardType) + if (pt == WildcardType) NoBestMethodAlternativeError(tree, argtpes, pt, isSecondTry && lastInferAttempt) + else inferMethodAlternative(tree, undetparams, argtpes, WildcardType, lastInferAttempt = isSecondTry) } else if (!competing.isEmpty) { - if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) - AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt) - else setError(tree) - () + AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt, isSecondTry && lastInferAttempt) } else { // checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) @@ -1607,29 +1604,28 @@ trait Infer { * * @param infer ... */ - def tryTwice(infer: => Unit): Unit = { + def tryTwice(infer: Boolean => Unit): Unit = { if (context.implicitsEnabled) { val saved = context.state var fallback = false context.setBufferErrors() - val res = try { - context.withImplicitsDisabled(infer) + try { + context.withImplicitsDisabled(infer(false)) if (context.hasErrors) { fallback = true context.restoreState(saved) context.flushBuffer() - infer + infer(true) } } catch { case ex: CyclicReference => throw ex case ex: TypeError => // recoverable cyclic references context.restoreState(saved) - if (!fallback) infer else () + if (!fallback) infer(true) else () } context.restoreState(saved) - res } - else infer + else infer(true) } /** Assign <code>tree</code> the type of all polymorphic alternatives diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 88e464a1f4..d1f319311e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -482,6 +482,10 @@ trait NamesDefaults { self: Analyzer => try typer.silent { tpr => val res = tpr.typed(arg, subst(paramtpe)) // better warning for SI-5044: if `silent` was not actually silent give a hint to the user + // [H]: the reason why `silent` is not silent is because the cyclic reference exception is + // thrown in a context completely different from `context` here. The exception happens while + // completing the type, and TypeCompleter is created/run with a non-silent Namer `context` + // and there is at the moment no way to connect the two unless we go through some global state. if (errsBefore < reporter.ERROR.count) WarnAfterNonSilentRecursiveInference(param, arg)(context) res diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 18529a061b..80d40011ad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -2516,7 +2516,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL // TODO: if patterns allow switch but the type of the scrutinee doesn't, cast (type-test) the scrutinee to the corresponding switchable type and switch on the result if (regularSwitchMaker.switchableTpe(scrutSym.tpe)) { val caseDefsWithDefault = regularSwitchMaker(cases map {c => (scrutSym, c)}, pt) - if (caseDefsWithDefault.length <= 2) None // not worth emitting a switch... also, the optimizer has trouble digesting tiny switches, apparently, so let's be nice and not generate them + if (caseDefsWithDefault isEmpty) None // not worth emitting a switch. else { // match on scrutSym -- converted to an int if necessary -- not on scrut directly (to avoid duplicating scrut) val scrutToInt: Tree = diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 4e578e3f0d..3373878beb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1084,8 +1084,16 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R def isEitherNullable = (NullClass.tpe <:< receiver.info) || (NullClass.tpe <:< actual.info) def isBoolean(s: Symbol) = unboxedValueClass(s) == BooleanClass def isUnit(s: Symbol) = unboxedValueClass(s) == UnitClass - def isNumeric(s: Symbol) = isNumericValueClass(unboxedValueClass(s)) || (s isSubClass ScalaNumberClass) - def isSpecial(s: Symbol) = isPrimitiveValueClass(unboxedValueClass(s)) || (s isSubClass ScalaNumberClass) || isMaybeValue(s) + def isNumeric(s: Symbol) = isNumericValueClass(unboxedValueClass(s)) || isAnyNumber(s) + def isScalaNumber(s: Symbol) = s isSubClass ScalaNumberClass + // test is behind a platform guard + def isJavaNumber(s: Symbol) = !forMSIL && (s isSubClass JavaNumberClass) + // includes java.lang.Number if appropriate [SI-5779] + def isAnyNumber(s: Symbol) = isScalaNumber(s) || isJavaNumber(s) + def isMaybeAnyValue(s: Symbol) = isPrimitiveValueClass(unboxedValueClass(s)) || isMaybeValue(s) + // used to short-circuit unrelatedTypes check if both sides are special + def isSpecial(s: Symbol) = isMaybeAnyValue(s) || isAnyNumber(s) + // unused def possibleNumericCount = onSyms(_ filter (x => isNumeric(x) || isMaybeValue(x)) size) val nullCount = onSyms(_ filter (_ == NullClass) size) @@ -1155,7 +1163,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R if (isCaseEquals) { def thisCase = receiver.info.member(nme.equals_).owner actual.info.baseClasses.find(_.isCase) match { - case Some(p) if (p != thisCase) => nonSensible("case class ", false) + case Some(p) if p != thisCase => nonSensible("case class ", false) case None => // stronger message on (Some(1) == None) //if (receiver.isCase && receiver.isEffectivelyFinal && !(receiver isSubClass actual)) nonSensiblyNeq() diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2ad9cba935..349bd1912b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2510,10 +2510,7 @@ trait Typers extends Modes with Adaptations with Taggings { namer.enterSyms(stats) // need to delay rest of typedRefinement to avoid cyclic reference errors unit.toCheck += { () => - // go to next outer context which is not silent, see #3614 - var c = context - while (c.bufferErrors) c = c.outer - val stats1 = newTyper(c).typedStats(stats, NoSymbol) + val stats1 = typedStats(stats, NoSymbol) for (stat <- stats1 if stat.isDef) { val member = stat.symbol if (!(context.owner.ancestors forall diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index ee6d4d1d22..4070174902 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -50,6 +50,10 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { protected def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) + /** The initial size of the hash table. + */ + def initialSize: Int = 32 + private def initialCapacity = capacity(initialSize) protected def randomSeed = seedGenerator.get.nextInt() @@ -361,10 +365,6 @@ private[collection] object FlatHashTable { def defaultLoadFactor: Int = 450 final def loadFactorDenum = 1000 - /** The initial size of the hash table. - */ - def initialSize: Int = 32 - def sizeForThreshold(size: Int, _loadFactor: Int) = math.max(32, (size.toLong * loadFactorDenum / _loadFactor).toInt) def newThreshold(_loadFactor: Int, size: Int) = { diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index a2f78dbde9..c307e6dcab 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -56,7 +56,15 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU protected def tableSizeSeed = Integer.bitCount(table.length - 1) - protected def initialSize: Int = HashTable.initialSize + /** The initial size of the hash table. + */ + protected def initialSize: Int = 16 + + /** The initial threshold. + */ + private def initialThreshold(_loadFactor: Int): Int = newThreshold(_loadFactor, initialCapacity) + + private def initialCapacity = capacity(initialSize) private def lastPopulatedIndex = { var idx = table.length - 1 @@ -354,16 +362,6 @@ private[collection] object HashTable { private[collection] final def defaultLoadFactor: Int = 750 // corresponds to 75% private[collection] final def loadFactorDenum = 1000; - /** The initial size of the hash table. - */ - private[collection] final def initialSize: Int = 16 - - /** The initial threshold. - */ - private[collection] final def initialThreshold(_loadFactor: Int): Int = newThreshold(_loadFactor, initialCapacity) - - private[collection] final def initialCapacity = capacity(initialSize) - private[collection] final def newThreshold(_loadFactor: Int, size: Int) = ((size.toLong * _loadFactor) / loadFactorDenum).toInt private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = ((thr.toLong * loadFactorDenum) / _loadFactor).toInt |