diff options
Diffstat (limited to 'src')
76 files changed, 1035 insertions, 673 deletions
diff --git a/src/compiler/scala/reflect/macros/contexts/Parsers.scala b/src/compiler/scala/reflect/macros/contexts/Parsers.scala index f4584f3627..cc3f01e53b 100644 --- a/src/compiler/scala/reflect/macros/contexts/Parsers.scala +++ b/src/compiler/scala/reflect/macros/contexts/Parsers.scala @@ -16,8 +16,9 @@ trait Parsers { val tree = gen.mkTreeOrBlock(parser.parseStatsOrPackages()) sreporter.infos.foreach { case sreporter.Info(pos, msg, sreporter.ERROR) => throw ParseException(pos, msg) + case _ => } tree } finally global.reporter = oldReporter } -}
\ No newline at end of file +} diff --git a/src/compiler/scala/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/reflect/quasiquotes/Parsers.scala index 6972c4070c..c695f438a4 100644 --- a/src/compiler/scala/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/reflect/quasiquotes/Parsers.scala @@ -56,6 +56,10 @@ trait Parsers { self: Quasiquotes => override implicit lazy val fresh: FreshNameCreator = new FreshNameCreator(nme.QUASIQUOTE_PREFIX) + // Do not check for tuple arity. The placeholders can support arbitrary tuple sizes. + override def makeSafeTupleTerm(trees: List[Tree], offset: Offset): Tree = treeBuilder.makeTupleTerm(trees) + override def makeSafeTupleType(trees: List[Tree], offset: Offset): Tree = treeBuilder.makeTupleType(trees) + override val treeBuilder = new ParserTreeBuilder { override implicit def fresh: FreshNameCreator = parser.fresh diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 1d96b940ae..831a0412cd 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -774,7 +774,58 @@ self => @inline final def caseSeparated[T](part: => T): List[T] = tokenSeparated(CASE, sepFirst = true, part) def readAnnots(part: => Tree): List[Tree] = tokenSeparated(AT, sepFirst = true, part) -/* --------- OPERAND/OPERATOR STACK --------------------------------------- */ + /** Create a tuple type Tree. If the arity is not supported, a syntax error is emitted. */ + def makeSafeTupleType(elems: List[Tree], offset: Offset) = { + if (checkTupleSize(elems, offset)) makeTupleType(elems) + else makeTupleType(Nil) // create a dummy node; makeTupleType(elems) would fail + } + + /** Create a tuple term Tree. If the arity is not supported, a syntax error is emitted. */ + def makeSafeTupleTerm(elems: List[Tree], offset: Offset) = { + checkTupleSize(elems, offset) + makeTupleTerm(elems) + } + + private[this] def checkTupleSize(elems: List[Tree], offset: Offset): Boolean = + if (elems.lengthCompare(definitions.MaxTupleArity) > 0) { + syntaxError(offset, "too many elements for tuple: "+elems.length+", allowed: "+definitions.MaxTupleArity, skipIt = false) + false + } else true + + /** Strip the artifitial `Parens` node to create a tuple term Tree. */ + def stripParens(t: Tree) = t match { + case Parens(ts) => atPos(t.pos) { makeSafeTupleTerm(ts, t.pos.point) } + case _ => t + } + + /** Create tree representing (unencoded) binary operation expression or pattern. */ + def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = { + require(isExpr || targs.isEmpty || targs.exists(_.isErroneous), s"Incompatible args to makeBinop: !isExpr but targs=$targs") + + def mkSelection(t: Tree) = { + def sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode)) + if (targs.isEmpty) sel else atPos(left.pos)(TypeApply(sel, targs)) + } + def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args + val arguments = right match { + case Parens(args) => mkNamed(args) + case _ => List(right) + } + if (isExpr) { + if (treeInfo.isLeftAssoc(op)) { + Apply(mkSelection(left), arguments) + } else { + val x = freshTermName() + Block( + List(ValDef(Modifiers(symtab.Flags.SYNTHETIC | symtab.Flags.ARTIFACT), x, TypeTree(), stripParens(left))), + Apply(mkSelection(right), List(Ident(x)))) + } + } else { + Apply(Ident(op.encode), stripParens(left) :: arguments) + } + } + + /* --------- OPERAND/OPERATOR STACK --------------------------------------- */ /** Modes for infix types. */ object InfixMode extends Enumeration { @@ -878,7 +929,7 @@ self => atPos(start, in.skipToken()) { makeFunctionTypeTree(ts, typ()) } else { ts foreach checkNotByNameOrVarargs - val tuple = atPos(start) { makeTupleType(ts) } + val tuple = atPos(start) { makeSafeTupleType(ts, start) } infixTypeRest( compoundTypeRest( annotTypeRest( @@ -945,7 +996,7 @@ self => def simpleType(): Tree = { val start = in.offset simpleTypeRest(in.token match { - case LPAREN => atPos(start)(makeTupleType(inParens(types()))) + case LPAREN => atPos(start)(makeSafeTupleType(inParens(types()), start)) case USCORE => wildcardType(in.skipToken()) case _ => path(thisOK = false, typeOK = true) match { diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 6b564197a1..473a40f42a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -42,44 +42,12 @@ abstract class TreeBuilder { def makeTupleType(elems: List[Tree]) = gen.mkTupleType(elems) - def stripParens(t: Tree) = t match { - case Parens(ts) => atPos(t.pos) { makeTupleTerm(ts) } - case _ => t - } - def makeAnnotated(t: Tree, annot: Tree): Tree = atPos(annot.pos union t.pos)(Annotated(annot, t)) def makeSelfDef(name: TermName, tpt: Tree): ValDef = ValDef(Modifiers(PRIVATE), name, tpt, EmptyTree) - /** Create tree representing (unencoded) binary operation expression or pattern. */ - def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = { - require(isExpr || targs.isEmpty || targs.exists(_.isErroneous), s"Incompatible args to makeBinop: !isExpr but targs=$targs") - - def mkSelection(t: Tree) = { - def sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode)) - if (targs.isEmpty) sel else atPos(left.pos)(TypeApply(sel, targs)) - } - def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args - val arguments = right match { - case Parens(args) => mkNamed(args) - case _ => List(right) - } - if (isExpr) { - if (treeInfo.isLeftAssoc(op)) { - Apply(mkSelection(left), arguments) - } else { - val x = freshTermName() - Block( - List(ValDef(Modifiers(SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))), - Apply(mkSelection(right), List(Ident(x)))) - } - } else { - Apply(Ident(op.encode), stripParens(left) :: arguments) - } - } - /** Tree for `od op`, start is start0 if od.pos is borked. */ def makePostfixSelect(start0: Int, end: Int, od: Tree, op: Name): Tree = { val start = if (od.pos.isDefined) od.pos.start else start0 diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala index 4a10756468..328a8187c8 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala @@ -40,7 +40,7 @@ abstract class BCodeIdiomatic extends SubComponent { if (emitStackMapFrame) asm.ClassWriter.COMPUTE_FRAMES else 0 ) - val StringBuilderClassName = "scala/collection/mutable/StringBuilder" + lazy val JavaStringBuilderClassName = jlStringBuilderRef.internalName val EMPTY_STRING_ARRAY = Array.empty[String] val EMPTY_INT_ARRAY = Array.empty[Int] @@ -184,10 +184,10 @@ abstract class BCodeIdiomatic extends SubComponent { * can-multi-thread */ final def genStartConcat(pos: Position): Unit = { - jmethod.visitTypeInsn(Opcodes.NEW, StringBuilderClassName) + jmethod.visitTypeInsn(Opcodes.NEW, JavaStringBuilderClassName) jmethod.visitInsn(Opcodes.DUP) invokespecial( - StringBuilderClassName, + JavaStringBuilderClassName, INSTANCE_CONSTRUCTOR_NAME, "()V", pos @@ -198,21 +198,23 @@ abstract class BCodeIdiomatic extends SubComponent { * can-multi-thread */ final def genStringConcat(el: BType, pos: Position): Unit = { - - val jtype = - if (el.isArray || el.isClass) ObjectRef - else el + val jtype = el match { + case ct: ClassBType if ct.isSubtypeOf(StringRef).get => StringRef + case ct: ClassBType if ct.isSubtypeOf(jlStringBufferRef).get => jlStringBufferRef + case ct: ClassBType if ct.isSubtypeOf(jlCharSequenceRef).get => jlCharSequenceRef + case rt: RefBType => ObjectRef + case pt: PrimitiveBType => pt // Currently this ends up being boxed in erasure + } val bt = MethodBType(List(jtype), jlStringBuilderRef) - - invokevirtual(StringBuilderClassName, "append", bt.descriptor, pos) + invokevirtual(JavaStringBuilderClassName, "append", bt.descriptor, pos) } /* * can-multi-thread */ final def genEndConcat(pos: Position): Unit = { - invokevirtual(StringBuilderClassName, "toString", "()Ljava/lang/String;", pos) + invokevirtual(JavaStringBuilderClassName, "toString", "()Ljava/lang/String;", pos) } /* diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala index 0e98bddeb1..3617f3d863 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala @@ -97,7 +97,9 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) { lazy val ObjectRef : ClassBType = classBTypeFromSymbol(ObjectClass) lazy val StringRef : ClassBType = classBTypeFromSymbol(StringClass) lazy val PredefRef : ClassBType = classBTypeFromSymbol(PredefModule.moduleClass) - lazy val jlStringBuilderRef : ClassBType = classBTypeFromSymbol(StringBuilderClass) + lazy val jlStringBuilderRef : ClassBType = classBTypeFromSymbol(JavaStringBuilderClass) + lazy val jlStringBufferRef : ClassBType = classBTypeFromSymbol(JavaStringBufferClass) + lazy val jlCharSequenceRef : ClassBType = classBTypeFromSymbol(JavaCharSequenceClass) lazy val jlThrowableRef : ClassBType = classBTypeFromSymbol(ThrowableClass) lazy val jlCloneableRef : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable lazy val jiSerializableRef : ClassBType = classBTypeFromSymbol(JavaSerializableClass) // java/io/Serializable @@ -374,6 +376,8 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: def StringRef : ClassBType = _coreBTypes.StringRef def PredefRef : ClassBType = _coreBTypes.PredefRef def jlStringBuilderRef : ClassBType = _coreBTypes.jlStringBuilderRef + def jlStringBufferRef : ClassBType = _coreBTypes.jlStringBufferRef + def jlCharSequenceRef : ClassBType = _coreBTypes.jlCharSequenceRef def jlThrowableRef : ClassBType = _coreBTypes.jlThrowableRef def jlCloneableRef : ClassBType = _coreBTypes.jlCloneableRef def jiSerializableRef : ClassBType = _coreBTypes.jiSerializableRef diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala index 4ecaf17a10..16fe2e5cff 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BoxUnbox.scala @@ -21,7 +21,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { import backendUtils._ /** - * Eliminate box-unbox paris within `method`. Such appear commonly after closure elimination: + * Eliminate box-unbox pairs within `method`. Such appear commonly after closure elimination: * * def t2 = { * val f = (b: Byte, i: Int) => i + b // no specialized variant for this function type @@ -767,7 +767,7 @@ class BoxUnbox[BT <: BTypes](val btypes: BT) { private def isSpecializedTupleClass(tupleClass: InternalName) = specializedTupleClassR.pattern.matcher(tupleClass).matches private val specializedTupleGetterR = "_[12]\\$mc[IJDCZ]\\$sp".r - private def isSpecializedTupleGetter(mi: MethodInsnNode) = specializedTupleGetterR.pattern.matcher(mi.name)matches + private def isSpecializedTupleGetter(mi: MethodInsnNode) = specializedTupleGetterR.pattern.matcher(mi.name).matches private val tupleGetterR = "_\\d\\d?".r private def isTupleGetter(mi: MethodInsnNode) = tupleGetterR.pattern.matcher(mi.name).matches diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala index ff36f36589..9a90c53d3e 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala @@ -125,7 +125,7 @@ object BytecodeUtils { } def sameTargetExecutableInstruction(a: JumpInsnNode, b: JumpInsnNode): Boolean = { - // Compare next executable instead of the the labels. Identifies a, b as the same target: + // Compare next executable instead of the labels. Identifies a, b as the same target: // LabelNode(a) // LabelNode(b) // Instr diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala index 039e6a6d03..b8547e1dc6 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala @@ -75,10 +75,10 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) { def rewriteClosureApplyInvocations(): Unit = { // sort all closure invocations to rewrite to ensure bytecode stability - val toRewrite = new java.util.TreeMap[ClosureInstantiation, mutable.ArrayBuffer[(MethodInsnNode, Int)]](closureInitOrdering) + val toRewrite = mutable.TreeMap.empty[ClosureInstantiation, mutable.ArrayBuffer[(MethodInsnNode, Int)]](closureInitOrdering) def addRewrite(init: ClosureInstantiation, invocation: MethodInsnNode, stackHeight: Int): Unit = { - if (!toRewrite.containsKey(init)) toRewrite.put(init, mutable.ArrayBuffer.empty[(MethodInsnNode, Int)]) - toRewrite.get(init) += ((invocation, stackHeight)) + val callsites = toRewrite.getOrElseUpdate(init, mutable.ArrayBuffer.empty[(MethodInsnNode, Int)]) + callsites += ((invocation, stackHeight)) } // For each closure instantiation find callsites of the closure and add them to the toRewrite @@ -113,9 +113,7 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) { case _ => } - for (entry <- toRewrite.entrySet.iterator().asScala) { - val closureInit = entry.getKey - val invocations = entry.getValue + for ((closureInit, invocations) <- toRewrite) { // Local variables that hold the captured values and the closure invocation arguments. val (localsForCapturedValues, argumentLocalsList) = localsForClosureRewrite(closureInit) for ((invocation, stackHeight) <- invocations) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala index c1fdb7eb59..f486bb0cb9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala @@ -771,154 +771,173 @@ object LocalOptImpls { // A set of all exception handlers that guard the current instruction, required for simplifyGotoReturn var activeHandlers = Set.empty[TryCatchBlockNode] - // Instructions that need to be removed. simplifyBranchOverGoto returns an instruction to be - // removed. It cannot remove it itself because the instruction may be the successor of the current - // instruction of the iterator, which is not supported in ASM. - var instructionsToRemove = Set.empty[AbstractInsnNode] + val jumpInsns = mutable.LinkedHashMap.empty[JumpInsnNode, Boolean] - val iterator = method.instructions.iterator() - while (iterator.hasNext) { - val instruction = iterator.next() + for (insn <- method.instructions.iterator().asScala) insn match { + case l: LabelNode => + activeHandlers ++= allHandlers.filter(_.start == l) + activeHandlers = activeHandlers.filter(_.end != l) - instruction match { - case l: LabelNode => - activeHandlers ++= allHandlers.filter(_.start == l) - activeHandlers = activeHandlers.filter(_.end != l) - case _ => + case ji: JumpInsnNode => + jumpInsns(ji) = activeHandlers.nonEmpty + + case _ => + } + + var _jumpTargets: Set[AbstractInsnNode] = null + def jumpTargets = { + if (_jumpTargets == null) { + _jumpTargets = jumpInsns.keysIterator.map(_.label).toSet } + _jumpTargets + } - if (instructionsToRemove(instruction)) { - iterator.remove() - instructionsToRemove -= instruction - } else if (isJumpNonJsr(instruction)) { // fast path - all of the below only treat jumps - var jumpRemoved = simplifyThenElseSameTarget(method, instruction) + def removeJumpFromMap(jump: JumpInsnNode) = { + jumpInsns.remove(jump) + _jumpTargets = null + } - if (!jumpRemoved) { - changed = collapseJumpChains(instruction) || changed - jumpRemoved = removeJumpToSuccessor(method, instruction) + def replaceJumpByPop(jump: JumpInsnNode) = { + removeJumpAndAdjustStack(method, jump) + removeJumpFromMap(jump) + } - if (!jumpRemoved) { - val staleGoto = simplifyBranchOverGoto(method, instruction) - instructionsToRemove ++= staleGoto - changed ||= staleGoto.nonEmpty - changed = simplifyGotoReturn(method, instruction, inTryBlock = activeHandlers.nonEmpty) || changed - } + /** + * Removes a conditional jump if it is followed by a GOTO to the same destination. + * + * CondJump l; [nops]; GOTO l; [...] + * POP*; [nops]; GOTO l; [...] + * + * Introduces 1 or 2 POP instructions, depending on the number of values consumed by the CondJump. + */ + def simplifyThenElseSameTarget(insn: AbstractInsnNode): Boolean = insn match { + case ConditionalJump(jump) => + nextExecutableInstruction(insn) match { + case Some(Goto(elseJump)) if sameTargetExecutableInstruction(jump, elseJump) => + replaceJumpByPop(jump) + true + + case _ => false } - changed ||= jumpRemoved - } + + case _ => false } - assert(instructionsToRemove.isEmpty, "some optimization required removing a previously traversed instruction. add `instructionsToRemove.foreach(method.instructions.remove)`") - changed - } - /** - * Removes a conditional jump if it is followed by a GOTO to the same destination. - * - * CondJump l; [nops]; GOTO l; [...] - * POP*; [nops]; GOTO l; [...] - * - * Introduces 1 or 2 POP instructions, depending on the number of values consumed by the CondJump. - */ - private def simplifyThenElseSameTarget(method: MethodNode, instruction: AbstractInsnNode): Boolean = instruction match { - case ConditionalJump(jump) => - nextExecutableInstruction(instruction) match { - case Some(Goto(elseJump)) if sameTargetExecutableInstruction(jump, elseJump) => - removeJumpAndAdjustStack(method, jump) + /** + * Replace jumps to a sequence of GOTO instructions by a jump to the final destination. + * + * Jump l; [any ops]; l: GOTO m; [any ops]; m: GOTO n; [any ops]; n: NotGOTO; [...] + * => Jump n; [rest unchanged] + * + * If there's a loop of GOTOs, the initial jump is replaced by one of the labels in the loop. + */ + def collapseJumpChains(insn: AbstractInsnNode): Boolean = insn match { + case JumpNonJsr(jump) => + val target = finalJumpTarget(jump) + if (jump.label == target) false else { + jump.label = target + _jumpTargets = null true + } - case _ => false - } - case _ => false - } + case _ => false + } - /** - * Replace jumps to a sequence of GOTO instructions by a jump to the final destination. - * - * Jump l; [any ops]; l: GOTO m; [any ops]; m: GOTO n; [any ops]; n: NotGOTO; [...] - * => Jump n; [rest unchanged] - * - * If there's a loop of GOTOs, the initial jump is replaced by one of the labels in the loop. - */ - private def collapseJumpChains(instruction: AbstractInsnNode): Boolean = instruction match { - case JumpNonJsr(jump) => - val target = finalJumpTarget(jump) - if (jump.label == target) false else { - jump.label = target + /** + * Eliminates unnecessary jump instructions + * + * Jump l; [nops]; l: [...] + * => POP*; [nops]; l: [...] + * + * Introduces 0, 1 or 2 POP instructions, depending on the number of values consumed by the Jump. + */ + def removeJumpToSuccessor(insn: AbstractInsnNode): Boolean = insn match { + case JumpNonJsr(jump) if nextExecutableInstruction(jump, alsoKeep = Set(jump.label)) contains jump.label => + replaceJumpByPop(jump) true - } - case _ => false - } + case _ => false + } - /** - * Eliminates unnecessary jump instructions - * - * Jump l; [nops]; l: [...] - * => POP*; [nops]; l: [...] - * - * Introduces 0, 1 or 2 POP instructions, depending on the number of values consumed by the Jump. - */ - private def removeJumpToSuccessor(method: MethodNode, instruction: AbstractInsnNode) = instruction match { - case JumpNonJsr(jump) if nextExecutableInstruction(jump, alsoKeep = Set(jump.label)) == Some(jump.label) => - removeJumpAndAdjustStack(method, jump) - true - case _ => false - } + /** + * If the "else" part of a conditional branch is a simple GOTO, negates the conditional branch + * and eliminates the GOTO. + * + * CondJump l; [nops, no jump targets]; GOTO m; [nops]; l: [...] + * => NegatedCondJump m; [nops, no jump targets]; [nops]; l: [...] + * + * Note that no jump targets are allowed in the first [nops] section. Otherwise, there could + * be some other jump to the GOTO, and eliminating it would change behavior. + */ + def simplifyBranchOverGoto(insn: AbstractInsnNode, inTryBlock: Boolean): Boolean = insn match { + case ConditionalJump(jump) => + // don't skip over jump targets, see doc comment + nextExecutableInstruction(jump, alsoKeep = jumpTargets) match { + case Some(Goto(goto)) => + if (nextExecutableInstruction(goto, alsoKeep = Set(jump.label)) contains jump.label) { + val newJump = new JumpInsnNode(negateJumpOpcode(jump.getOpcode), goto.label) + method.instructions.set(jump, newJump) + removeJumpFromMap(jump) + jumpInsns(newJump) = inTryBlock + replaceJumpByPop(goto) + true + } else false + + case _ => false + } + case _ => false + } - /** - * If the "else" part of a conditional branch is a simple GOTO, negates the conditional branch - * and eliminates the GOTO. - * - * CondJump l; [nops, no labels]; GOTO m; [nops]; l: [...] - * => NegatedCondJump m; [nops, no labels]; [nops]; l: [...] - * - * Note that no label definitions are allowed in the first [nops] section. Otherwise, there could - * be some other jump to the GOTO, and eliminating it would change behavior. - * - * For technical reasons, we cannot remove the GOTO here (*).Instead this method returns an Option - * containing the GOTO that needs to be eliminated. - * - * (*) The ASM instruction iterator (used in the caller [[simplifyJumps]]) has an undefined - * behavior if the successor of the current instruction is removed, which may be the case here - */ - private def simplifyBranchOverGoto(method: MethodNode, instruction: AbstractInsnNode): Option[JumpInsnNode] = instruction match { - case ConditionalJump(jump) => - // don't skip over labels, see doc comment - nextExecutableInstructionOrLabel(jump) match { - case Some(Goto(goto)) => - if (nextExecutableInstruction(goto, alsoKeep = Set(jump.label)) == Some(jump.label)) { - val newJump = new JumpInsnNode(negateJumpOpcode(jump.getOpcode), goto.label) - method.instructions.set(jump, newJump) - Some(goto) - } else None - - case _ => None - } - case _ => None - } + /** + * Inlines xRETURN and ATHROW + * + * GOTO l; [any ops]; l: xRETURN/ATHROW + * => xRETURN/ATHROW; [any ops]; l: xRETURN/ATHROW + * + * inlining is only done if the GOTO instruction is not part of a try block, otherwise the + * rewrite might change the behavior. For xRETURN, the reason is that return instructions may throw + * an IllegalMonitorStateException, as described here: + * http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.return + */ + def simplifyGotoReturn(instruction: AbstractInsnNode, inTryBlock: Boolean): Boolean = !inTryBlock && (instruction match { + case Goto(jump) => + nextExecutableInstruction(jump.label) match { + case Some(target) => + if (isReturn(target) || target.getOpcode == ATHROW) { + method.instructions.set(jump, target.clone(null)) + removeJumpFromMap(jump) + true + } else false + + case _ => false + } + case _ => false + }) - /** - * Inlines xRETURN and ATHROW - * - * GOTO l; [any ops]; l: xRETURN/ATHROW - * => xRETURN/ATHROW; [any ops]; l: xRETURN/ATHROW - * - * inlining is only done if the GOTO instruction is not part of a try block, otherwise the - * rewrite might change the behavior. For xRETURN, the reason is that return instructions may throw - * an IllegalMonitorStateException, as described here: - * http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.return - */ - private def simplifyGotoReturn(method: MethodNode, instruction: AbstractInsnNode, inTryBlock: Boolean): Boolean = !inTryBlock && (instruction match { - case Goto(jump) => - nextExecutableInstruction(jump.label) match { - case Some(target) => - if (isReturn(target) || target.getOpcode == ATHROW) { - method.instructions.set(jump, target.clone(null)) - true - } else false + def run(): Boolean = { + var changed = false + + // `.toList` because we're modifying the map while iterating over it + for ((jumpInsn, inTryBlock) <- jumpInsns.toList if jumpInsns.contains(jumpInsn) && isJumpNonJsr(jumpInsn)) { + var jumpRemoved = simplifyThenElseSameTarget(jumpInsn) - case _ => false + if (!jumpRemoved) { + changed = collapseJumpChains(jumpInsn) || changed + jumpRemoved = removeJumpToSuccessor(jumpInsn) + + if (!jumpRemoved) { + changed = simplifyBranchOverGoto(jumpInsn, inTryBlock) || changed + changed = simplifyGotoReturn(jumpInsn, inTryBlock) || changed + } + } + + changed ||= jumpRemoved } - case _ => false - }) + + if (changed) run() + changed + } + + run() + } } diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 20e2c4346f..1446d22217 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -319,7 +319,7 @@ trait ScalaSettings extends AbsScalaSettings def YoptWarningNoInlineMissingBytecode = YoptWarnings.contains(YoptWarningsChoices.noInlineMissingBytecode) def YoptWarningNoInlineMissingScalaInlineInfoAttr = YoptWarnings.contains(YoptWarningsChoices.noInlineMissingScalaInlineInfoAttr) - val YoptTrace = StringSetting("-YoptTrace", "package/Class.method", "Trace the optimizer progress for a specific method.", "") + val YoptTrace = StringSetting("-Yopt-trace", "package/Class.method", "Trace the optimizer progress for a specific method.", "") private def removalIn212 = "This flag is scheduled for removal in 2.12. If you have a case where you need this flag then please report a bug." diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index d83cf68b38..9d02228ab5 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -244,7 +244,10 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { // These three lines are assembling Foo.bar$extension[T1, T2, ...]($this) // which leaves the actual argument application for extensionCall. - val sel = Select(gen.mkAttributedRef(companion), extensionMeth) + // SI-9542 We form the selection here from the thisType of the companion's owner. This is motivated + // by the test case, and is a valid way to construct the reference because we know that this + // method is also enclosed by that owner. + val sel = Select(gen.mkAttributedRef(companion.owner.thisType, companion), extensionMeth) val targs = origTpeParams map (_.tpeHK) val callPrefix = gen.mkMethodCall(sel, targs, This(origThis) :: Nil) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index f7a1f462b7..7cd05b56c3 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -651,7 +651,7 @@ abstract class UnCurry extends InfoTransform * This transformation erases the dependent method types by: * - Widening the formal parameter type to existentially abstract * over the prior parameters (using `packSymbols`). This transformation - * is performed in the the `InfoTransform`er [[scala.reflect.internal.transform.UnCurry]]. + * is performed in the `InfoTransform`er [[scala.reflect.internal.transform.UnCurry]]. * - Inserting casts in the method body to cast to the original, * precise type. * diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala index 1a4df9973e..4ae97ce281 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala @@ -542,7 +542,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { * * (0) A or B must be in the domain to draw any conclusions. * - * For example, knowing the the scrutinee is *not* true does not + * For example, knowing the scrutinee is *not* true does not * statically exclude it from being `X`, because that is an opaque * Boolean. * @@ -691,7 +691,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis { // if X is mutable. freshExistentialSubtype(t.tpe) } - else trees find (a => a.correspondsStructure(t)(sameValue)) match { + else trees find (a => equivalentTree(a, t)) match { case Some(orig) => debug.patmat("unique tp for tree: " + ((orig, orig.tpe))) orig.tpe diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index affbcf9ec8..ab3b25e76b 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -84,11 +84,15 @@ trait TreeAndTypeAnalysis extends Debugging { tp <:< tpImpliedNormalizedToAny } - // TODO: improve, e.g., for constants - def sameValue(a: Tree, b: Tree): Boolean = (a eq b) || ((a, b) match { - case (_ : Ident, _ : Ident) => a.symbol eq b.symbol - case _ => false - }) + def equivalentTree(a: Tree, b: Tree): Boolean = (a, b) match { + case (Select(qual1, _), Select(qual2, _)) => equivalentTree(qual1, qual2) && a.symbol == b.symbol + case (Ident(_), Ident(_)) => a.symbol == b.symbol + case (Literal(c1), Literal(c2)) => c1 == c2 + case (This(_), This(_)) => a.symbol == b.symbol + case (Apply(fun1, args1), Apply(fun2, args2)) => equivalentTree(fun1, fun2) && args1.corresponds(args2)(equivalentTree) + // Those are the only cases we need to handle in the pattern matcher + case _ => false + } trait CheckableTreeAndTypeAnalysis { val typer: Typer @@ -172,6 +176,8 @@ trait TreeAndTypeAnalysis extends Debugging { filterChildren(subclasses) }) } + case sym if sym.isCase => + List(List(tp)) case sym => debug.patmat("enum unsealed "+ ((tp, sym, sym.isSealed, isPrimitiveValueClass(sym)))) @@ -276,7 +282,7 @@ trait MatchApproximation extends TreeAndTypeAnalysis with ScalaLogic with MatchT // hashconsing trees (modulo value-equality) def unique(t: Tree, tpOverride: Type = NoType): Tree = - trees find (a => a.correspondsStructure(t)(sameValue)) match { + trees find (a => equivalentTree(a, t)) match { case Some(orig) => // debug.patmat("unique: "+ (t eq orig, orig)) orig diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index 96a20ea631..e12b8548a8 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -503,14 +503,26 @@ trait MatchTranslation { */ def treeMaker(binder: Symbol, binderKnownNonNull: Boolean, pos: Position): TreeMaker = { val paramAccessors = binder.constrParamAccessors + val numParams = paramAccessors.length + def paramAccessorAt(subPatIndex: Int) = paramAccessors(math.min(subPatIndex, numParams - 1)) // binders corresponding to mutable fields should be stored (SI-5158, SI-6070) // make an exception for classes under the scala package as they should be well-behaved, // to optimize matching on List + val hasRepeated = paramAccessors.lastOption match { + case Some(x) => definitions.isRepeated(x) + case _ => false + } val mutableBinders = ( if (!binder.info.typeSymbol.hasTransOwner(ScalaPackageClass) && - (paramAccessors exists (_.isMutable))) - subPatBinders.zipWithIndex.collect{ case (binder, idx) if paramAccessors(idx).isMutable => binder } - else Nil + (paramAccessors exists (x => x.isMutable || definitions.isRepeated(x)))) { + + subPatBinders.zipWithIndex.flatMap { + case (binder, idx) => + val param = paramAccessorAt(idx) + if (param.isMutable || (definitions.isRepeated(param) && !aligner.isStar)) binder :: Nil + else Nil + } + } else Nil ) // checks binder ne null before chaining to the next extractor diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index 18a63a6e53..c6e7f8fcda 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -101,7 +101,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { case class SubstOnlyTreeMaker(prevBinder: Symbol, nextBinder: Symbol) extends TreeMaker { val pos = NoPosition - val localSubstitution = Substitution(prevBinder, CODE.REF(nextBinder)) + val localSubstitution = Substitution(prevBinder, gen.mkAttributedStableRef(nextBinder)) def chainBefore(next: Tree)(casegen: Casegen): Tree = substitution(next) override def toString = "S"+ localSubstitution } @@ -118,7 +118,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { val res: Tree lazy val nextBinder = freshSym(pos, nextBinderTp) - lazy val localSubstitution = Substitution(List(prevBinder), List(CODE.REF(nextBinder))) + lazy val localSubstitution = Substitution(List(prevBinder), List(gen.mkAttributedStableRef(nextBinder))) def chainBefore(next: Tree)(casegen: Casegen): Tree = atPos(pos)(casegen.flatMapCond(cond, res, nextBinder, substitution(next))) @@ -485,7 +485,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { // NOTE: generate `patTree == patBinder`, since the extractor must be in control of the equals method (also, patBinder may be null) // equals need not be well-behaved, so don't intersect with pattern's (stabilized) type (unlike MaybeBoundTyped's accumType, where it's required) val cond = codegen._equals(patTree, prevBinder) - val res = CODE.REF(prevBinder) + val res = gen.mkAttributedStableRef(prevBinder) override def toString = "ET"+((prevBinder.name, patTree)) } diff --git a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala index 0574869714..9898cfd785 100644 --- a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala +++ b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala @@ -65,7 +65,7 @@ trait AnalyzerPlugins { self: Analyzer => * The hooks into `typeSig` allow analyzer plugins to add annotations to (or change the types * of) definition symbols. This cannot not be achieved by using `pluginsTyped`: this method * is only called during type checking, so changing the type of a symbol at this point is too - * late: references to the symbol might already be typed and therefore obtain the the original + * late: references to the symbol might already be typed and therefore obtain the original * type assigned during naming. * * @param defTree is the definition for which the type was computed. The different cases are diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala index a702b3cdf5..f90e61ff92 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala @@ -79,7 +79,7 @@ trait PatternTypers { // do not update the symbol if the tree's symbol's type does not define an unapply member // (e.g. since it's some method that returns an object with an unapply member) val fun = inPlaceAdHocOverloadingResolution(fun0)(hasUnapplyMember) - val caseClass = fun.tpe.typeSymbol.linkedClassOfClass + val caseClass = companionSymbolOf(fun.tpe.typeSymbol.sourceModule, context) val member = unapplyMember(fun.tpe) def resultType = (fun.tpe memberType member).finalResultType def isEmptyType = resultOfMatchingMethod(resultType, nme.isEmpty)() diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 3860cc252d..9261d6b851 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -88,17 +88,19 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans if (sym.hasAccessBoundary) "" + sym.privateWithin.name else "" ) - def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type): Boolean = (tp1.dealiasWiden, tp2.dealiasWiden) match { + def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type, isModuleOverride: Boolean): Boolean = (tp1.dealiasWiden, tp2.dealiasWiden) match { case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) => rtp1 <:< rtp2 case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) => rtp1 <:< rtp2 case (TypeRef(_, sym, _), _) if sym.isModuleClass => - overridesTypeInPrefix(NullaryMethodType(tp1), tp2, prefix) + overridesTypeInPrefix(NullaryMethodType(tp1), tp2, prefix, isModuleOverride) case _ => def classBoundAsSeen(tp: Type) = tp.typeSymbol.classBound.asSeenFrom(prefix, tp.typeSymbol.owner) - - (tp1 <:< tp2) || ( // object override check + (tp1 <:< tp2) || isModuleOverride && ( + // Object override check. This requires that both the overridden and the overriding member are object + // definitions. The overriding module type is allowed to replace the original one with the same name + // as long as it conform to the original non-singleton type. tp1.typeSymbol.isModuleClass && tp2.typeSymbol.isModuleClass && { val cb1 = classBoundAsSeen(tp1) val cb2 = classBoundAsSeen(tp2) @@ -520,7 +522,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } def checkOverrideTerm() { other.cookJavaRawInfo() // #2454 - if (!overridesTypeInPrefix(lowType, highType, rootType)) { // 8 + if (!overridesTypeInPrefix(lowType, highType, rootType, low.isModuleOrModuleClass && high.isModuleOrModuleClass)) { // 8 overrideTypeError() explainTypes(lowType, highType) } @@ -1152,11 +1154,13 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def toConstructor(pos: Position, tpe: Type): Tree = { val rtpe = tpe.finalResultType assert(rtpe.typeSymbol hasFlag CASE, tpe) - localTyper.typedOperator { + val tree = localTyper.typedOperator { atPos(pos) { Select(New(TypeTree(rtpe)), rtpe.typeSymbol.primaryConstructor) } } + checkUndesiredProperties(rtpe.typeSymbol, tree.pos) + tree } override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { @@ -1527,11 +1531,20 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans !tree.tpe.resultType.typeSymbol.primaryConstructor.isLessAccessibleThan(tree.symbol) if (doTransform) { + def loop(t: Tree): Unit = t match { + case Ident(_) => + checkUndesiredProperties(t.symbol, t.pos) + case Select(qual, _) => + checkUndesiredProperties(t.symbol, t.pos) + loop(qual) + case _ => + } tree foreach { case i@Ident(_) => enterReference(i.pos, i.symbol) // SI-5390 need to `enterReference` for `a` in `a.B()` case _ => } + loop(tree) toConstructor(tree.pos, tree.tpe) } else { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 84af9233e1..3a8edafd58 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1860,7 +1860,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper clazz.annotations.map(_.completeInfo()) if (templ.symbol == NoSymbol) templ setSymbol clazz.newLocalDummy(templ.pos) - val self1 = templ.self match { + val self1 = (templ.self: @unchecked) match { case vd @ ValDef(_, _, tpt, EmptyTree) => val tpt1 = checkNoEscaping.privates( clazz.thisSym, @@ -5421,6 +5421,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (!isPastTyper) signalDone(context.asInstanceOf[analyzer.Context], tree, result) + if (mode.inPatternMode && !mode.inPolyMode && result.isType) + PatternMustBeValue(result, pt) + result } @@ -5510,10 +5513,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // as a compromise, context.enrichmentEnabled tells adaptToMember to go ahead and enrich, // but arbitrary conversions (in adapt) are disabled // TODO: can we achieve the pattern matching bit of the string interpolation SIP without this? - typingInPattern(context.withImplicitsDisabledAllowEnrichment(typed(tree, PATTERNmode, pt))) match { - case tpt if tpt.isType => PatternMustBeValue(tpt, pt); tpt - case pat => pat - } + typingInPattern(context.withImplicitsDisabledAllowEnrichment(typed(tree, PATTERNmode, pt))) } /** Types a (fully parameterized) type tree */ diff --git a/src/intellij/scala-build.iml.SAMPLE b/src/intellij/scala-build.iml.SAMPLE new file mode 100644 index 0000000000..bf722e464f --- /dev/null +++ b/src/intellij/scala-build.iml.SAMPLE @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module external.linked.project.id="scalaz-build" external.linked.project.path="$MODULE_DIR$/../../project" external.root.project.path="$MODULE_DIR$/../.." external.system.id="SBT" sbt.imports="sbt._, Keys._, dsl._, _root_.com.typesafe.sbt.SbtPgp.autoImport._, _root_.sbt.plugins.IvyPlugin, _root_.sbt.plugins.JvmPlugin, _root_.sbt.plugins.CorePlugin, _root_.sbt.plugins.JUnitXmlReportPlugin, _root_.com.typesafe.sbt.SbtPgp" sbt.resolvers="https://repo1.maven.org/maven2/|maven|public, /Users/jason/.ivy2/cache|ivy|Local cache" type="SBT_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="false"> + <output url="file://$MODULE_DIR$/../../project/target/idea-classes" /> + <output-test url="file://$MODULE_DIR$/../../project/target/idea-test-classes" /> + <exclude-output /> + <content url="file://$MODULE_DIR$/../../project"> + <sourceFolder url="file://$MODULE_DIR$/../../project" isTestSource="false" /> + <excludeFolder url="file://$MODULE_DIR$/../../project/project/target" /> + <excludeFolder url="file://$MODULE_DIR$/../../project/target" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module-library"> + <library name="SBT: sbt-and-plugins"> + <CLASSES> + <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.commons/commons-lang3/jars/commons-lang3-3.3.2.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.pantsbuild/jarjar/jars/jarjar-1.6.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.ant/ant/jars/ant-1.9.6.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.ant/ant-launcher/jars/ant-launcher-1.9.6.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.ow2.asm/asm/jars/asm-5.0.4.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.ow2.asm/asm-commons/jars/asm-commons-5.0.4.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.ow2.asm/asm-tree/jars/asm-tree-5.0.4.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.maven/maven-plugin-api/jars/maven-plugin-api-3.3.3.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.maven/maven-model/jars/maven-model-3.3.3.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.codehaus.plexus/plexus-utils/jars/plexus-utils-3.0.20.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.apache.maven/maven-artifact/jars/maven-artifact-3.3.3.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.eclipse.sisu/org.eclipse.sisu.plexus/eclipse-plugins/org.eclipse.sisu.plexus-0.3.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/javax.enterprise/cdi-api/jars/cdi-api-1.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/javax.annotation/jsr250-api/jars/jsr250-api-1.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/javax.inject/javax.inject/jars/javax.inject-1.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.eclipse.sisu/org.eclipse.sisu.inject/eclipse-plugins/org.eclipse.sisu.inject-0.3.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.codehaus.plexus/plexus-component-annotations/jars/plexus-component-annotations-1.5.5.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.codehaus.plexus/plexus-classworlds/bundles/plexus-classworlds-2.5.2.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/biz.aQute.bnd/biz.aQute.bnd/jars/biz.aQute.bnd-2.4.1.jar!/" /> + <root url="jar://$USER_HOME$/.sbt/boot/scala-2.10.5/lib/scala-library.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/sbt/jars/sbt-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/main/jars/main-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/actions/jars/actions-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/classpath/jars/classpath-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.sbt/boot/scala-2.10.5/lib/scala-compiler.jar!/" /> + <root url="jar://$USER_HOME$/.sbt/boot/scala-2.10.5/lib/scala-reflect.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/interface/jars/interface-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/io/jars/io-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/control/jars/control-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/launcher-interface/jars/launcher-interface-1.0.0-M1.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/completion/jars/completion-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/collections/jars/collections-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/jline/jline/jars/jline-2.11.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/api/jars/api-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-integration/jars/compiler-integration-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/incremental-compiler/jars/incremental-compiler-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/logging/jars/logging-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/process/jars/process-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/relation/jars/relation-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compile/jars/compile-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/classfile/jars/classfile-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/persist/jars/persist-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-tools.sbinary/sbinary_2.10/jars/sbinary_2.10-0.4.2.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-ivy-integration/jars/compiler-ivy-integration-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/ivy/jars/ivy-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/cross/jars/cross-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt.ivy/ivy/jars/ivy-2.3.0-sbt-c5d1b95fdcc1e1007740ffbecf4eb07abc51ec93.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/com.jcraft/jsch/jars/jsch-0.1.46.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/serialization_2.10/jars/serialization_2.10-0.1.1.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang.modules/scala-pickling_2.10/jars/scala-pickling_2.10-0.10.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scalamacros/quasiquotes_2.10/jars/quasiquotes_2.10-2.0.1.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.json4s/json4s-core_2.10/jars/json4s-core_2.10-3.2.10.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.json4s/json4s-ast_2.10/jars/json4s-ast_2.10-3.2.10.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/com.thoughtworks.paranamer/paranamer/jars/paranamer-2.6.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.spire-math/jawn-parser_2.10/jars/jawn-parser_2.10-0.6.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.spire-math/json4s-support_2.10/jars/json4s-support_2.10-0.6.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/run/jars/run-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/task-system/jars/task-system-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/tasks/jars/tasks-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/tracking/jars/tracking-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/cache/jars/cache-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/testing/jars/testing-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-agent/jars/test-agent-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-interface/jars/test-interface-1.0.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/main-settings/jars/main-settings-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/apply-macro/jars/apply-macro-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/command/jars/command-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/logic/jars/logic-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-interface/jars/compiler-interface-bin-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/compiler-interface/jars/compiler-interface-src-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/precompiled-2_8_2/jars/compiler-interface-bin-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/precompiled-2_9_2/jars/compiler-interface-bin-0.13.9.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/precompiled-2_9_3/jars/compiler-interface-bin-0.13.9.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/main/srcs/main-0.13.9-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang/scala-library/srcs/scala-library-2.10.5-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang/scala-reflect/srcs/scala-reflect-2.10.5-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-lang/scala-compiler/srcs/scala-compiler-2.10.5-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/actions/srcs/actions-0.13.9-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/sbt/srcs/sbt-0.13.9-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/run/srcs/run-0.13.9-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/test-interface/srcs/test-interface-1.0-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/testing/srcs/testing-0.13.9-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/tasks/srcs/tasks-0.13.9-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/ivy/srcs/ivy-0.13.9-sources.jar!/" /> + <root url="jar://$USER_HOME$/.ivy2/cache/org.scala-sbt/completion/srcs/completion-0.13.9-sources.jar!/" /> + </SOURCES> + </library> + </orderEntry> + </component> +</module>
\ No newline at end of file diff --git a/src/intellij/scala.ipr.SAMPLE b/src/intellij/scala.ipr.SAMPLE index c4c6a2e44f..e88d6ef257 100644 --- a/src/intellij/scala.ipr.SAMPLE +++ b/src/intellij/scala.ipr.SAMPLE @@ -44,6 +44,7 @@ <module fileurl="file://$PROJECT_DIR$/reflect.iml" filepath="$PROJECT_DIR$/reflect.iml" /> <module fileurl="file://$PROJECT_DIR$/repl.iml" filepath="$PROJECT_DIR$/repl.iml" /> <module fileurl="file://$PROJECT_DIR$/scala.iml" filepath="$PROJECT_DIR$/scala.iml" /> + <module fileurl="file://$PROJECT_DIR$/scala-build.iml" filepath="$PROJECT_DIR$/scala-build.iml" /> <module fileurl="file://$PROJECT_DIR$/scaladoc.iml" filepath="$PROJECT_DIR$/scaladoc.iml" /> <module fileurl="file://$PROJECT_DIR$/scalap.iml" filepath="$PROJECT_DIR$/scalap.iml" /> <module fileurl="file://$PROJECT_DIR$/test.iml" filepath="$PROJECT_DIR$/test.iml" /> @@ -123,4 +124,4 @@ <SOURCES /> </library> </component> -</project>
\ No newline at end of file +</project> diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index d89e9d291d..7f3200b90a 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -486,6 +486,37 @@ object Array extends FallbackArrayBuilding { * @see [[http://www.scala-lang.org/files/archive/spec/2.11/ Scala Language Specification]], for in-depth information on the transformations the Scala compiler makes on Arrays (Sections 6.6 and 6.15 respectively.) * @see [[http://docs.scala-lang.org/sips/completed/scala-2-8-arrays.html "Scala 2.8 Arrays"]] the Scala Improvement Document detailing arrays since Scala 2.8. * @see [[http://docs.scala-lang.org/overviews/collections/arrays.html "The Scala 2.8 Collections' API"]] section on `Array` by Martin Odersky for more information. + * @hideImplicitConversion scala.Predef.booleanArrayOps + * @hideImplicitConversion scala.Predef.byteArrayOps + * @hideImplicitConversion scala.Predef.charArrayOps + * @hideImplicitConversion scala.Predef.doubleArrayOps + * @hideImplicitConversion scala.Predef.floatArrayOps + * @hideImplicitConversion scala.Predef.intArrayOps + * @hideImplicitConversion scala.Predef.longArrayOps + * @hideImplicitConversion scala.Predef.refArrayOps + * @hideImplicitConversion scala.Predef.shortArrayOps + * @hideImplicitConversion scala.Predef.unitArrayOps + * @hideImplicitConversion scala.Predef._booleanArrayOps + * @hideImplicitConversion scala.Predef._byteArrayOps + * @hideImplicitConversion scala.Predef._charArrayOps + * @hideImplicitConversion scala.Predef._doubleArrayOps + * @hideImplicitConversion scala.Predef._floatArrayOps + * @hideImplicitConversion scala.Predef._intArrayOps + * @hideImplicitConversion scala.Predef._longArrayOps + * @hideImplicitConversion scala.Predef._refArrayOps + * @hideImplicitConversion scala.Predef._shortArrayOps + * @hideImplicitConversion scala.Predef._unitArrayOps + * @hideImplicitConversion scala.LowPriorityImplicits.wrapRefArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapIntArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapDoubleArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapLongArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapFloatArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapCharArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapByteArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapShortArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapBooleanArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapUnitArray + * @hideImplicitConversion scala.LowPriorityImplicits.genericWrapArray * @define coll array * @define Coll `Array` * @define orderDependent diff --git a/src/library/scala/Byte.scala b/src/library/scala/Byte.scala index 413231c0d1..fb662911b3 100644 --- a/src/library/scala/Byte.scala +++ b/src/library/scala/Byte.scala @@ -79,8 +79,8 @@ final abstract class Byte private extends AnyVal { */ def >>>(x: Long): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 @@ -90,8 +90,8 @@ final abstract class Byte private extends AnyVal { */ def >>(x: Int): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 diff --git a/src/library/scala/Char.scala b/src/library/scala/Char.scala index ec2d48c181..9f06503569 100644 --- a/src/library/scala/Char.scala +++ b/src/library/scala/Char.scala @@ -79,8 +79,8 @@ final abstract class Char private extends AnyVal { */ def >>>(x: Long): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 @@ -90,8 +90,8 @@ final abstract class Char private extends AnyVal { */ def >>(x: Int): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 diff --git a/src/library/scala/Int.scala b/src/library/scala/Int.scala index 72e5ebf81b..3bd3775eba 100644 --- a/src/library/scala/Int.scala +++ b/src/library/scala/Int.scala @@ -79,8 +79,8 @@ final abstract class Int private extends AnyVal { */ def >>>(x: Long): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 @@ -90,8 +90,8 @@ final abstract class Int private extends AnyVal { */ def >>(x: Int): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 diff --git a/src/library/scala/Long.scala b/src/library/scala/Long.scala index 1bd0fe88b1..b27a66647f 100644 --- a/src/library/scala/Long.scala +++ b/src/library/scala/Long.scala @@ -79,8 +79,8 @@ final abstract class Long private extends AnyVal { */ def >>>(x: Long): Long /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 @@ -90,8 +90,8 @@ final abstract class Long private extends AnyVal { */ def >>(x: Int): Long /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 diff --git a/src/library/scala/Short.scala b/src/library/scala/Short.scala index 36b9ec4df9..2cbbf3cc59 100644 --- a/src/library/scala/Short.scala +++ b/src/library/scala/Short.scala @@ -79,8 +79,8 @@ final abstract class Short private extends AnyVal { */ def >>>(x: Long): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 @@ -90,8 +90,8 @@ final abstract class Short private extends AnyVal { */ def >>(x: Int): Int /** - * Returns this value bit-shifted left by the specified number of bits, - * filling in the right bits with the same value as the left-most bit of this. + * Returns this value bit-shifted right by the specified number of bits, + * filling in the left bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ * -21 >> 3 == -3 diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 17bb83e52e..518bba6b6d 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -10,7 +10,7 @@ package scala package collection import mutable.ArrayBuffer -import scala.annotation.migration +import scala.annotation.{tailrec, migration} import immutable.Stream /** The `Iterator` object provides various functions for creating specialized iterators. @@ -166,8 +166,10 @@ object Iterator { private[scala] final class ConcatIterator[+A](private[this] var current: Iterator[A], initial: Vector[() => Iterator[A]]) extends Iterator[A] { @deprecated def this(initial: Vector[() => Iterator[A]]) = this(Iterator.empty, initial) // for binary compatibility private[this] var queue: Vector[() => Iterator[A]] = initial + private[this] var currentHasNextChecked = false // Advance current to the next non-empty iterator // current is set to null when all iterators are exhausted + @tailrec private[this] def advance(): Boolean = { if (queue.isEmpty) { current = null @@ -176,20 +178,57 @@ object Iterator { else { current = queue.head() queue = queue.tail - current.hasNext || advance() + if (current.hasNext) { + currentHasNextChecked = true + true + } else advance() } } - def hasNext = (current ne null) && (current.hasNext || advance()) - def next() = if (hasNext) current.next() else Iterator.empty.next() + def hasNext = + if (currentHasNextChecked) true + else if (current eq null) false + else if (current.hasNext) { + currentHasNextChecked = true + true + } else advance() + def next() = + if (hasNext) { + currentHasNextChecked = false + current.next() + } else Iterator.empty.next() override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new ConcatIterator(current, queue :+ (() => that.toIterator)) } private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] { + private[this] var state = 0 // 0: lhs not checked, 1: lhs has next, 2: switched to rhs private[this] lazy val rhs: Iterator[A] = that.toIterator - def hasNext = lhs.hasNext || rhs.hasNext - def next() = if (lhs.hasNext) lhs.next() else rhs.next() + def hasNext = state match { + case 0 => + if (lhs.hasNext) { + state = 1 + true + } else { + state = 2 + rhs.hasNext + } + case 1 => true + case _ => rhs.hasNext + } + def next() = state match { + case 0 => + if (lhs.hasNext) lhs.next() + else { + state = 2 + rhs.next() + } + case 1 => + state = 0 + lhs.next() + case _ => + rhs.next() + } override def ++[B >: A](that: => GenTraversableOnce[B]) = new ConcatIterator(this, Vector(() => that.toIterator)) diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 875f6e1c02..86e86d4584 100644 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -52,7 +52,10 @@ import convert._ * - `scala.collection.Set` => `java.util.Set` * - `scala.collection.Map` => `java.util.Map` * - * @author Martin Odersky + * The following one way conversion is provided via `asScala`: + * + * - `java.util.Properties` => `scala.collection.mutable.Map` + * * @since 2.8.1 */ object JavaConverters extends DecorateAsJava with DecorateAsScala diff --git a/src/library/scala/collection/Searching.scala b/src/library/scala/collection/Searching.scala index b68124b3f8..25e8b5e253 100644 --- a/src/library/scala/collection/Searching.scala +++ b/src/library/scala/collection/Searching.scala @@ -36,12 +36,12 @@ object Searching { class SearchImpl[A, Repr](val coll: SeqLike[A, Repr]) { /** Search the sorted sequence for a specific element. If the sequence is an - * `IndexedSeq`, a binary search is used. Otherwise, a linear search is used. + * `IndexedSeqLike`, a binary search is used. Otherwise, a linear search is used. * * The sequence should be sorted with the same `Ordering` before calling; otherwise, * the results are undefined. * - * @see [[scala.collection.IndexedSeq]] + * @see [[scala.collection.IndexedSeqLike]] * @see [[scala.math.Ordering]] * @see [[scala.collection.SeqLike]], method `sorted` * @@ -54,18 +54,18 @@ object Searching { */ final def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult = coll match { - case _: IndexedSeq[A] => binarySearch(elem, 0, coll.length)(ord) + case _: IndexedSeqLike[A, Repr] => binarySearch(elem, 0, coll.length)(ord) case _ => linearSearch(coll.view, elem, 0)(ord) } /** Search within an interval in the sorted sequence for a specific element. If the - * sequence is an IndexedSeq, a binary search is used. Otherwise, a linear search + * sequence is an `IndexedSeqLike`, a binary search is used. Otherwise, a linear search * is used. * * The sequence should be sorted with the same `Ordering` before calling; otherwise, * the results are undefined. * - * @see [[scala.collection.IndexedSeq]] + * @see [[scala.collection.IndexedSeqLike]] * @see [[scala.math.Ordering]] * @see [[scala.collection.SeqLike]], method `sorted` * @@ -81,7 +81,7 @@ object Searching { final def search[B >: A](elem: B, from: Int, to: Int) (implicit ord: Ordering[B]): SearchResult = coll match { - case _: IndexedSeq[A] => binarySearch(elem, from, to)(ord) + case _: IndexedSeqLike[A, Repr] => binarySearch(elem, from, to)(ord) case _ => linearSearch(coll.view(from, to), elem, from)(ord) } diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index 6658b6feea..e6aa5da067 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -16,7 +16,7 @@ import WrapAsJava._ import scala.language.implicitConversions -/** A collection of decorators that allow to convert between +/** A collection of decorators that allow converting between * Scala and Java collections using `asScala` and `asJava` methods. * * The following conversions are supported via `asJava`, `asScala` @@ -38,8 +38,8 @@ import scala.language.implicitConversions * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala * assert(sl eq sl2) * }}} - * The following conversions also are supported, but the - * direction Scala to Java is done my a more specifically named method: + * The following conversions are also supported, but the + * direction from Scala to Java is done by the more specifically named methods: * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`. * * - `scala.collection.Iterable` <=> `java.util.Collection` @@ -53,10 +53,12 @@ import scala.language.implicitConversions * - `scala.collection.Set` => `java.util.Set` * - `scala.collection.Map` => `java.util.Map` * - * @author Martin Odersky + * The following one way conversion is provided via `asScala`: + * + * - `java.util.Properties` => `scala.collection.mutable.Map` + * * @since 2.8.1 */ - trait DecorateAsJava { /** * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala index a65e25ed6e..98b91f7c84 100644 --- a/src/library/scala/collection/immutable/ListSet.scala +++ b/src/library/scala/collection/immutable/ListSet.scala @@ -12,7 +12,7 @@ package immutable import generic._ import scala.annotation.tailrec -import mutable.Builder +import mutable.{Builder, ReusableBuilder} /** $factoryInfo * @define Coll immutable.ListSet @@ -32,8 +32,10 @@ object ListSet extends ImmutableSetFactory[ListSet] { * a time to a list backed set puts the "squared" in N^2. There is a * temporary space cost, but it's improbable a list backed set could * become large enough for this to matter given its pricy element lookup. + * + * This builder is reusable. */ - class ListSetBuilder[Elem](initial: ListSet[Elem]) extends Builder[Elem, ListSet[Elem]] { + class ListSetBuilder[Elem](initial: ListSet[Elem]) extends ReusableBuilder[Elem, ListSet[Elem]] { def this() = this(empty[Elem]) protected val elems = (new mutable.ListBuffer[Elem] ++= initial).reverse protected val seen = new mutable.HashSet[Elem] ++= initial diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index cd2d3f843b..539ae9c387 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -13,7 +13,7 @@ package immutable import scala.annotation.unchecked.uncheckedVariance import scala.compat.Platform import scala.collection.generic._ -import scala.collection.mutable.Builder +import scala.collection.mutable.{Builder, ReusableBuilder} import scala.collection.parallel.immutable.ParVector /** Companion object to the Vector class @@ -156,7 +156,7 @@ override def companion: GenericCompanion[Vector] = Vector override def take(n: Int): Vector[A] = { if (n <= 0) Vector.empty - else if (startIndex + n < endIndex) + else if (startIndex < endIndex - n) dropBack0(startIndex + n) else this @@ -165,7 +165,7 @@ override def companion: GenericCompanion[Vector] = Vector override def drop(n: Int): Vector[A] = { if (n <= 0) this - else if (startIndex + n < endIndex) + else if (startIndex < endIndex - n) dropFront0(startIndex + n) else Vector.empty @@ -704,8 +704,8 @@ extends AbstractIterator[A] } } - -final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A @uncheckedVariance] { +/** A class to build instances of `Vector`. This builder is reusable. */ +final class VectorBuilder[A]() extends ReusableBuilder[A,Vector[A]] with VectorPointer[A @uncheckedVariance] { // possible alternative: start with display0 = null, blockIndex = -32, lo = 32 // to avoid allocating initial array if the result will be empty anyways diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index af7600ad3d..2ed5bbea60 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -427,7 +427,11 @@ object AnyRefMap { def apply(): AnyRefMapBuilder[J, U] = new AnyRefMapBuilder[J, U] } - final class AnyRefMapBuilder[K <: AnyRef, V] extends Builder[(K, V), AnyRefMap[K, V]] { + /** A builder for instances of `AnyRefMap`. + * + * This builder can be reused to create multiple instances. + */ + final class AnyRefMapBuilder[K <: AnyRef, V] extends ReusableBuilder[(K, V), AnyRefMap[K, V]] { private[collection] var elems: AnyRefMap[K, V] = new AnyRefMap[K, V] def +=(entry: (K, V)): this.type = { elems += entry diff --git a/src/library/scala/collection/mutable/ArrayBuilder.scala b/src/library/scala/collection/mutable/ArrayBuilder.scala index ac78ab823b..549ffef565 100644 --- a/src/library/scala/collection/mutable/ArrayBuilder.scala +++ b/src/library/scala/collection/mutable/ArrayBuilder.scala @@ -18,7 +18,7 @@ import scala.reflect.ClassTag * * @tparam T the type of the elements for the builder. */ -abstract class ArrayBuilder[T] extends Builder[T, Array[T]] with Serializable +abstract class ArrayBuilder[T] extends ReusableBuilder[T, Array[T]] with Serializable /** A companion object for array builders. * @@ -49,6 +49,8 @@ object ArrayBuilder { /** A class for array builders for arrays of reference types. * + * This builder can be reused. + * * @tparam T type of elements for the array builder, subtype of `AnyRef` with a `ClassTag` context bound. */ @deprecatedInheritance("ArrayBuilder.ofRef is an internal implementation not intended for subclassing.", "2.11.0") @@ -98,12 +100,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -115,7 +118,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofRef" } - /** A class for array builders for arrays of `byte`s. */ + /** A class for array builders for arrays of `byte`s. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofByte is an internal implementation not intended for subclassing.", "2.11.0") class ofByte extends ArrayBuilder[Byte] { @@ -163,12 +166,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -180,7 +184,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofByte" } - /** A class for array builders for arrays of `short`s. */ + /** A class for array builders for arrays of `short`s. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofShort is an internal implementation not intended for subclassing.", "2.11.0") class ofShort extends ArrayBuilder[Short] { @@ -228,12 +232,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -245,7 +250,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofShort" } - /** A class for array builders for arrays of `char`s. */ + /** A class for array builders for arrays of `char`s. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofChar is an internal implementation not intended for subclassing.", "2.11.0") class ofChar extends ArrayBuilder[Char] { @@ -293,12 +298,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -310,7 +316,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofChar" } - /** A class for array builders for arrays of `int`s. */ + /** A class for array builders for arrays of `int`s. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofInt is an internal implementation not intended for subclassing.", "2.11.0") class ofInt extends ArrayBuilder[Int] { @@ -358,12 +364,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -375,7 +382,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofInt" } - /** A class for array builders for arrays of `long`s. */ + /** A class for array builders for arrays of `long`s. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofLong is an internal implementation not intended for subclassing.", "2.11.0") class ofLong extends ArrayBuilder[Long] { @@ -423,12 +430,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -440,7 +448,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofLong" } - /** A class for array builders for arrays of `float`s. */ + /** A class for array builders for arrays of `float`s. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofFloat is an internal implementation not intended for subclassing.", "2.11.0") class ofFloat extends ArrayBuilder[Float] { @@ -488,12 +496,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -505,7 +514,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofFloat" } - /** A class for array builders for arrays of `double`s. */ + /** A class for array builders for arrays of `double`s. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofDouble is an internal implementation not intended for subclassing.", "2.11.0") class ofDouble extends ArrayBuilder[Double] { @@ -553,12 +562,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -570,7 +580,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofDouble" } - /** A class for array builders for arrays of `boolean`s. */ + /** A class for array builders for arrays of `boolean`s. It can be reused. */ class ofBoolean extends ArrayBuilder[Boolean] { private var elems: Array[Boolean] = _ @@ -617,12 +627,13 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } @@ -634,65 +645,33 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofBoolean" } - /** A class for array builders for arrays of `Unit` type. */ + /** A class for array builders for arrays of `Unit` type. It can be reused. */ @deprecatedInheritance("ArrayBuilder.ofUnit is an internal implementation not intended for subclassing.", "2.11.0") class ofUnit extends ArrayBuilder[Unit] { - private var elems: Array[Unit] = _ - private var capacity: Int = 0 private var size: Int = 0 - private def mkArray(size: Int): Array[Unit] = { - val newelems = new Array[Unit](size) - if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) - newelems - } - - private def resize(size: Int) { - elems = mkArray(size) - capacity = size - } - - override def sizeHint(size: Int) { - if (capacity < size) resize(size) - } - - private def ensureSize(size: Int) { - if (capacity < size || capacity == 0) { - var newsize = if (capacity == 0) 16 else capacity * 2 - while (newsize < size) newsize *= 2 - resize(newsize) - } - } - def +=(elem: Unit): this.type = { - ensureSize(size + 1) - elems(size) = elem size += 1 this } - override def ++=(xs: TraversableOnce[Unit]): this.type = xs match { - case xs: WrappedArray.ofUnit => - ensureSize(this.size + xs.length) - Array.copy(xs.array, 0, elems, this.size, xs.length) - size += xs.length - this - case _ => - super.++=(xs) + override def ++=(xs: TraversableOnce[Unit]): this.type = { + size += xs.size + this } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems - else mkArray(size) + val ans = new Array[Unit](size) + var i = 0 + while (i < size) { ans(i) = (); i += 1 } + ans } override def equals(other: Any): Boolean = other match { - case x: ofUnit => (size == x.size) && (elems == x.elems) + case x: ofUnit => (size == x.size) case _ => false } diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala index 75560580cc..8d6a0ec69d 100644 --- a/src/library/scala/collection/mutable/Builder.scala +++ b/src/library/scala/collection/mutable/Builder.scala @@ -18,6 +18,14 @@ import generic._ * elements to the builder with `+=` and then converting to the required * collection type with `result`. * + * One cannot assume that a single `Builder` can build more than one + * instance of the desired collection. Particular subclasses may allow + * such behavior. Otherwise, `result` should be treated as a terminal + * operation: after it is called, no further methods should be called on + * the builder. Extend the [[collection.mutable.ReusableBuilder]] trait + * instead of `Builder` for builders that may be reused to build multiple + * instances. + * * @tparam Elem the type of elements that get added to the builder. * @tparam To the type of collection that it produced. * @@ -36,8 +44,10 @@ trait Builder[-Elem, +To] extends Growable[Elem] { */ def clear() - /** Produces a collection from the added elements. - * The builder's contents are undefined after this operation. + /** Produces a collection from the added elements. This is a terminal operation: + * the builder's contents are undefined after this operation, and no further + * methods should be called. + * * @return a collection containing the elements added to this builder. */ def result(): To @@ -112,6 +122,8 @@ trait Builder[-Elem, +To] extends Growable[Elem] { * @tparam NewTo the type of collection returned by `f`. * @return a new builder which is the same as the current builder except * that a transformation function is applied to this builder's result. + * + * @note The original builder should no longer be used after `mapResult` is called. */ def mapResult[NewTo](f: To => NewTo): Builder[Elem, NewTo] = new Builder[Elem, NewTo] with Proxy { diff --git a/src/library/scala/collection/mutable/GrowingBuilder.scala b/src/library/scala/collection/mutable/GrowingBuilder.scala index c4b5e546aa..27d554d98e 100644 --- a/src/library/scala/collection/mutable/GrowingBuilder.scala +++ b/src/library/scala/collection/mutable/GrowingBuilder.scala @@ -15,6 +15,8 @@ import generic._ /** The canonical builder for collections that are growable, i.e. that support an * efficient `+=` method which adds an element to the collection. * + * GrowableBuilders can produce only a single instance of the collection they are growing. + * * @author Paul Phillips * @version 2.8 * @since 2.8 @@ -25,6 +27,6 @@ import generic._ class GrowingBuilder[Elem, To <: Growable[Elem]](empty: To) extends Builder[Elem, To] { protected var elems: To = empty def +=(x: Elem): this.type = { elems += x; this } - def clear() { elems = empty } + def clear() { empty.clear } def result: To = elems } diff --git a/src/library/scala/collection/mutable/LazyBuilder.scala b/src/library/scala/collection/mutable/LazyBuilder.scala index ebee38b77f..f0a5e6971a 100644 --- a/src/library/scala/collection/mutable/LazyBuilder.scala +++ b/src/library/scala/collection/mutable/LazyBuilder.scala @@ -13,12 +13,14 @@ package mutable /** A builder that constructs its result lazily. Iterators or iterables to * be added to this builder with `++=` are not evaluated until `result` is called. * + * This builder can be reused. + * * @since 2.8 * * @tparam Elem type of the elements for this builder. * @tparam To type of the collection this builder builds. */ -abstract class LazyBuilder[Elem, +To] extends Builder[Elem, To] { +abstract class LazyBuilder[Elem, +To] extends ReusableBuilder[Elem, To] { /** The different segments of elements to be added to the builder, represented as iterators */ protected var parts = new ListBuffer[TraversableOnce[Elem]] def +=(x: Elem): this.type = { parts += List(x); this } diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index 0a483ceb86..02fcced3ac 100644 --- a/src/library/scala/collection/mutable/ListBuffer.scala +++ b/src/library/scala/collection/mutable/ListBuffer.scala @@ -46,7 +46,7 @@ final class ListBuffer[A] with Buffer[A] with GenericTraversableTemplate[A, ListBuffer] with BufferLike[A, ListBuffer[A]] - with Builder[A, List[A]] + with ReusableBuilder[A, List[A]] with SeqForwarder[A] with Serializable { @@ -297,6 +297,10 @@ final class ListBuffer[A] // Implementation of abstract method in Builder + /** Returns the accumulated `List`. + * + * This method may be called multiple times to obtain snapshots of the list in different stages of construction. + */ def result: List[A] = toList /** Converts this buffer to a list. Takes constant time. The buffer is diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala index f39a6ba634..ecbb1952af 100644 --- a/src/library/scala/collection/mutable/LongMap.scala +++ b/src/library/scala/collection/mutable/LongMap.scala @@ -519,7 +519,11 @@ object LongMap { def apply(): LongMapBuilder[U] = new LongMapBuilder[U] } - final class LongMapBuilder[V] extends Builder[(Long, V), LongMap[V]] { + /** A builder for instances of `LongMap`. + * + * This builder can be reused to create multiple instances. + */ + final class LongMapBuilder[V] extends ReusableBuilder[(Long, V), LongMap[V]] { private[collection] var elems: LongMap[V] = new LongMap[V] def +=(entry: (Long, V)): this.type = { elems += entry diff --git a/src/library/scala/collection/mutable/MapBuilder.scala b/src/library/scala/collection/mutable/MapBuilder.scala index a5a6b12ea9..cfc3079f41 100644 --- a/src/library/scala/collection/mutable/MapBuilder.scala +++ b/src/library/scala/collection/mutable/MapBuilder.scala @@ -23,7 +23,7 @@ package mutable * @since 2.8 */ class MapBuilder[A, B, Coll <: scala.collection.GenMap[A, B] with scala.collection.GenMapLike[A, B, Coll]](empty: Coll) -extends Builder[(A, B), Coll] { +extends ReusableBuilder[(A, B), Coll] { protected var elems: Coll = empty def +=(x: (A, B)): this.type = { elems = (elems + x).asInstanceOf[Coll] diff --git a/src/library/scala/collection/mutable/ReusableBuilder.scala b/src/library/scala/collection/mutable/ReusableBuilder.scala new file mode 100644 index 0000000000..caab3071b6 --- /dev/null +++ b/src/library/scala/collection/mutable/ReusableBuilder.scala @@ -0,0 +1,51 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + +package scala +package collection +package mutable + +import generic._ + +/** `ReusableBuilder` is a marker trait that indicates that a `Builder` + * can be reused to build more than one instance of a collection. In + * particular, calling `result` followed by `clear` will produce a + * collection and reset the builder to begin building a new collection + * of the same type. + * + * It is up to subclasses to implement this behavior, and to document any + * other behavior that varies from standard `ReusableBuilder` usage + * (e.g. operations being well-defined after a call to `result`, or allowing + * multiple calls to result to obtain different snapshots of a collection under + * construction). + * + * @tparam Elem the type of elements that get added to the builder. + * @tparam To the type of collection that it produced. + * + * @since 2.12 + */ +trait ReusableBuilder[-Elem, +To] extends Builder[Elem, To] { + /** Clears the contents of this builder. + * After execution of this method, the builder will contain no elements. + * + * If executed immediately after a call to `result`, this allows a new + * instance of the same type of collection to be built. + */ + override def clear(): Unit // Note: overriding for scaladoc only! + + /** Produces a collection from the added elements. + * + * After a call to `result`, the behavior of all other methods is undefined + * save for `clear`. If `clear` is called, then the builder is reset and + * may be used to build another instance. + * + * @return a collection containing the elements added to this builder. + */ + override def result(): To // Note: overriding for scaladoc only! +} diff --git a/src/library/scala/collection/mutable/SetBuilder.scala b/src/library/scala/collection/mutable/SetBuilder.scala index 01bfdc96ed..5d1e9ffc3a 100644 --- a/src/library/scala/collection/mutable/SetBuilder.scala +++ b/src/library/scala/collection/mutable/SetBuilder.scala @@ -17,7 +17,9 @@ package mutable * @param empty The empty element of the collection. * @since 2.8 */ -class SetBuilder[A, Coll <: scala.collection.Set[A] with scala.collection.SetLike[A, Coll]](empty: Coll) extends Builder[A, Coll] { +class SetBuilder[A, Coll <: scala.collection.Set[A] +with scala.collection.SetLike[A, Coll]](empty: Coll) +extends ReusableBuilder[A, Coll] { protected var elems: Coll = empty def +=(x: A): this.type = { elems = elems + x; this } def clear() { elems = empty } diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala index c56d40786e..b5b9498374 100644 --- a/src/library/scala/collection/mutable/StringBuilder.scala +++ b/src/library/scala/collection/mutable/StringBuilder.scala @@ -33,7 +33,7 @@ final class StringBuilder(private val underlying: JavaStringBuilder) with java.lang.CharSequence with IndexedSeq[Char] with StringLike[StringBuilder] - with Builder[Char, String] + with ReusableBuilder[Char, String] with Serializable { override protected[this] def thisCollection: StringBuilder = this @@ -435,7 +435,11 @@ final class StringBuilder(private val underlying: JavaStringBuilder) */ override def mkString = toString - /** Returns the result of this Builder (a String) + /** Returns the result of this Builder (a String). + * + * If this method is called multiple times, each call will result in a snapshot of the buffer at that point in time. + * In particular, a `StringBuilder` can be used to build multiple independent strings by emptying the buffer with `clear` + * after each call to `result`. * * @return the string assembled by this StringBuilder */ diff --git a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala index bfe95a11ab..c4781321d7 100644 --- a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala +++ b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala @@ -17,12 +17,14 @@ import scala.runtime.ScalaRunTime._ /** A builder class for arrays. * + * This builder can be reused. + * * @tparam A type of elements that can be added to this builder. * @param tag class tag for objects of type `A`. * * @since 2.8 */ -class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A]] { +class WrappedArrayBuilder[A](tag: ClassTag[A]) extends ReusableBuilder[A, WrappedArray[A]] { @deprecated("use tag instead", "2.10.0") val manifest: ClassTag[A] = tag @@ -73,12 +75,13 @@ class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A this } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) elems + if (capacity != 0 && capacity == size) { + capacity = 0 + elems + } else mkArray(size) } diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index f49536d351..e67e698a5c 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -36,6 +36,8 @@ import scala.reflect.ClassTag * * @author Philipp Haller, Heather Miller, Aleksandar Prokopec, Viktor Klang * + * @see [[http://docs.scala-lang.org/overviews/core/futures.html Futures and Promises]] + * * @define multipleCallbacks * Multiple callbacks may be registered; there is no guarantee that they will be * executed in a particular order. diff --git a/src/library/scala/concurrent/duration/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala index 8b7d81d1c4..a905ef345c 100644 --- a/src/library/scala/concurrent/duration/Duration.scala +++ b/src/library/scala/concurrent/duration/Duration.scala @@ -94,7 +94,7 @@ object Duration { timeUnitLabels flatMap { case (unit, names) => expandLabels(names) map (_ -> unit) } toMap /** - * Extract length and time unit out of a string, where the format must match the description for [[Duration$.apply(String):Duration apply(String)]]. + * Extract length and time unit out of a string, where the format must match the description for [[Duration$.apply(s:String)* apply(String)]]. * The extractor will not match for malformed strings or non-finite durations. */ def unapply(s: String): Option[(Long, TimeUnit)] = @@ -355,7 +355,7 @@ object Duration { * - isomorphic to `java.lang.Double` when it comes to infinite or undefined values * * The conversion between Duration and Double is done using [[Duration.toUnit]] (with unit NANOSECONDS) - * and [[Duration$.fromNanos(Double):Duration Duration.fromNanos(Double)]]. + * and [[Duration$.fromNanos(nanos:Double)* Duration.fromNanos(Double)]] * * <h2>Ordering</h2> * diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 371fd59a93..e769dfb8cb 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -397,7 +397,7 @@ object BigDecimal { * @version 1.1 */ final class BigDecimal(val bigDecimal: BigDec, val mc: MathContext) -extends ScalaNumber with ScalaNumericConversions with Serializable { +extends ScalaNumber with ScalaNumericConversions with Serializable with Ordered[BigDecimal] { def this(bigDecimal: BigDec) = this(bigDecimal, BigDecimal.defaultMathContext) import BigDecimal.RoundingMode._ import BigDecimal.{decimal, binary, exact} @@ -537,22 +537,6 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { */ def compare (that: BigDecimal): Int = this.bigDecimal compareTo that.bigDecimal - /** Less-than-or-equals comparison of BigDecimals - */ - def <= (that: BigDecimal): Boolean = compare(that) <= 0 - - /** Greater-than-or-equals comparison of BigDecimals - */ - def >= (that: BigDecimal): Boolean = compare(that) >= 0 - - /** Less-than of BigDecimals - */ - def < (that: BigDecimal): Boolean = compare(that) < 0 - - /** Greater-than comparison of BigDecimals - */ - def > (that: BigDecimal): Boolean = compare(that) > 0 - /** Addition of BigDecimals */ def + (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal add that.bigDecimal, mc) diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index abc7371d9f..3ae3b9bf6c 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -109,7 +109,12 @@ object BigInt { * @author Martin Odersky * @version 1.0, 15/07/2003 */ -final class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericConversions with Serializable { +final class BigInt(val bigInteger: BigInteger) + extends ScalaNumber + with ScalaNumericConversions + with Serializable + with Ordered[BigInt] +{ /** Returns the hash code for this BigInt. */ override def hashCode(): Int = if (isValidLong) unifiedPrimitiveHashcode() @@ -176,22 +181,6 @@ final class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNum */ def compare (that: BigInt): Int = this.bigInteger.compareTo(that.bigInteger) - /** Less-than-or-equals comparison of BigInts - */ - def <= (that: BigInt): Boolean = compare(that) <= 0 - - /** Greater-than-or-equals comparison of BigInts - */ - def >= (that: BigInt): Boolean = compare(that) >= 0 - - /** Less-than of BigInts - */ - def < (that: BigInt): Boolean = compare(that) < 0 - - /** Greater-than comparison of BigInts - */ - def > (that: BigInt): Boolean = compare(that) > 0 - /** Addition of BigInts */ def + (that: BigInt): BigInt = new BigInt(this.bigInteger.add(that.bigInteger)) diff --git a/src/library/scala/math/package.scala b/src/library/scala/math/package.scala index b6593d6661..54c81ed613 100644 --- a/src/library/scala/math/package.scala +++ b/src/library/scala/math/package.scala @@ -58,7 +58,19 @@ package object math { * logarithms. */ def exp(x: Double): Double = java.lang.Math.exp(x) + + /** Returns the natural logarithm of a `double` value. + * + * @param x the number to take the natural logarithm of + * @return the value `logₑ(x)` where `e` is Eulers number + */ def log(x: Double): Double = java.lang.Math.log(x) + + /** Returns the square root of a `double` value. + * + * @param x the number to take the square root of + * @return the value √x + */ def sqrt(x: Double): Double = java.lang.Math.sqrt(x) def IEEEremainder(x: Double, y: Double): Double = java.lang.Math.IEEEremainder(x, y) diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 4ff49c44d0..e099853463 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -157,6 +157,9 @@ object ManifestFactory { override def newArray(len: Int): Array[Unit] = new Array[Unit](len) override def newWrappedArray(len: Int): WrappedArray[Unit] = new WrappedArray.ofUnit(new Array[Unit](len)) override def newArrayBuilder(): ArrayBuilder[Unit] = new ArrayBuilder.ofUnit() + override protected def arrayClass[T](tp: Class[_]): Class[Array[T]] = + if (tp eq runtimeClass) classOf[Array[scala.runtime.BoxedUnit]].asInstanceOf[Class[Array[T]]] + else super.arrayClass(tp) private def readResolve(): Any = Manifest.Unit } diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index d4a5e2f0e8..7ea597eac9 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -105,7 +105,7 @@ private[scala] trait PropertiesTrait { * or "version (unknown)" if it cannot be determined. */ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)") - val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2015, LAMP/EPFL") + val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2016, LAMP/EPFL") /** This is the encoding to use reading in source files, overridden with -encoding. * Note that it uses "prop" i.e. looks in the scala jar, not the system properties. diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 6b015df6b4..44eee5cbfd 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -428,13 +428,15 @@ trait Definitions extends api.StandardDefinitions { def elementType(container: Symbol, tp: Type): Type = elementExtract(container, tp) // collections classes - lazy val ConsClass = requiredClass[scala.collection.immutable.::[_]] - lazy val IteratorClass = requiredClass[scala.collection.Iterator[_]] - lazy val IterableClass = requiredClass[scala.collection.Iterable[_]] - lazy val ListClass = requiredClass[scala.collection.immutable.List[_]] - lazy val SeqClass = requiredClass[scala.collection.Seq[_]] - lazy val StringBuilderClass = requiredClass[scala.collection.mutable.StringBuilder] - lazy val TraversableClass = requiredClass[scala.collection.Traversable[_]] + lazy val ConsClass = requiredClass[scala.collection.immutable.::[_]] + lazy val IteratorClass = requiredClass[scala.collection.Iterator[_]] + lazy val IterableClass = requiredClass[scala.collection.Iterable[_]] + lazy val ListClass = requiredClass[scala.collection.immutable.List[_]] + lazy val SeqClass = requiredClass[scala.collection.Seq[_]] + lazy val JavaStringBuilderClass = requiredClass[java.lang.StringBuilder] + lazy val JavaStringBufferClass = requiredClass[java.lang.StringBuffer] + lazy val JavaCharSequenceClass = requiredClass[java.lang.CharSequence] + lazy val TraversableClass = requiredClass[scala.collection.Traversable[_]] lazy val ListModule = requiredModule[scala.collection.immutable.List.type] def List_apply = getMemberMethod(ListModule, nme.apply) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 65740e87f1..5b613316cc 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -56,7 +56,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => new FreeTypeSymbol(name, origin) initFlags flags /** - * This map stores the original owner the the first time the owner of a symbol is re-assigned. + * This map stores the original owner the first time the owner of a symbol is re-assigned. * The original owner of a symbol is needed in some places in the backend. Ideally, owners should * be versioned like the type history. */ @@ -503,7 +503,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => case _ => new StubTermSymbol(this, name.toTermName, missingMessage) } - /** Given a field, construct a term symbol that represents the source construct that gave rise the the field */ + /** Given a field, construct a term symbol that represents the source construct that gave rise the field */ def sugaredSymbolOrSelf = { val getter = getterIn(owner) if (getter == NoSymbol) { diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 2e6cd819b4..e53b47e808 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3970,14 +3970,15 @@ trait Types } } - def normalizePlus(tp: Type) = ( + def normalizePlus(tp: Type): Type = { if (isRawType(tp)) rawToExistential(tp) else tp.normalize match { - // Unify the two representations of module classes - case st @ SingleType(_, sym) if sym.isModule => st.underlying.normalize - case _ => tp.normalize + // Unify the representations of module classes + case st@SingleType(_, sym) if sym.isModule => st.underlying.normalize + case st@ThisType(sym) if sym.isModuleClass => normalizePlus(st.underlying) + case _ => tp.normalize } - ) + } /* todo: change to: diff --git a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala index f9b10c90be..e6d7b11cad 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeComparers.scala @@ -463,7 +463,7 @@ trait TypeComparers { case SingletonClass => tp1.isStable || fourthTry case _: ClassSymbol => classOnRight case _: TypeSymbol if sym2.isDeferred => abstractTypeOnRight(tp2.bounds.lo) || fourthTry - case _: TypeSymbol => retry(tp1.normalize, tp2.normalize) + case _: TypeSymbol => retry(normalizePlus(tp1), normalizePlus(tp2)) case _ => fourthTry } } @@ -517,7 +517,7 @@ trait TypeComparers { * - handle typerefs, refined types, and singleton types. */ def fourthTry = { - def retry(lhs: Type, rhs: Type) = isSubType(lhs, rhs, depth) + def retry(lhs: Type, rhs: Type) = ((tp1 ne lhs) || (tp2 ne rhs)) && isSubType(lhs, rhs, depth) def abstractTypeOnLeft(hi: Type) = isDifferentTypeConstructor(tp1, hi) && retry(hi, tp2) tp1 match { @@ -526,22 +526,16 @@ trait TypeComparers { case TypeRef(_, sym2, _) => sym1 isBottomSubClass sym2 case _ => isSingleType(tp2) && retry(tp1, tp2.widen) } - def moduleOnLeft = tp2 match { - case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2) - case _ => false - } - def classOnLeft = ( - if (isRawType(tp1)) retry(rawToExistential(tp1), tp2) - else if (sym1.isModuleClass) moduleOnLeft - else sym1.isRefinementClass && retry(sym1.info, tp2) - ) + sym1 match { - case NothingClass => true - case NullClass => nullOnLeft - case _: ClassSymbol => classOnLeft - case _: TypeSymbol if sym1.isDeferred => abstractTypeOnLeft(tp1.bounds.hi) - case _: TypeSymbol => retry(tp1.normalize, tp2.normalize) - case _ => false + case NothingClass => true + case NullClass => nullOnLeft + case _: ClassSymbol if isRawType(tp1) => retry(normalizePlus(tp1), normalizePlus(tp2)) + case _: ClassSymbol if sym1.isModuleClass => retry(normalizePlus(tp1), normalizePlus(tp2)) + case _: ClassSymbol if sym1.isRefinementClass => retry(sym1.info, tp2) + case _: TypeSymbol if sym1.isDeferred => abstractTypeOnLeft(tp1.bounds.hi) + case _: TypeSymbol => retry(normalizePlus(tp1), normalizePlus(tp2)) + case _ => false } case RefinedType(parents, _) => parents exists (retry(_, tp2)) case _: SingletonType => retry(tp1.underlying, tp2) diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index ba85630dbc..13874916cc 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -266,7 +266,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.IterableClass definitions.ListClass definitions.SeqClass - definitions.StringBuilderClass + definitions.JavaStringBuilderClass + definitions.JavaStringBufferClass + definitions.JavaCharSequenceClass definitions.TraversableClass definitions.ListModule definitions.NilModule diff --git a/src/scaladoc/scala/tools/nsc/doc/Settings.scala b/src/scaladoc/scala/tools/nsc/doc/Settings.scala index a63ed1abe8..8a341a92d5 100644 --- a/src/scaladoc/scala/tools/nsc/doc/Settings.scala +++ b/src/scaladoc/scala/tools/nsc/doc/Settings.scala @@ -316,30 +316,6 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_)) "scala.Predef.Ensuring", "scala.collection.TraversableOnce.alternateImplicit") - /** There's a reason all these are specialized by hand but documenting each of them is beyond the point */ - val arraySkipConversions = List( - "scala.Predef.refArrayOps", - "scala.Predef.intArrayOps", - "scala.Predef.doubleArrayOps", - "scala.Predef.longArrayOps", - "scala.Predef.floatArrayOps", - "scala.Predef.charArrayOps", - "scala.Predef.byteArrayOps", - "scala.Predef.shortArrayOps", - "scala.Predef.booleanArrayOps", - "scala.Predef.unitArrayOps", - "scala.LowPriorityImplicits.wrapRefArray", - "scala.LowPriorityImplicits.wrapIntArray", - "scala.LowPriorityImplicits.wrapDoubleArray", - "scala.LowPriorityImplicits.wrapLongArray", - "scala.LowPriorityImplicits.wrapFloatArray", - "scala.LowPriorityImplicits.wrapCharArray", - "scala.LowPriorityImplicits.wrapByteArray", - "scala.LowPriorityImplicits.wrapShortArray", - "scala.LowPriorityImplicits.wrapBooleanArray", - "scala.LowPriorityImplicits.wrapUnitArray", - "scala.LowPriorityImplicits.genericWrapArray") - // included as names as here we don't have access to a Global with Definitions :( def valueClassList = List("unit", "boolean", "byte", "short", "char", "int", "long", "float", "double") def valueClassFilterPrefixes = List("scala.LowPriorityImplicits", "scala.Predef") diff --git a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala index fb4ed34571..707d0c469f 100644 --- a/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/CommentFactoryBase.scala @@ -26,29 +26,30 @@ trait CommentFactoryBase { this: MemberLookupBase => /* Creates comments with necessary arguments */ def createComment ( - body0: Option[Body] = None, - authors0: List[Body] = List.empty, - see0: List[Body] = List.empty, - result0: Option[Body] = None, - throws0: Map[String,Body] = Map.empty, - valueParams0: Map[String,Body] = Map.empty, - typeParams0: Map[String,Body] = Map.empty, - version0: Option[Body] = None, - since0: Option[Body] = None, - todo0: List[Body] = List.empty, - deprecated0: Option[Body] = None, - note0: List[Body] = List.empty, - example0: List[Body] = List.empty, - constructor0: Option[Body] = None, - source0: Option[String] = None, - inheritDiagram0: List[String] = List.empty, - contentDiagram0: List[String] = List.empty, - group0: Option[Body] = None, - groupDesc0: Map[String,Body] = Map.empty, - groupNames0: Map[String,Body] = Map.empty, - groupPrio0: Map[String,Body] = Map.empty - ) : Comment = new Comment{ - val body = if(body0 isDefined) body0.get else Body(Seq.empty) + body0: Option[Body] = None, + authors0: List[Body] = List.empty, + see0: List[Body] = List.empty, + result0: Option[Body] = None, + throws0: Map[String,Body] = Map.empty, + valueParams0: Map[String,Body] = Map.empty, + typeParams0: Map[String,Body] = Map.empty, + version0: Option[Body] = None, + since0: Option[Body] = None, + todo0: List[Body] = List.empty, + deprecated0: Option[Body] = None, + note0: List[Body] = List.empty, + example0: List[Body] = List.empty, + constructor0: Option[Body] = None, + source0: Option[String] = None, + inheritDiagram0: List[String] = List.empty, + contentDiagram0: List[String] = List.empty, + group0: Option[Body] = None, + groupDesc0: Map[String,Body] = Map.empty, + groupNames0: Map[String,Body] = Map.empty, + groupPrio0: Map[String,Body] = Map.empty, + hideImplicitConversions0: List[Body] = List.empty + ): Comment = new Comment { + val body = body0 getOrElse Body(Seq.empty) val authors = authors0 val see = see0 val result = result0 @@ -83,18 +84,20 @@ trait CommentFactoryBase { this: MemberLookupBase => } val groupNames = groupNames0 flatMap { case (group, body) => - try { - body match { - case Body(List(Paragraph(Chain(List(Summary(Text(name))))))) if (!name.trim.contains("\n")) => List(group -> (name.trim)) - case _ => List() - } - } catch { - case _: java.lang.NumberFormatException => List() + body match { + case Body(List(Paragraph(Chain(List(Summary(Text(name))))))) if (!name.trim.contains("\n")) => List(group -> (name.trim)) + case _ => List() } } + override val hideImplicitConversions: List[String] = + hideImplicitConversions0 flatMap { + case Body(List(Paragraph(Chain(List(Summary(Text(e))))))) if (!e.trim.contains("\n")) => List(e) + case _ => List() + } } + private val endOfText = '\u0003' private val endOfLine = '\u000A' @@ -165,11 +168,11 @@ trait CommentFactoryBase { this: MemberLookupBase => private val SymbolTagRegex = new Regex("""\s*@(param|tparam|throws|groupdesc|groupname|groupprio)\s+(\S*)\s*(.*)""") - /** The start of a scaladoc code block */ + /** The start of a Scaladoc code block */ private val CodeBlockStartRegex = new Regex("""(.*?)((?:\{\{\{)|(?:\u000E<pre(?: [^>]*)?>\u000E))(.*)""") - /** The end of a scaladoc code block */ + /** The end of a Scaladoc code block */ private val CodeBlockEndRegex = new Regex("""(.*?)((?:\}\}\})|(?:\u000E</pre>\u000E))(.*)""") @@ -183,6 +186,8 @@ trait CommentFactoryBase { this: MemberLookupBase => private final case class SimpleTagKey(name: String) extends TagKey private final case class SymbolTagKey(name: String, symbol: String) extends TagKey + private val TrailingWhitespaceRegex = """\s+$""".r + /** Parses a raw comment string into a `Comment` object. * @param comment The expanded comment string (including start and end markers) to be parsed. * @param src The raw comment source string. @@ -192,8 +197,8 @@ trait CommentFactoryBase { this: MemberLookupBase => * start and end markers, line start markers and unnecessary whitespace. */ def clean(comment: String): List[String] = { def cleanLine(line: String): String = { - //replaceAll removes trailing whitespaces - line.replaceAll("""\s+$""", "") match { + // Remove trailing whitespaces + TrailingWhitespaceRegex.replaceAllIn(line, "") match { case CleanCommentLine(ctl) => ctl case tl => tl } @@ -246,7 +251,7 @@ trait CommentFactoryBase { this: MemberLookupBase => parse0(docBody append endOfLine append marker, tags, lastTagKey, ls, inCodeBlock = true) } - case CodeBlockEndRegex(before, marker, after) :: ls => + case CodeBlockEndRegex(before, marker, after) :: ls => { if (!before.trim.isEmpty && !after.trim.isEmpty) parse0(docBody, tags, lastTagKey, before :: marker :: after :: ls, inCodeBlock = true) if (!before.trim.isEmpty) @@ -264,23 +269,27 @@ trait CommentFactoryBase { this: MemberLookupBase => case None => parse0(docBody append endOfLine append marker, tags, lastTagKey, ls, inCodeBlock = false) } + } - case SymbolTagRegex(name, sym, body) :: ls if (!inCodeBlock) => + case SymbolTagRegex(name, sym, body) :: ls if (!inCodeBlock) => { val key = SymbolTagKey(name, sym) val value = body :: tags.getOrElse(key, Nil) parse0(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) + } - case SimpleTagRegex(name, body) :: ls if (!inCodeBlock) => + case SimpleTagRegex(name, body) :: ls if (!inCodeBlock) => { val key = SimpleTagKey(name) val value = body :: tags.getOrElse(key, Nil) parse0(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) + } - case SingleTagRegex(name) :: ls if (!inCodeBlock) => + case SingleTagRegex(name) :: ls if (!inCodeBlock) => { val key = SimpleTagKey(name) val value = "" :: tags.getOrElse(key, Nil) parse0(docBody, tags + (key -> value), Some(key), ls, inCodeBlock) + } - case line :: ls if (lastTagKey.isDefined) => + case line :: ls if (lastTagKey.isDefined) => { val newtags = if (!line.isEmpty) { val key = lastTagKey.get val value = @@ -291,13 +300,15 @@ trait CommentFactoryBase { this: MemberLookupBase => tags + (key -> value) } else tags parse0(docBody, newtags, lastTagKey, ls, inCodeBlock) + } - case line :: ls => + case line :: ls => { if (docBody.length > 0) docBody append endOfLine docBody append line parse0(docBody, tags, lastTagKey, ls, inCodeBlock) + } - case Nil => + case Nil => { // Take the {inheritance, content} diagram keys aside, as it doesn't need any parsing val inheritDiagramTag = SimpleTagKey("inheritanceDiagram") val contentDiagramTag = SimpleTagKey("contentDiagram") @@ -321,7 +332,7 @@ trait CommentFactoryBase { this: MemberLookupBase => def oneTag(key: SimpleTagKey, filterEmpty: Boolean = true): Option[Body] = ((bodyTags remove key): @unchecked) match { case Some(r :: rs) if !(filterEmpty && r.blocks.isEmpty) => - if (!rs.isEmpty) reporter.warning(pos, "Only one '@" + key.name + "' tag is allowed") + if (!rs.isEmpty) reporter.warning(pos, s"Only one '@${key.name}' tag is allowed") Some(r) case _ => None } @@ -334,7 +345,7 @@ trait CommentFactoryBase { this: MemberLookupBase => bodyTags.keys.toSeq flatMap { case stk: SymbolTagKey if (stk.name == key.name) => Some(stk) case stk: SimpleTagKey if (stk.name == key.name) => - reporter.warning(pos, "Tag '@" + stk.name + "' must be followed by a symbol name") + reporter.warning(pos, s"Tag '@${stk.name}' must be followed by a symbol name") None case _ => None } @@ -342,7 +353,7 @@ trait CommentFactoryBase { this: MemberLookupBase => for (key <- keys) yield { val bs = (bodyTags remove key).get if (bs.length > 1) - reporter.warning(pos, "Only one '@" + key.name + "' tag for symbol " + key.symbol + " is allowed") + reporter.warning(pos, s"Only one '@${key.name}' tag for symbol ${key.symbol} is allowed") (key.symbol, bs.head) } Map.empty[String, Body] ++ (if (filterEmpty) pairs.filterNot(_._2.blocks.isEmpty) else pairs) @@ -385,14 +396,15 @@ trait CommentFactoryBase { this: MemberLookupBase => group0 = oneTag(SimpleTagKey("group")), groupDesc0 = allSymsOneTag(SimpleTagKey("groupdesc")), groupNames0 = allSymsOneTag(SimpleTagKey("groupname")), - groupPrio0 = allSymsOneTag(SimpleTagKey("groupprio")) + groupPrio0 = allSymsOneTag(SimpleTagKey("groupprio")), + hideImplicitConversions0 = allTags(SimpleTagKey("hideImplicitConversion")) ) for ((key, _) <- bodyTags) - reporter.warning(pos, "Tag '@" + key.name + "' is not recognised") + reporter.warning(pos, s"Tag '@${key.name}' is not recognised") com - + } } parse0(new StringBuilder(comment.size), Map.empty, None, clean(comment), inCodeBlock = false) @@ -424,7 +436,7 @@ trait CommentFactoryBase { this: MemberLookupBase => /* BLOCKS */ - /** {{{ block ::= code | title | hrule | para }}} */ + /** {{{ block ::= code | title | hrule | listBlock | para }}} */ def block(): Block = { if (checkSkipInitWhitespace("{{{")) code() @@ -459,7 +471,7 @@ trait CommentFactoryBase { this: MemberLookupBase => * nLine ::= nSpc listStyle para '\n' * }}} * Where n and m stand for the number of spaces. When `m > n`, a new list is nested. */ - def listBlock: Block = { + def listBlock(): Block = { /** Consumes one list item block and returns it, or None if the block is * not a list or a different list. */ diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala index e5eb68d65a..183297f2c3 100644 --- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala +++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Comment.scala @@ -123,6 +123,9 @@ abstract class Comment { /** Member group priorities */ def groupPrio: Map[String,Int] + /** A list of implicit conversions to hide */ + def hideImplicitConversions: List[String] + override def toString = body.toString + "\n" + (authors map ("@author " + _.toString)).mkString("\n") + diff --git a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala index 9086ee29c6..6076b1708c 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/HtmlFactory.scala @@ -46,9 +46,14 @@ class HtmlFactory(val universe: doc.Universe, index: doc.Index) { "source-code-pro-v6-latin-regular.eot", "source-code-pro-v6-latin-regular.ttf", "source-code-pro-v6-latin-regular.woff", + "MaterialIcons-Regular.eot", + "MaterialIcons-Regular.ttf", + "MaterialIcons-Regular.woff", "index.js", "jquery.js", + "jquery.mousewheel.min.js", + "jquery.panzoom.min.js", "scheduler.js", "diagrams.js", "template.js", diff --git a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala index e0cfbc9334..6e87f2b0a9 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/scaladoc/scala/tools/nsc/doc/html/page/Template.scala @@ -40,6 +40,8 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <link href={ relativeLinkTo{List("template.css", "lib")} } media="screen" type="text/css" rel="stylesheet"/> <link href={ relativeLinkTo{List("diagrams.css", "lib")} } media="screen" type="text/css" rel="stylesheet" id="diagrams-css" /> <script type="text/javascript" src={ relativeLinkTo{List("jquery.js", "lib")} } id="jquery-js"></script> + <script type="text/javascript" src={ relativeLinkTo{List("jquery.panzoom.min.js", "lib")} }></script> + <script type="text/javascript" src={ relativeLinkTo{List("jquery.mousewheel.min.js", "lib")} }></script> <script type="text/javascript" src={ relativeLinkTo{List("template.js", "lib")} }></script> <script type="text/javascript" src={ relativeLinkTo{List("tools.tooltip.js", "lib")} }></script> { if (universe.settings.docDiagrams.value) { @@ -140,7 +142,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp if (tpl.linearizationTemplates.isEmpty && tpl.conversions.isEmpty) NodeSeq.Empty else - <li class="inherit out"><span>By inheritance</span></li> + <li class="inherit out"><span>By Inheritance</span></li> } </ol> </div> @@ -176,7 +178,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <span class="filtertype"></span> <ol> <li class="hideall out"><span>Hide All</span></li> - <li class="showall in"><span>Show all</span></li> + <li class="showall in"><span>Show All</span></li> </ol> </div> } @@ -282,7 +284,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp { if (Set("epfl", "EPFL").contains(tpl.universe.settings.docfooter.value)) - <div id="footer">Scala programming documentation. Copyright (c) 2003-2015 <a href="http://www.epfl.ch" target="_top">EPFL</a>, with contributions from <a href="http://typesafe.com" target="_top">Typesafe</a>.</div> + <div id="footer">Scala programming documentation. Copyright (c) 2003-2016 <a href="http://www.epfl.ch" target="_top">EPFL</a>, with contributions from <a href="http://typesafe.com" target="_top">Typesafe</a>.</div> else <div id="footer"> { tpl.universe.settings.docfooter.value } </div> } @@ -624,7 +626,7 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp <dt>To do</dt> <dd>{ val todoXml: List[NodeSeq] = (for(todo <- comment.todo ) yield <span class="cmt">{bodyToHtml(todo)}</span> ) - todoXml.reduceLeft(_ ++ Text(", ") ++ _) + todoXml.reduceLeft(_ ++ _) }</dd> } @@ -682,9 +684,12 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp if (diagramSvg != NodeSeq.Empty) { <div class="toggleContainer block diagram-container" id={ id + "-container"}> <span class="toggle diagram-link">{ description }</span> - <div class="diagram" id={ id }>{ - diagramSvg - }</div> + <div class="diagram" id={ id }>{ diagramSvg }</div> + <div id="diagram-controls" class="hiddenContent"> + <button id="diagram-zoom-out" class="diagram-btn"><i class="material-icons"></i></button> + <button id="diagram-zoom-in" class="diagram-btn"><i class="material-icons"></i></button> + <button title="Toggle full-screen" id="diagram-fs" class="diagram-btn to-full"><i class="material-icons"></i></button> + </div> </div> } else NodeSeq.Empty } else NodeSeq.Empty diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.eot b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.eot Binary files differnew file mode 100644 index 0000000000..bf67d48bdb --- /dev/null +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.eot diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.ttf b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.ttf Binary files differnew file mode 100644 index 0000000000..683dcd05ac --- /dev/null +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.ttf diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.woff b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.woff Binary files differnew file mode 100644 index 0000000000..ddd6be3e3d --- /dev/null +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/MaterialIcons-Regular.woff diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.css index 22736a04dd..8c20810784 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.css +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.css @@ -1,3 +1,34 @@ +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url(MaterialIcons-Regular.eot); + src: local('Material Icons'), + local('MaterialIcons-Regular'), + url(MaterialIcons-Regular.woff) format('woff'), + url(MaterialIcons-Regular.ttf) format('truetype'); +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + display: inline-block; + width: 1em; + height: 1em; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + -moz-osx-font-smoothing: grayscale; + font-feature-settings: 'liga'; +} + .diagram-container { display: none; } @@ -38,6 +69,61 @@ text-decoration: none; } +#inheritance-diagram-container > span.toggle { + z-index: 2; +} + +#inheritance-diagram-container.full-screen { + position: fixed !important; + margin: 0; + border-radius: 0; + top: 0em; + bottom: 3em; + left: 0; + width: 100%; + height: 100%; + z-index: 10000; +} + +#inheritance-diagram-container.full-screen > span.toggle { + display: none; +} + +#inheritance-diagram-container.full-screen > div.diagram { + position: absolute; + top: 0; right: 0; bottom: 0; left: 0; + margin: auto; +} + +#diagram-controls { + z-index: 2; + position: absolute; + bottom: 1em; + right: 1em; +} + +#diagram-controls > button.diagram-btn { + border-radius: 1.25em; + height: 2.5em; + width: 2.5em; + background-color: #c2c2c2; + color: #fff; + border: 0; + float: left; + margin: 0 0.1em; + cursor: pointer; + line-height: 0.9; + outline: none; +} + +#diagram-controls > button.diagram-btn:hover { + background-color: #e2e2e2; +} + +#diagram-controls > button.diagram-btn > i.material-icons { + font-size: 1.5em; +} + svg a { cursor:pointer; } diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js index 801680b687..5d139c1080 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/diagrams.js @@ -15,10 +15,6 @@ $(document).ready(function() if(Modernizr && !Modernizr.inlinesvg) return; - // only execute this in the main window - if(diagrams.isPopup) - return; - if($("#content-diagram").length) $("#inheritance-diagram").css("padding-bottom", "20px"); @@ -62,41 +58,16 @@ $(document).ready(function() }); diagrams.initHighlighting(); -}); - -/** - * Initializes the diagrams in the popup. - */ -diagrams.initPopup = function(id) -{ - // copy diagram from main window - if(!jQuery.browser.msie) - $("body").append(opener.$("#" + id).data("svg")); - // positioning - $("svg").css("position", "absolute"); - $(window).resize(function() - { - var svg_w = $("svg").css("width").replace("px", ""); - var svg_h = $("svg").css("height").replace("px", ""); - var x = $(window).width() / 2 - svg_w / 2; - if(x < 0) x = 0; - var y = $(window).height() / 2 - svg_h / 2; - if(y < 0) y = 0; - $("svg").css("left", x + "px"); - $("svg").css("top", y + "px"); - }); - $(window).resize(); + $("button#diagram-fs").click(function() { + $("#inheritance-diagram-container").toggleClass("full-screen"); + $("#inheritance-diagram-container > div.diagram").css({ + height: $("svg").height() + "pt" + }); - diagrams.initHighlighting(); - $("svg a").click(function(e) { - opener.diagrams.redirectFromPopup(this.href.baseVal); - window.close(); - }); - $(document).keyup(function(e) { - if (e.keyCode == 27) window.close(); - }); -} + $panzoom.panzoom("reset", { animate: false, contain: false }); + }); +}); /** * Initializes highlighting for nodes and edges. @@ -182,39 +153,29 @@ diagrams.initHighlighting = function() /** * Resizes the diagrams according to the available width. */ -diagrams.resize = function() -{ - // available width - var availableWidth = $("body").width() - 100; - - $(".diagram-container").each(function() { - // unregister click event on whole div - $(".diagram", this).unbind("click"); - var diagramWidth = $(".diagram", this).data("width"); - var diagramHeight = $(".diagram", this).data("height"); - - if(diagramWidth > availableWidth) - { - // resize diagram - var height = diagramHeight / diagramWidth * availableWidth; - $(".diagram svg", this).width(availableWidth); - $(".diagram svg", this).height(height); - - // register click event on whole div - $(".diagram", this).click(function() { - diagrams.popup($(this)); - }); - $(".diagram", this).addClass("magnifying"); - } - else - { - // restore full size of diagram - $(".diagram svg", this).width(diagramWidth); - $(".diagram svg", this).height(diagramHeight); - // don't show custom cursor any more - $(".diagram", this).removeClass("magnifying"); - } - }); +diagrams.resize = function() { + // available width + var availableWidth = $("body").width() - 100; + + $(".diagram-container").each(function() { + // unregister click event on whole div + $(".diagram", this).unbind("click"); + var diagramWidth = $(".diagram", this).data("width"); + var diagramHeight = $(".diagram", this).data("height"); + + if(diagramWidth > availableWidth) { + // resize diagram + var height = diagramHeight / diagramWidth * availableWidth; + $(".diagram svg", this).width(availableWidth); + $(".diagram svg", this).height(height); + } else { + // restore full size of diagram + $(".diagram svg", this).width(diagramWidth); + $(".diagram svg", this).height(diagramHeight); + // don't show custom cursor any more + $(".diagram", this).removeClass("magnifying"); + } + }); }; /** @@ -222,82 +183,38 @@ diagrams.resize = function() */ diagrams.toggle = function(container, dontAnimate) { - // change class of link - $(".diagram-link", container).toggleClass("open"); - // get element to show / hide - var div = $(".diagram", container); - if (div.is(':visible')) - { - $(".diagram-help", container).hide(); - div.unbind("click"); - div.removeClass("magnifying"); - div.slideUp(100); - } - else - { - diagrams.resize(); - if(dontAnimate) - div.show(); - else - div.slideDown(100); - $(".diagram-help", container).show(); - } -}; - -/** - * Opens a popup containing a copy of a diagram. - */ -diagrams.windows = {}; -diagrams.popup = function(diagram) -{ - var id = diagram.attr("id"); - if(!diagrams.windows[id] || diagrams.windows[id].closed) { - var title = $(".symbol .name", $("#signature")).text(); - // cloning from parent window to popup somehow doesn't work in IE - // therefore include the SVG as a string into the HTML - var svgIE = jQuery.browser.msie ? $("<div />").append(diagram.data("svg")).html() : ""; - var html = '' + - '<?xml version="1.0" encoding="UTF-8"?>\n' + - '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n' + - '<html>\n' + - ' <head>\n' + - ' <title>' + title + '</title>\n' + - ' <link href="' + $("#diagrams-css").attr("href") + '" media="screen" type="text/css" rel="stylesheet" />\n' + - ' <script type="text/javascript" src="' + $("#jquery-js").attr("src") + '"></script>\n' + - ' <script type="text/javascript" src="' + $("#diagrams-js").attr("src") + '"></script>\n' + - ' <script type="text/javascript">\n' + - ' diagrams.isPopup = true;\n' + - ' </script>\n' + - ' </head>\n' + - ' <body onload="diagrams.initPopup(\'' + id + '\');">\n' + - ' <a href="#" onclick="window.close();" id="close-link">Close this window</a>\n' + - ' ' + svgIE + '\n' + - ' </body>\n' + - '</html>'; - - var padding = 30; - var screenHeight = screen.availHeight; - var screenWidth = screen.availWidth; - var w = Math.min(screenWidth, diagram.data("width") + 2 * padding); - var h = Math.min(screenHeight, diagram.data("height") + 2 * padding); - var left = (screenWidth - w) / 2; - var top = (screenHeight - h) / 2; - var parameters = "height=" + h + ", width=" + w + ", left=" + left + ", top=" + top + ", scrollbars=yes, location=no, resizable=yes"; - var win = window.open("about:blank", "_blank", parameters); - win.document.open(); - win.document.write(html); - win.document.close(); - diagrams.windows[id] = win; - } - win.focus(); -}; - -/** - * This method is called from within the popup when a node is clicked. - */ -diagrams.redirectFromPopup = function(url) -{ - window.location = url; + // change class of link + $(".diagram-link", container).toggleClass("open"); + // get element to show / hide + var div = $(".diagram", container); + if (div.is(':visible')) { + $(".diagram-help", container).hide(); + div.unbind("click"); + div.slideUp(100); + + $("#diagram-controls", container).hide(); + $("#inheritance-diagram-container").unbind('mousewheel.focal'); + } else { + diagrams.resize(); + if(dontAnimate) + div.show(); + else + div.slideDown(100); + $(".diagram-help", container).show(); + + $("#diagram-controls", container).show(); + + $("#inheritance-diagram-container").on('mousewheel.focal', function(e) { + e.preventDefault(); + var delta = e.delta || e.originalEvent.wheelDelta; + var zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0; + $panzoom.panzoom('zoom', zoomOut, { + increment: 0.1, + animate: true, + focal: e + }); + }); + } }; /** diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/jquery.mousewheel.min.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/jquery.mousewheel.min.js new file mode 100644 index 0000000000..03bfd60c5e --- /dev/null +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/jquery.mousewheel.min.js @@ -0,0 +1,8 @@ +/*! + * jQuery Mousewheel 3.1.13 + * + * Copyright 2015 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
\ No newline at end of file diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/jquery.panzoom.min.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/jquery.panzoom.min.js new file mode 100644 index 0000000000..7c3be68b7e --- /dev/null +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/jquery.panzoom.min.js @@ -0,0 +1,9 @@ +/** + * @license jquery.panzoom.js v2.0.5 + * Updated: Thu Jul 03 2014 + * Add pan and zoom functionality to any element + * Copyright (c) 2014 timmy willison + * Released under the MIT license + * https://github.com/timmywil/jquery.panzoom/blob/master/MIT-License.txt + */ +!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return b(a,c)}):"object"==typeof exports?b(a,require("jquery")):b(a,a.jQuery)}("undefined"!=typeof window?window:this,function(a,b){"use strict";function c(a,b){for(var c=a.length;--c;)if(+a[c]!==+b[c])return!1;return!0}function d(a){var c={range:!0,animate:!0};return"boolean"==typeof a?c.animate=a:b.extend(c,a),c}function e(a,c,d,e,f,g,h,i,j){this.elements="array"===b.type(a)?[+a[0],+a[2],+a[4],+a[1],+a[3],+a[5],0,0,1]:[a,c,d,e,f,g,h||0,i||0,j||1]}function f(a,b,c){this.elements=[a,b,c]}function g(a,c){if(!(this instanceof g))return new g(a,c);1!==a.nodeType&&b.error("Panzoom called on non-Element node"),b.contains(l,a)||b.error("Panzoom element must be attached to the document");var d=b.data(a,m);if(d)return d;this.options=c=b.extend({},g.defaults,c),this.elem=a;var e=this.$elem=b(a);this.$set=c.$set&&c.$set.length?c.$set:e,this.$doc=b(a.ownerDocument||l),this.$parent=e.parent(),this.isSVG=r.test(a.namespaceURI)&&"svg"!==a.nodeName.toLowerCase(),this.panning=!1,this._buildTransform(),this._transform=!this.isSVG&&b.cssProps.transform.replace(q,"-$1").toLowerCase(),this._buildTransition(),this.resetDimensions();var f=b(),h=this;b.each(["$zoomIn","$zoomOut","$zoomRange","$reset"],function(a,b){h[b]=c[b]||f}),this.enable(),b.data(a,m,this)}var h="over out down up move enter leave cancel".split(" "),i=b.extend({},b.event.mouseHooks),j={};if(a.PointerEvent)b.each(h,function(a,c){b.event.fixHooks[j[c]="pointer"+c]=i});else{var k=i.props;i.props=k.concat(["touches","changedTouches","targetTouches","altKey","ctrlKey","metaKey","shiftKey"]),i.filter=function(a,b){var c,d=k.length;if(!b.pageX&&b.touches&&(c=b.touches[0]))for(;d--;)a[k[d]]=c[k[d]];return a},b.each(h,function(a,c){if(2>a)j[c]="mouse"+c;else{var d="touch"+("down"===c?"start":"up"===c?"end":c);b.event.fixHooks[d]=i,j[c]=d+" mouse"+c}})}b.pointertouch=j;var l=a.document,m="__pz__",n=Array.prototype.slice,o=!!a.PointerEvent,p=function(){var a=l.createElement("input");return a.setAttribute("oninput","return"),"function"==typeof a.oninput}(),q=/([A-Z])/g,r=/^http:[\w\.\/]+svg$/,s=/^inline/,t="(\\-?[\\d\\.e]+)",u="\\,?\\s*",v=new RegExp("^matrix\\("+t+u+t+u+t+u+t+u+t+u+t+"\\)$");return e.prototype={x:function(a){var b=a instanceof f,c=this.elements,d=a.elements;return b&&3===d.length?new f(c[0]*d[0]+c[1]*d[1]+c[2]*d[2],c[3]*d[0]+c[4]*d[1]+c[5]*d[2],c[6]*d[0]+c[7]*d[1]+c[8]*d[2]):d.length===c.length?new e(c[0]*d[0]+c[1]*d[3]+c[2]*d[6],c[0]*d[1]+c[1]*d[4]+c[2]*d[7],c[0]*d[2]+c[1]*d[5]+c[2]*d[8],c[3]*d[0]+c[4]*d[3]+c[5]*d[6],c[3]*d[1]+c[4]*d[4]+c[5]*d[7],c[3]*d[2]+c[4]*d[5]+c[5]*d[8],c[6]*d[0]+c[7]*d[3]+c[8]*d[6],c[6]*d[1]+c[7]*d[4]+c[8]*d[7],c[6]*d[2]+c[7]*d[5]+c[8]*d[8]):!1},inverse:function(){var a=1/this.determinant(),b=this.elements;return new e(a*(b[8]*b[4]-b[7]*b[5]),a*-(b[8]*b[1]-b[7]*b[2]),a*(b[5]*b[1]-b[4]*b[2]),a*-(b[8]*b[3]-b[6]*b[5]),a*(b[8]*b[0]-b[6]*b[2]),a*-(b[5]*b[0]-b[3]*b[2]),a*(b[7]*b[3]-b[6]*b[4]),a*-(b[7]*b[0]-b[6]*b[1]),a*(b[4]*b[0]-b[3]*b[1]))},determinant:function(){var a=this.elements;return a[0]*(a[8]*a[4]-a[7]*a[5])-a[3]*(a[8]*a[1]-a[7]*a[2])+a[6]*(a[5]*a[1]-a[4]*a[2])}},f.prototype.e=e.prototype.e=function(a){return this.elements[a]},g.rmatrix=v,g.events=b.pointertouch,g.defaults={eventNamespace:".panzoom",transition:!0,cursor:"move",disablePan:!1,disableZoom:!1,increment:.3,minScale:.4,maxScale:5,rangeStep:.05,duration:200,easing:"ease-in-out",contain:!1},g.prototype={constructor:g,instance:function(){return this},enable:function(){this._initStyle(),this._bind(),this.disabled=!1},disable:function(){this.disabled=!0,this._resetStyle(),this._unbind()},isDisabled:function(){return this.disabled},destroy:function(){this.disable(),b.removeData(this.elem,m)},resetDimensions:function(){var a=this.$parent;this.container={width:a.innerWidth(),height:a.innerHeight()};var c,d=a.offset(),e=this.elem,f=this.$elem;this.isSVG?(c=e.getBoundingClientRect(),c={left:c.left-d.left,top:c.top-d.top,width:c.width,height:c.height,margin:{left:0,top:0}}):c={left:b.css(e,"left",!0)||0,top:b.css(e,"top",!0)||0,width:f.innerWidth(),height:f.innerHeight(),margin:{top:b.css(e,"marginTop",!0)||0,left:b.css(e,"marginLeft",!0)||0}},c.widthBorder=b.css(e,"borderLeftWidth",!0)+b.css(e,"borderRightWidth",!0)||0,c.heightBorder=b.css(e,"borderTopWidth",!0)+b.css(e,"borderBottomWidth",!0)||0,this.dimensions=c},reset:function(a){a=d(a);var b=this.setMatrix(this._origTransform,a);a.silent||this._trigger("reset",b)},resetZoom:function(a){a=d(a);var b=this.getMatrix(this._origTransform);a.dValue=b[3],this.zoom(b[0],a)},resetPan:function(a){var b=this.getMatrix(this._origTransform);this.pan(b[4],b[5],d(a))},setTransform:function(a){for(var c=this.isSVG?"attr":"style",d=this.$set,e=d.length;e--;)b[c](d[e],"transform",a)},getTransform:function(a){var c=this.$set,d=c[0];return a?this.setTransform(a):a=b[this.isSVG?"attr":"style"](d,"transform"),"none"===a||v.test(a)||this.setTransform(a=b.css(d,"transform")),a||"none"},getMatrix:function(a){var b=v.exec(a||this.getTransform());return b&&b.shift(),b||[1,0,0,1,0,0]},setMatrix:function(a,c){if(!this.disabled){c||(c={}),"string"==typeof a&&(a=this.getMatrix(a));var d,e,f,g,h,i,j,k,l,m,n=+a[0],o=this.$parent,p="undefined"!=typeof c.contain?c.contain:this.options.contain;return p&&(d=this._checkDims(),e=this.container,l=d.width+d.widthBorder,m=d.height+d.heightBorder,f=(l*Math.abs(n)-e.width)/2,g=(m*Math.abs(n)-e.height)/2,j=d.left+d.margin.left,k=d.top+d.margin.top,"invert"===p?(h=l>e.width?l-e.width:0,i=m>e.height?m-e.height:0,f+=(e.width-l)/2,g+=(e.height-m)/2,a[4]=Math.max(Math.min(a[4],f-j),-f-j-h),a[5]=Math.max(Math.min(a[5],g-k),-g-k-i+d.heightBorder)):(g+=d.heightBorder/2,h=e.width>l?e.width-l:0,i=e.height>m?e.height-m:0,"center"===o.css("textAlign")&&s.test(b.css(this.elem,"display"))?h=0:f=g=0,a[4]=Math.min(Math.max(a[4],f-j),-f-j+h),a[5]=Math.min(Math.max(a[5],g-k),-g-k+i))),"skip"!==c.animate&&this.transition(!c.animate),c.range&&this.$zoomRange.val(n),this.setTransform("matrix("+a.join(",")+")"),c.silent||this._trigger("change",a),a}},isPanning:function(){return this.panning},transition:function(a){if(this._transition)for(var c=a||!this.options.transition?"none":this._transition,d=this.$set,e=d.length;e--;)b.style(d[e],"transition")!==c&&b.style(d[e],"transition",c)},pan:function(a,b,c){if(!this.options.disablePan){c||(c={});var d=c.matrix;d||(d=this.getMatrix()),c.relative&&(a+=+d[4],b+=+d[5]),d[4]=a,d[5]=b,this.setMatrix(d,c),c.silent||this._trigger("pan",d[4],d[5])}},zoom:function(a,c){"object"==typeof a?(c=a,a=null):c||(c={});var d=b.extend({},this.options,c);if(!d.disableZoom){var g=!1,h=d.matrix||this.getMatrix();"number"!=typeof a&&(a=+h[0]+d.increment*(a?-1:1),g=!0),a>d.maxScale?a=d.maxScale:a<d.minScale&&(a=d.minScale);var i=d.focal;if(i&&!d.disablePan){var j=this._checkDims(),k=i.clientX,l=i.clientY;this.isSVG||(k-=(j.width+j.widthBorder)/2,l-=(j.height+j.heightBorder)/2);var m=new f(k,l,1),n=new e(h),o=this.parentOffset||this.$parent.offset(),p=new e(1,0,o.left-this.$doc.scrollLeft(),0,1,o.top-this.$doc.scrollTop()),q=n.inverse().x(p.inverse().x(m)),r=a/h[0];n=n.x(new e([r,0,0,r,0,0])),m=p.x(n.x(q)),h[4]=+h[4]+(k-m.e(0)),h[5]=+h[5]+(l-m.e(1))}h[0]=a,h[3]="number"==typeof d.dValue?d.dValue:a,this.setMatrix(h,{animate:"boolean"==typeof d.animate?d.animate:g,range:!d.noSetRange}),d.silent||this._trigger("zoom",h[0],d)}},option:function(a,c){var d;if(!a)return b.extend({},this.options);if("string"==typeof a){if(1===arguments.length)return void 0!==this.options[a]?this.options[a]:null;d={},d[a]=c}else d=a;this._setOptions(d)},_setOptions:function(a){b.each(a,b.proxy(function(a,c){switch(a){case"disablePan":this._resetStyle();case"$zoomIn":case"$zoomOut":case"$zoomRange":case"$reset":case"disableZoom":case"onStart":case"onChange":case"onZoom":case"onPan":case"onEnd":case"onReset":case"eventNamespace":this._unbind()}switch(this.options[a]=c,a){case"disablePan":this._initStyle();case"$zoomIn":case"$zoomOut":case"$zoomRange":case"$reset":this[a]=c;case"disableZoom":case"onStart":case"onChange":case"onZoom":case"onPan":case"onEnd":case"onReset":case"eventNamespace":this._bind();break;case"cursor":b.style(this.elem,"cursor",c);break;case"minScale":this.$zoomRange.attr("min",c);break;case"maxScale":this.$zoomRange.attr("max",c);break;case"rangeStep":this.$zoomRange.attr("step",c);break;case"startTransform":this._buildTransform();break;case"duration":case"easing":this._buildTransition();case"transition":this.transition();break;case"$set":c instanceof b&&c.length&&(this.$set=c,this._initStyle(),this._buildTransform())}},this))},_initStyle:function(){var a={"backface-visibility":"hidden","transform-origin":this.isSVG?"0 0":"50% 50%"};this.options.disablePan||(a.cursor=this.options.cursor),this.$set.css(a);var c=this.$parent;c.length&&!b.nodeName(c[0],"body")&&(a={overflow:"hidden"},"static"===c.css("position")&&(a.position="relative"),c.css(a))},_resetStyle:function(){this.$elem.css({cursor:"",transition:""}),this.$parent.css({overflow:"",position:""})},_bind:function(){var a=this,c=this.options,d=c.eventNamespace,e=o?"pointerdown"+d:"touchstart"+d+" mousedown"+d,f=o?"pointerup"+d:"touchend"+d+" click"+d,h={},i=this.$reset,j=this.$zoomRange;if(b.each(["Start","Change","Zoom","Pan","End","Reset"],function(){var a=c["on"+this];b.isFunction(a)&&(h["panzoom"+this.toLowerCase()+d]=a)}),c.disablePan&&c.disableZoom||(h[e]=function(b){var d;("touchstart"===b.type?!(d=b.touches)||(1!==d.length||c.disablePan)&&2!==d.length:c.disablePan||1!==b.which)||(b.preventDefault(),b.stopPropagation(),a._startMove(b,d))}),this.$elem.on(h),i.length&&i.on(f,function(b){b.preventDefault(),a.reset()}),j.length&&j.attr({step:c.rangeStep===g.defaults.rangeStep&&j.attr("step")||c.rangeStep,min:c.minScale,max:c.maxScale}).prop({value:this.getMatrix()[0]}),!c.disableZoom){var k=this.$zoomIn,l=this.$zoomOut;k.length&&l.length&&(k.on(f,function(b){b.preventDefault(),a.zoom()}),l.on(f,function(b){b.preventDefault(),a.zoom(!0)})),j.length&&(h={},h[(o?"pointerdown":"mousedown")+d]=function(){a.transition(!0)},h[(p?"input":"change")+d]=function(){a.zoom(+this.value,{noSetRange:!0})},j.on(h))}},_unbind:function(){this.$elem.add(this.$zoomIn).add(this.$zoomOut).add(this.$reset).off(this.options.eventNamespace)},_buildTransform:function(){return this._origTransform=this.getTransform(this.options.startTransform)},_buildTransition:function(){if(this._transform){var a=this.options;this._transition=this._transform+" "+a.duration+"ms "+a.easing}},_checkDims:function(){var a=this.dimensions;return a.width&&a.height||this.resetDimensions(),this.dimensions},_getDistance:function(a){var b=a[0],c=a[1];return Math.sqrt(Math.pow(Math.abs(c.clientX-b.clientX),2)+Math.pow(Math.abs(c.clientY-b.clientY),2))},_getMiddle:function(a){var b=a[0],c=a[1];return{clientX:(c.clientX-b.clientX)/2+b.clientX,clientY:(c.clientY-b.clientY)/2+b.clientY}},_trigger:function(a){"string"==typeof a&&(a="panzoom"+a),this.$elem.triggerHandler(a,[this].concat(n.call(arguments,1)))},_startMove:function(a,d){var e,f,g,h,i,j,k,m,n=this,p=this.options,q=p.eventNamespace,r=this.getMatrix(),s=r.slice(0),t=+s[4],u=+s[5],v={matrix:r,animate:"skip"};o?(f="pointermove",g="pointerup"):"touchstart"===a.type?(f="touchmove",g="touchend"):(f="mousemove",g="mouseup"),f+=q,g+=q,this.transition(!0),this.panning=!0,this._trigger("start",a,d),d&&2===d.length?(h=this._getDistance(d),i=+r[0],j=this._getMiddle(d),e=function(a){a.preventDefault();var b=n._getMiddle(d=a.touches),c=n._getDistance(d)-h;n.zoom(c*(p.increment/100)+i,{focal:b,matrix:r,animate:!1}),n.pan(+r[4]+b.clientX-j.clientX,+r[5]+b.clientY-j.clientY,v),j=b}):(k=a.pageX,m=a.pageY,e=function(a){a.preventDefault(),n.pan(t+a.pageX-k,u+a.pageY-m,v)}),b(l).off(q).on(f,e).on(g,function(a){a.preventDefault(),b(this).off(q),n.panning=!1,a.type="panzoomend",n._trigger(a,r,!c(r,s))})}},b.Panzoom=g,b.fn.panzoom=function(a){var c,d,e,f;return"string"==typeof a?(f=[],d=n.call(arguments,1),this.each(function(){c=b.data(this,m),c?"_"!==a.charAt(0)&&"function"==typeof(e=c[a])&&void 0!==(e=e.apply(c,d))&&f.push(e):f.push(void 0)}),f.length?1===f.length?f[0]:f:this):this.each(function(){new g(this,a)})},g});
\ No newline at end of file diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css index 662ae48944..43e59076ca 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.css @@ -769,6 +769,10 @@ div#footer { box-shadow: none; } +#comment > dl > div > ol { + list-style-type: none; +} + div.fullcomment div.block ol li p, div.fullcomment div.block ol li { display:inline diff --git a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js index 9d9d7bdfff..3baf0d9db7 100644 --- a/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js +++ b/src/scaladoc/scala/tools/nsc/doc/html/resource/lib/template.js @@ -1,7 +1,20 @@ // © 2009–2010 EPFL/LAMP // code by Gilles Dubochet with contributions by Pedro Furlanetto, Marcin Kubala and Felix Mulder +var $panzoom = undefined; $(document).ready(function() { + // Add zoom functionality to type inheritance diagram + $panzoom = $("#inheritance-diagram").panzoom({ + increment: 0.1, + minScale: 1, + maxScale: 3, + transition: true, + duration: 200, + contain: 'invert', + easing: "ease-in-out", + $zoomIn: $('#diagram-zoom-in'), + $zoomOut: $('#diagram-zoom-out'), + }); $("#template > div > div > ol > li > span > a").click(function(e) { $("#template > div > div > ol > li").removeClass("selected"); @@ -275,12 +288,7 @@ $(document).ready(function() { function toggleShowContentFct(e){ e.toggleClass("open"); var content = $(".hiddenContent", e.parent().get(0)); - if (content.is(':visible')) { - content.slideUp(100); - } - else { - content.slideDown(100); - } + (content.is(':visible') ? content.slideUp : content.slideDown)(100); }; $(".toggle:not(.diagram-link)").click(function() { diff --git a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index 0264f2f99f..830d902b68 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -98,10 +98,15 @@ trait ModelFactoryImplicitSupport { // also keep empty conversions, so they appear in diagrams // conversions = conversions.filter(!_.members.isEmpty) - // Filter out specialized conversions from array - if (sym == ArrayClass) - conversions = conversions.filterNot((conv: ImplicitConversionImpl) => - hardcoded.arraySkipConversions.contains(conv.conversionQualifiedName)) + val hiddenConversions: Seq[String] = thisFactory + .comment(sym, inTpl.linkTarget, inTpl) + .map(_.hideImplicitConversions) + .getOrElse(Nil) + + conversions = conversions filterNot { conv: ImplicitConversionImpl => + hiddenConversions.contains(conv.conversionShortName) || + hiddenConversions.contains(conv.conversionQualifiedName) + } // Filter out non-sensical conversions from value types if (isPrimitiveValueType(sym.tpe_*)) diff --git a/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala b/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala index 093899231e..86900f26c9 100644 --- a/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/model/diagram/DiagramFactory.scala @@ -248,7 +248,7 @@ trait DiagramFactory extends DiagramDirectiveParser { case _ => Nil }) - // Only show the the non-isolated nodes + // Only show the non-isolated nodes // TODO: Decide if we really want to hide package members, I'm not sure that's a good idea (!!!) // TODO: Does .distinct cause any stability issues? val sourceNodes = edges.map(_._1) diff --git a/src/scalap/decoder.properties b/src/scalap/decoder.properties index 333f6ce715..9bb8d130ea 100644 --- a/src/scalap/decoder.properties +++ b/src/scalap/decoder.properties @@ -1,2 +1,2 @@ version.number=2.0.1 -copyright.string=(c) 2002-2015 LAMP/EPFL +copyright.string=(c) 2002-2016 LAMP/EPFL |