diff options
Diffstat (limited to 'src')
58 files changed, 572 insertions, 356 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 17bea7f796..e79c92e162 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1366,7 +1366,8 @@ self => } parseDo case FOR => - def parseFor = atPos(in.skipToken()) { + val start = in.skipToken() + def parseFor = atPos(start) { val enums = if (in.token == LBRACE) inBracesOrNil(enumerators()) else inParensOrNil(enumerators()) @@ -1378,7 +1379,11 @@ self => makeFor(enums, expr()) } } - parseFor + def adjustStart(tree: Tree) = + if (tree.pos.isRange && start < tree.pos.start) + tree setPos tree.pos.withStart(start) + else tree + adjustStart(parseFor) case RETURN => def parseReturn = atPos(in.skipToken()) { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index e6bf43fe93..dd0f8fdbe0 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -754,8 +754,12 @@ trait Scanners extends ScannersCommon { } else { val isUnclosedLiteral = !isUnicodeEscape && (ch == SU || (!multiLine && (ch == CR || ch == LF))) if (isUnclosedLiteral) { - syntaxError(if (!multiLine) "unclosed string literal" else "unclosed multi-line string literal") - } else { + if (multiLine) + incompleteInputError("unclosed multi-line string literal") + else + syntaxError("unclosed string literal") + } + else { putChar(ch) nextRawChar() getStringPart(multiLine) diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 8bbf11650c..486a43614b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -42,10 +42,14 @@ trait BasicBlocks { private final class SuccessorList() { private var successors: List[BasicBlock] = Nil + /** This method is very hot! Handle with care. */ private def updateConserve() { - var lb: ListBuffer[BasicBlock] = null - var matches = 0 - var remaining = successors + var lb: ListBuffer[BasicBlock] = null + var matches = 0 + var remaining = successors + val direct = directSuccessors + var scratchHandlers: List[ExceptionHandler] = method.exh + var scratchBlocks: List[BasicBlock] = direct def addBlock(bb: BasicBlock) { if (matches < 0) @@ -60,25 +64,27 @@ trait BasicBlocks { } } - // exceptionSuccessors - method.exh foreach { handler => - if (handler covers outer) - addBlock(handler.startBlock) + while (scratchBlocks ne Nil) { + addBlock(scratchBlocks.head) + scratchBlocks = scratchBlocks.tail } - // directSuccessors - val direct = directSuccessors - direct foreach addBlock - /** Return a list of successors for 'b' that come from exception handlers * covering b's (non-exceptional) successors. These exception handlers * might not cover 'b' itself. This situation corresponds to an * exception being thrown as the first thing of one of b's successors. */ - method.exh foreach { handler => - direct foreach { block => - if (handler covers block) + while (scratchHandlers ne Nil) { + val handler = scratchHandlers.head + if (handler covers outer) + addBlock(handler.startBlock) + + scratchBlocks = direct + while (scratchBlocks ne Nil) { + if (handler covers scratchBlocks.head) addBlock(handler.startBlock) + scratchBlocks = scratchBlocks.tail } + scratchHandlers = scratchHandlers.tail } // Blocks did not align: create a new list. if (matches < 0) @@ -101,7 +107,7 @@ trait BasicBlocks { } /** Flags of this basic block. */ - private var flags: Int = 0 + private[this] var flags: Int = 0 /** Does this block have the given flag? */ def hasFlag(flag: Int): Boolean = (flags & flag) != 0 diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala index 1f68781777..24a26b2ad3 100644 --- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala +++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala @@ -49,7 +49,11 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp if(top === self) {{ var url = '{ val p = templateToPath(tpl); "../" * (p.size - 1) + "index.html" }'; var hash = '{ val p = templateToPath(tpl); (p.tail.reverse ::: List(p.head.replace(".html", ""))).mkString(".") }'; - window.location.href = url + '#' + hash; + var anchor = window.location.hash; + var anchor_opt = ''; + if (anchor.length { scala.xml.Unparsed(">=") /* unless we use Unparsed, it gets escaped and crashes the script */ } 1) + anchor_opt = '@' + anchor.substring(1); + window.location.href = url + '#' + hash + anchor_opt; }} </script> </xml:group> diff --git a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala index efc393c812..2aed99657e 100644 --- a/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala +++ b/src/compiler/scala/tools/nsc/interactive/ScratchPadMaker.scala @@ -113,9 +113,11 @@ trait ScratchPadMaker { self: Global => val topLevel = objectName.isEmpty if (topLevel) objectName = tree.symbol.fullName body foreach traverseStat - applyPendingPatches(skipped) - if (topLevel) - patches += Patch(skipped, epilogue) + if (skipped != 0) { // don't issue prologue and epilogue if there are no instrumented statements + applyPendingPatches(skipped) + if (topLevel) + patches += Patch(skipped, epilogue) + } case _ => } diff --git a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala index f49e8d6b59..0f5777d260 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala @@ -37,7 +37,7 @@ trait ExprTyper { } /** Parse a line into a sequence of trees. Returns None if the input is incomplete. */ - def parse(line: String): Option[List[Tree]] = { + def parse(line: String): Option[List[Tree]] = debugging(s"""parse("$line")""") { var isIncomplete = false reporter.withIncompleteHandler((_, _) => isIncomplete = true) { val trees = codeParser.stmts(line) diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 570704f049..972debb900 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -550,6 +550,10 @@ abstract class CleanUp extends Transform with ast.TreeDSL { else tree } + case DefDef(mods, name, tps, vps, tp, rhs) if tree.symbol.hasStaticAnnotation => + reporter.error(tree.pos, "The @static annotation is not allowed on method definitions.") + super.transform(tree) + case ValDef(mods, name, tpt, rhs) if tree.symbol.hasStaticAnnotation => def transformStaticValDef = { log("moving @static valdef field: " + name + ", in: " + tree.symbol.owner) @@ -592,7 +596,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { } // create a static field in the companion class for this @static field - val stfieldSym = linkedClass.newVariable(newTermName(name), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo sym.tpe + val stfieldSym = linkedClass.newValue(newTermName(name), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo sym.tpe + if (sym.isMutable) stfieldSym.setFlag(MUTABLE) stfieldSym.addAnnotation(StaticClass) val names = classNames.getOrElseUpdate(linkedClass, linkedClass.info.decls.collect { @@ -768,7 +773,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL { staticSym <- clazz.info.decls if staticSym.hasStaticAnnotation } staticSym match { - case stfieldSym if stfieldSym.isVariable => + case stfieldSym if (stfieldSym.isValue && !stfieldSym.isMethod) || stfieldSym.isVariable => + log(stfieldSym + " is value: " + stfieldSym.isValue) val valdef = staticBodies((clazz, stfieldSym)) val ValDef(_, _, _, rhs) = valdef val fixedrhs = rhs.changeOwner((valdef.symbol, clazz.info.decl(nme.CONSTRUCTOR))) diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 2831afc48e..0820d3e714 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -111,7 +111,8 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { } def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { - var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) + // No variance for method type parameters + var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) map (_ resetFlag COVARIANT | CONTRAVARIANT) val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpeHK)) val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType def transform(clonedType: Type): Type = clonedType match { diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index e8387c80f5..12e2433e0d 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -111,7 +111,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD var added = false val stats = for (stat <- body1) yield stat match { - case Block(_, _) | Apply(_, _) | If(_, _, _) if !added => + case Block(_, _) | Apply(_, _) | If(_, _, _) | Try(_, _, _) if !added => // Avoid adding bitmaps when they are fully overshadowed by those // that are added inside loops if (LocalLazyValFinder.find(stat)) { diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 773d9a6f50..b7195b0349 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -85,10 +85,33 @@ trait ContextErrors { def typeErrorMsg(found: Type, req: Type, possiblyMissingArgs: Boolean) = { def missingArgsMsg = if (possiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else "" + "type mismatch" + foundReqMsg(found, req) + missingArgsMsg } } + def notAnyRefMessage(found: Type): String = { + val tp = found.widen + def name = tp.typeSymbol.nameString + def parents = tp.parents filterNot isTrivialTopType + def onlyAny = tp.parents forall (_.typeSymbol == AnyClass) + def parents_s = ( if (parents.isEmpty) tp.parents else parents ) mkString ", " + def what = ( + if (tp.typeSymbol.isAbstractType) { + val descr = if (onlyAny) "unbounded" else "bounded only by " + parents_s + s"$name is $descr, which means AnyRef is not a known parent" + } + else if (tp.typeSymbol.isAnonOrRefinementClass) + s"the parents of this type ($parents_s) extend Any, not AnyRef" + else + s"$name extends Any, not AnyRef" + ) + if (isPrimitiveValueType(found)) "" else "\n" + + s"""|Note that $what. + |Such types can participate in value classes, but instances + |cannot appear in singleton types or in reference comparisons.""".stripMargin + } + import ErrorUtils._ trait TyperContextErrors { @@ -296,12 +319,17 @@ trait ContextErrors { else "" ) - companion + semicolon + val notAnyRef = ( + if (ObjectClass.info.member(name).exists) notAnyRefMessage(target) + else "" + ) + companion + notAnyRef + semicolon } + def targetStr = targetKindString + target.directObjectString withAddendum(qual.pos)( - if (name == nme.CONSTRUCTOR) target + " does not have a constructor" - else nameString + " is not a member of " + targetKindString + target.directObjectString + addendum - ) + if (name == nme.CONSTRUCTOR) s"$target does not have a constructor" + else s"$nameString is not a member of $targetStr$addendum" + ) } issueNormalTypeError(sel, errMsg) // the error has to be set for the copied tree, otherwise @@ -1095,44 +1123,42 @@ trait ContextErrors { pre1: String, pre2: String, trailer: String) (isView: Boolean, pt: Type, tree: Tree)(implicit context0: Context) = { if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) { - val coreMsg = - pre1+" "+info1.sym.fullLocationString+" of type "+info1.tpe+"\n "+ - pre2+" "+info2.sym.fullLocationString+" of type "+info2.tpe+"\n "+ - trailer - val errMsg = - if (isView) { - val found = pt.typeArgs(0) - val req = pt.typeArgs(1) - def defaultExplanation = - "Note that implicit conversions are not applicable because they are ambiguous:\n "+ - coreMsg+"are possible conversion functions from "+ found+" to "+req - - def explanation = { - val sym = found.typeSymbol - // Explain some common situations a bit more clearly. - if (AnyRefClass.tpe <:< req) { - if (sym == AnyClass || sym == UnitClass) { - "Note: " + sym.name + " is not implicitly converted to AnyRef. You can safely\n" + - "pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so." - } - else boxedClass get sym match { - case Some(boxed) => - "Note: an implicit exists from " + sym.fullName + " => " + boxed.fullName + ", but\n" + - "methods inherited from Object are rendered ambiguous. This is to avoid\n" + - "a blanket implicit which would convert any " + sym.fullName + " to any AnyRef.\n" + - "You may wish to use a type ascription: `x: " + boxed.fullName + "`." - case _ => - defaultExplanation - } - } - else defaultExplanation - } - - typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req)) + "\n" + explanation - } else { - "ambiguous implicit values:\n "+coreMsg + "match expected type "+pt + def coreMsg = + s"""| $pre1 ${info1.sym.fullLocationString} of type ${info1.tpe} + | $pre2 ${info2.sym.fullLocationString} of type ${info2.tpe} + | $trailer""".stripMargin + def viewMsg = { + val found :: req :: _ = pt.typeArgs + def explanation = { + val sym = found.typeSymbol + // Explain some common situations a bit more clearly. Some other + // failures which have nothing to do with implicit conversions + // per se, but which manifest as implicit conversion conflicts + // involving Any, are further explained from foundReqMsg. + if (AnyRefClass.tpe <:< req) ( + if (sym == AnyClass || sym == UnitClass) ( + s"""|Note: ${sym.name} is not implicitly converted to AnyRef. You can safely + |pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so.""".stripMargin + ) + else boxedClass get sym map (boxed => + s"""|Note: an implicit exists from ${sym.fullName} => ${boxed.fullName}, but + |methods inherited from Object are rendered ambiguous. This is to avoid + |a blanket implicit which would convert any ${sym.fullName} to any AnyRef. + |You may wish to use a type ascription: `x: ${boxed.fullName}`.""".stripMargin + ) getOrElse "" + ) + else + s"""|Note that implicit conversions are not applicable because they are ambiguous: + |${coreMsg}are possible conversion functions from $found to $req""".stripMargin } - context.issueAmbiguousError(AmbiguousTypeError(tree, tree.pos, errMsg)) + typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req)) + ( + if (explanation == "") "" else "\n" + explanation + ) + } + context.issueAmbiguousError(AmbiguousTypeError(tree, tree.pos, + if (isView) viewMsg + else s"ambiguous implicit values:\n${coreMsg}match expected type $pt") + ) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 226e17f605..6a91922b4c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -593,7 +593,7 @@ trait Implicits { typed1(itree, EXPRmode, wildPt) if (context.hasErrors) - return fail("typed implicit %s has errors".format(info.sym.fullLocationString)) + return fail(context.errBuffer.head.errMsg) if (Statistics.canEnable) Statistics.incCounter(typedImplicits) @@ -615,7 +615,7 @@ trait Implicits { } if (context.hasErrors) - fail("hasMatchingSymbol reported threw error(s)") + fail("hasMatchingSymbol reported error: " + context.errBuffer.head.errMsg) else if (isLocal && !hasMatchingSymbol(itree1)) fail("candidate implicit %s is shadowed by %s".format( info.sym.fullLocationString, itree1.symbol.fullLocationString)) @@ -639,7 +639,7 @@ trait Implicits { // #2421: check that we correctly instantiated type parameters outside of the implicit tree: checkBounds(itree2, NoPrefix, NoSymbol, undetParams, targs, "inferred ") if (context.hasErrors) - return fail("type parameters weren't correctly instantiated outside of the implicit tree") + return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + context.errBuffer.head.errMsg) // filter out failures from type inference, don't want to remove them from undetParams! // we must be conservative in leaving type params in undetparams @@ -675,7 +675,7 @@ trait Implicits { } if (context.hasErrors) - fail("typing TypeApply reported errors for the implicit tree") + fail("typing TypeApply reported errors for the implicit tree: " + context.errBuffer.head.errMsg) else { val result = new SearchResult(itree2, subst) if (Statistics.canEnable) Statistics.incCounter(foundImplicits) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 28636fc76e..1b3602fca2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -280,7 +280,16 @@ trait Infer { def issue(err: AbsTypeError): Unit = context.issue(err) - def isPossiblyMissingArgs(found: Type, req: Type) = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req) + def isPossiblyMissingArgs(found: Type, req: Type) = ( + false + /** However it is that this condition is expected to imply + * "is possibly missing args", it is too weak. It is + * better to say nothing than to offer misleading guesses. + + (found.resultApprox ne found) + && isWeaklyCompatible(found.resultApprox, req) + */ + ) def explainTypes(tp1: Type, tp2: Type) = withDisambiguation(List(), tp1, tp2)(global.explainTypes(tp1, tp2)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 77d1260564..adced9d8c9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -192,6 +192,10 @@ trait Namers extends MethodSynthesis { if (!allowsOverload(sym)) { val prev = scope.lookupEntry(sym.name) if ((prev ne null) && prev.owner == scope && conflict(sym, prev.sym)) { + if (sym.isSynthetic || prev.sym.isSynthetic) { + handleSyntheticNameConflict(sym, prev.sym) + handleSyntheticNameConflict(prev.sym, sym) + } DoubleDefError(sym, prev.sym) sym setInfo ErrorType scope unlink prev.sym // let them co-exist... @@ -202,6 +206,14 @@ trait Namers extends MethodSynthesis { scope enter sym } + /** Logic to handle name conflicts of synthetically generated symbols + * We handle right now: t6227 + */ + def handleSyntheticNameConflict(sym1: Symbol, sym2: Symbol) = { + if (sym1.isImplicit && sym1.isMethod && sym2.isModule && sym2.companionClass.isCaseClass) + validate(sym2.companionClass) + } + def enterSym(tree: Tree): Context = { def dispatch() = { var returnContext = this.context @@ -1390,6 +1402,7 @@ trait Namers extends MethodSynthesis { fail(ImplicitAtToplevel) } if (sym.isClass) { + checkNoConflict(IMPLICIT, CASE) if (sym.isAnyOverride && !sym.hasFlag(TRAIT)) fail(OverrideClass) } else { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 9201981635..166bb2d18c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1618,6 +1618,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R if ((clazz isSubClass AnyValClass) && !isPrimitiveValueClass(clazz)) { if (clazz.isTrait) unit.error(clazz.pos, "Only classes (not traits) are allowed to extend AnyVal") + else if ((clazz != AnyValClass) && clazz.hasFlag(ABSTRACT)) + unit.error(clazz.pos, "`abstract' modifier cannot be used with value classes") } } diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index f0dca64a00..f8a5c401df 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -252,6 +252,13 @@ trait TypeDiagnostics { } "" // no elaborable variance situation found } + + // For found/required errors where AnyRef would have sufficed: + // explain in greater detail. + def explainAnyVsAnyRef(found: Type, req: Type): String = { + if (AnyRefClass.tpe <:< req) notAnyRefMessage(found) else "" + } + // TODO - figure out how to avoid doing any work at all // when the message will never be seen. I though context.reportErrors // being false would do that, but if I return "<suppressed>" under @@ -261,7 +268,10 @@ trait TypeDiagnostics { ";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) + "\n required: " + req + existentialContext(req) + explainAlias(req) ) - withDisambiguation(Nil, found, req)(baseMessage) + explainVariance(found, req) + ( withDisambiguation(Nil, found, req)(baseMessage) + + explainVariance(found, req) + + explainAnyVsAnyRef(found, req) + ) } case class TypeDiag(tp: Type, sym: Symbol) extends Ordered[TypeDiag] { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f6baf02c3e..b6dab13111 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -233,10 +233,11 @@ trait Typers extends Modes with Adaptations with Tags { * @param tree ... * @return ... */ - def checkStable(tree: Tree): Tree = + def checkStable(tree: Tree): Tree = ( if (treeInfo.isExprSafeToInline(tree)) tree else if (tree.isErrorTyped) tree else UnstableTreeError(tree) + ) /** Would tree be a stable (i.e. a pure expression) if the type * of its symbol was not volatile? @@ -5201,7 +5202,10 @@ trait Typers extends Modes with Adaptations with Tags { def typedSingletonTypeTree(tree: SingletonTypeTree) = { val ref1 = checkStable( - typed(tree.ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe)) + context.withImplicitsDisabled( + typed(tree.ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe) + ) + ) tree setType ref1.tpe.resultType } diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala index 270581a3aa..d470f4c966 100644 --- a/src/library/scala/Function.scala +++ b/src/library/scala/Function.scala @@ -28,11 +28,11 @@ object Function { /** Turns a function `A => Option[B]` into a `PartialFunction[A, B]`. * - * TODO: check if the paragraph below is still correct * '''Important note''': this transformation implies the original function - * will be called 2 or more times on each logical invocation, because the + * may be called 2 or more times on each logical invocation, because the * only way to supply an implementation of `isDefinedAt` is to call the * function and examine the return value. + * See also [[scala.PartialFunction]], method `applyOrElse`. * * @param f a function `T => Option[R]` * @return a partial function defined for those inputs where diff --git a/src/library/scala/LowPriorityImplicits.scala b/src/library/scala/LowPriorityImplicits.scala index 491cd417a3..8c49d2f67b 100644 --- a/src/library/scala/LowPriorityImplicits.scala +++ b/src/library/scala/LowPriorityImplicits.scala @@ -27,15 +27,20 @@ class LowPriorityImplicits { * any potential conflicts. Conflicts do exist because the wrappers * need to implement ScalaNumber in order to have a symmetric equals * method, but that implies implementing java.lang.Number as well. + * + * Note - these are inlined because they are value classes, but + * the call to xxxWrapper is not eliminated even though it does nothing. + * Even inlined, every call site does a no-op retrieval of Predef's MODULE$ + * because maybe loading Predef has side effects! */ - implicit def byteWrapper(x: Byte) = new runtime.RichByte(x) - implicit def shortWrapper(x: Short) = new runtime.RichShort(x) - implicit def intWrapper(x: Int) = new runtime.RichInt(x) - implicit def charWrapper(c: Char) = new runtime.RichChar(c) - implicit def longWrapper(x: Long) = new runtime.RichLong(x) - implicit def floatWrapper(x: Float) = new runtime.RichFloat(x) - implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x) - implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x) + @inline implicit def byteWrapper(x: Byte) = new runtime.RichByte(x) + @inline implicit def shortWrapper(x: Short) = new runtime.RichShort(x) + @inline implicit def intWrapper(x: Int) = new runtime.RichInt(x) + @inline implicit def charWrapper(c: Char) = new runtime.RichChar(c) + @inline implicit def longWrapper(x: Long) = new runtime.RichLong(x) + @inline implicit def floatWrapper(x: Float) = new runtime.RichFloat(x) + @inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x) + @inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x) // These eight implicits exist solely to exclude Null from the domain of // the boxed types, so that e.g. "var x: Int = null" is a compile time diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index 7154b8da34..d0a339bdd5 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -67,7 +67,7 @@ trait PartialFunction[-A, +B] extends (A => B) { self => * of this partial function and `that`. The resulting partial function * takes `x` to `this(x)` where `this` is defined, and to `that(x)` where it is not. */ - def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = + def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = new OrElse[A1, B1] (this, that) //TODO: why not overload it with orElse(that: F1): F1? @@ -78,10 +78,8 @@ trait PartialFunction[-A, +B] extends (A => B) { self => * @return a partial function with the same domain as this partial function, which maps * arguments `x` to `k(this(x))`. */ - override def andThen[C](k: B => C) : PartialFunction[A, C] = new PartialFunction[A, C] { - def isDefinedAt(x: A): Boolean = self isDefinedAt x - def apply(x: A): C = k(self(x)) - } + override def andThen[C](k: B => C): PartialFunction[A, C] = + new AndThen[A, B, C] (this, k) /** Turns this partial function into an plain function returning an `Option` result. * @see Function.unlift @@ -90,28 +88,54 @@ trait PartialFunction[-A, +B] extends (A => B) { self => */ def lift: A => Option[B] = new Lifted(this) - /** - * TODO: comment + /** Applies this partial function to the given argument when it is contained in the function domain. + * Applies fallback function where this partial function is not defined. + * + * Note that expression `pf.applyOrElse(x, default)` is equivalent to + * {{{ if(pf isDefinedAt x) pf(x) else default(x) }}} + * except that `applyOrElse` method can be implemented more efficiently. + * For all partial function literals compiler generates `applyOrElse` implementation which + * avoids double evaluation of pattern matchers and guards. + * This makes `applyOrElse` the basis for the efficient implementation for many operations and scenarios, such as: + * + * - combining partial functions into `orElse`/`andThen` chains does not lead to + * excessive `apply`/`isDefinedAt` evaluation + * - `lift` and `unlift` do not evaluate source functions twice on each invocation + * - `runWith` allows efficient imperative-style combining of partial functions + * with conditionally applied actions + * + * For non-literal partial function classes with nontrivial `isDefinedAt` method + * it is recommended to override `applyOrElse` with custom implementation that avoids + * double `isDefinedAt` evaluation. This may result in better performance + * and more predictable behavior w.r.t. side effects. + * + * @param x the function argument + * @param default the fallback function + * @return the result of this function or fallback function application. * @since 2.10 */ def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = if (isDefinedAt(x)) apply(x) else default(x) - /** - * TODO: comment - * @since 2.10 - */ - def run[U](x: A)(action: B => U): Boolean = - applyOrElse(x, fallbackToken) match { - case FallbackToken => false - case z => action(z); true - } - - /** - * TODO: comment + /** Composes this partial function with an action function which + * gets applied to results of this partial function. + * The action function is invoked only for its side effects; its result is ignored. + * + * Note that expression `pf.runWith(action)(x)` is equivalent to + * {{{ if(pf isDefinedAt x) { action(pf(x)); true } else false }}} + * except that `runWith` is implemented via `applyOrElse` and thus potentially more efficient. + * Using `runWith` avoids double evaluation of pattern matchers and guards for partial function literals. + * @see `applyOrElse`. + * + * @param action the action function + * @return a function which maps arguments `x` to `isDefinedAt(x)`. The resulting function + * runs `action(this(x))` where `this` is defined. * @since 2.10 */ - def runWith[U](action: B => U): A => Boolean = { x => run(x)(action) } + def runWith[U](action: B => U): A => Boolean = { x => + val z = applyOrElse(x, checkFallback[B]) + if (!fallbackOccurred(z)) { action(z); true } else false + } } /** A few handy operations which leverage the extra bit of information @@ -137,11 +161,10 @@ object PartialFunction { def apply(x: A): B = f1.applyOrElse(x, f2) - override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = - f1.applyOrElse(x, fallbackToken) match { - case FallbackToken => f2.applyOrElse(x, default) - case z => z - } + override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = { + val z = f1.applyOrElse(x, checkFallback[B]) + if (!fallbackOccurred(z)) z else f2.applyOrElse(x, default) + } override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) = new OrElse[A1, B1] (f1, f2 orElse that) @@ -150,23 +173,61 @@ object PartialFunction { new OrElse[A, C] (f1 andThen k, f2 andThen k) } - private[scala] lazy val FallbackToken: PartialFunction[Any, PartialFunction[Any, Nothing]] = { case _ => FallbackToken.asInstanceOf[PartialFunction[Any, Nothing]] } - private[scala] final def fallbackToken[B] = FallbackToken.asInstanceOf[PartialFunction[Any, B]] - //TODO: check generated code for PF literal here + /** Composite function produced by `PartialFunction#andThen` method + */ + private final class AndThen[-A, B, +C] (pf: PartialFunction[A, B], k: B => C) extends PartialFunction[A, C] { + def isDefinedAt(x: A) = pf.isDefinedAt(x) + + def apply(x: A): C = k(pf(x)) + + override def applyOrElse[A1 <: A, C1 >: C](x: A1, default: A1 => C1): C1 = { + val z = pf.applyOrElse(x, checkFallback[B]) + if (!fallbackOccurred(z)) k(z) else default(x) + } + } + + /** To implement patterns like {{{ if(pf isDefinedAt x) f1(pf(x)) else f2(x) }}} efficiently + * the following trick is used: + * + * To avoid double evaluation of pattern matchers & guards `applyOrElse` method is used here + * instead of `isDefinedAt`/`apply` pair. + * + * After call to `applyOrElse` we need both the function result it returned and + * the fact if the function's argument was contained in its domain. The only degree of freedom we have here + * to achieve this goal is tweaking with the continuation argument (`default`) of `applyOrElse` method. + * The obvious way is to throw an exception from `default` function and to catch it after + * calling `applyOrElse` but I consider this somewhat inefficient. + * + * I know only one way how you can do this task efficiently: `default` function should return unique marker object + * which never may be returned by any other (regular/partial) function. This way after calling `applyOrElse` you need + * just one reference comparison to distinguish if `pf isDefined x` or not. + * + * This correctly interacts with specialization as return type of `applyOrElse` + * (which is parameterized upper bound) can never be specialized. + * + * Here `fallback_pf` is used as both unique marker object and special fallback function that returns it. + */ + private[this] final val fallback_pf: PartialFunction[Any, Any] = { case _ => fallback_pf } + @inline private final def checkFallback[B] = fallback_pf.asInstanceOf[PartialFunction[Any, B]] + @inline private final def fallbackOccurred[B](x: B) = (fallback_pf eq x.asInstanceOf[AnyRef]) - private[scala] final class Lifted[-A, +B] (val pf: PartialFunction[A, B]) + private final class Lifted[-A, +B] (val pf: PartialFunction[A, B]) extends runtime.AbstractFunction1[A, Option[B]] { - def apply(x: A): Option[B] = pf.applyOrElse(x, fallbackToken) match { - case FallbackToken => None - case z => Some(z) + def apply(x: A): Option[B] = { + val z = pf.applyOrElse(x, checkFallback[B]) + if (!fallbackOccurred(z)) Some(z) else None } } private final class Unlifted[A, B] (f: A => Option[B]) extends runtime.AbstractPartialFunction[A, B] { def isDefinedAt(x: A): Boolean = f(x).isDefined - override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = - f(x) getOrElse default(x) //TODO: check generated code and inline getOrElse if needed + + override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = { + val z = f(x) + if (!z.isEmpty) z.get else default(x) + } + override def lift = f } @@ -178,7 +239,6 @@ object PartialFunction { /** Converts ordinary function to partial one * @since 2.10 */ - //TODO: check generated code for PF literal here def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) } private[this] final val constFalse: Any => Boolean = { _ => false} @@ -189,12 +249,11 @@ object PartialFunction { override def orElse[A1, B1](that: PartialFunction[A1, B1]) = that override def andThen[C](k: Nothing => C) = this override val lift = (x: Any) => None - override def run[U](x: Any)(action: Nothing => U) = false override def runWith[U](action: Nothing => U) = constFalse } - /** - * TODO: comment + /** The partial function with empty domain. + * Any attempt to invoke empty partial function leads to throwing [[scala.MatchError]] exception. * @since 2.10 */ def empty[A, B] : PartialFunction[A, B] = empty_pf diff --git a/src/library/scala/collection/CustomParallelizable.scala b/src/library/scala/collection/CustomParallelizable.scala index dc634c67d3..a56cb5da59 100644 --- a/src/library/scala/collection/CustomParallelizable.scala +++ b/src/library/scala/collection/CustomParallelizable.scala @@ -10,7 +10,7 @@ package scala.collection import parallel.Combiner -trait CustomParallelizable[+A, +ParRepr <: Parallel] extends Parallelizable[A, ParRepr] { +trait CustomParallelizable[+A, +ParRepr <: Parallel] extends Any with Parallelizable[A, ParRepr] { override def par: ParRepr override protected[this] def parCombiner: Combiner[A, ParRepr] = throw new UnsupportedOperationException("") } diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 0b297aeb45..b41327ed95 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -146,6 +146,29 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { private object EmptyHashMap extends HashMap[Any, Nothing] { } + // utility method to create a HashTrieMap from two leaf HashMaps (HashMap1 or HashMapCollision1) with non-colliding hash code) + private def makeHashTrieMap[A, B](hash0:Int, elem0:HashMap[A, B], hash1:Int, elem1:HashMap[A, B], level:Int, size:Int) : HashTrieMap[A, B] = { + val index0 = (hash0 >>> level) & 0x1f + val index1 = (hash1 >>> level) & 0x1f + if(index0 != index1) { + val bitmap = (1 << index0) | (1 << index1) + val elems = new Array[HashMap[A,B]](2) + if(index0 < index1) { + elems(0) = elem0 + elems(1) = elem1 + } else { + elems(0) = elem1 + elems(1) = elem0 + } + new HashTrieMap[A, B](bitmap, elems, size) + } else { + val elems = new Array[HashMap[A,B]](1) + val bitmap = (1 << index0) + elems(0) = makeHashTrieMap(hash0, elem0, hash1, elem1, level + 5, size) + new HashTrieMap[A, B](bitmap, elems, size) + } + } + // TODO: add HashMap2, HashMap3, ... class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { @@ -183,30 +206,10 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { new HashMap1(nkv._1, hash, nkv._2, nkv) } } else { - var thatindex = (hash >>> level) & 0x1f - var thisindex = (this.hash >>> level) & 0x1f if (hash != this.hash) { // they have different hashes, but may collide at this level - find a level at which they don't - var lvl = level - var top: HashTrieMap[A, B1] = null - var prev: HashTrieMap[A, B1] = null - while (thisindex == thatindex) { - val newlevel = new HashTrieMap[A, B1](1 << thisindex, new Array[HashMap[A, B1]](1), 2) - if (prev ne null) prev.elems(0) = newlevel else top = newlevel - prev = newlevel - lvl += 5 - thatindex = (hash >>> lvl) & 0x1f - thisindex = (this.hash >>> lvl) & 0x1f - } - val bottelems = new Array[HashMap[A,B1]](2) - val ind = if (thisindex < thatindex) 1 else 0 - bottelems(1 - ind) = this - bottelems(ind) = new HashMap1[A, B1](key, hash, value, kv) - val bottom = new HashTrieMap[A,B1]((1 << thisindex) | (1 << thatindex), bottelems, 2) - if (prev ne null) { - prev.elems(0) = bottom - top - } else bottom + val that = new HashMap1[A, B1](key, hash, value, kv) + makeHashTrieMap[A,B1](this.hash, this, hash, that, level, 2) } else { // 32-bit hash collision (rare, but not impossible) new HashMapCollision1(hash, ListMap.empty.updated(this.key,this.value).updated(key,value)) @@ -221,12 +224,13 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { // this method may be called multiple times in a multithreaded environment, but that's ok private[HashMap] def ensurePair: (A,B) = if (kv ne null) kv else { kv = (key, value); kv } protected override def merge0[B1 >: B](that: HashMap[A, B1], level: Int, merger: Merger[A, B1]): HashMap[A, B1] = { - that.updated0(key, hash, level, value, kv, if (merger ne null) merger.invert else null) + that.updated0(key, hash, level, value, kv, merger.invert) } } private[collection] class HashMapCollision1[A, +B](private[collection] val hash: Int, val kvs: ListMap[A, B @uV]) extends HashMap[A, B @uV] { + // assert(kvs.size > 1) override def size = kvs.size @@ -238,20 +242,20 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { if ((merger eq null) || !kvs.contains(key)) new HashMapCollision1(hash, kvs.updated(key, value)) else new HashMapCollision1(hash, kvs + merger((key, kvs(key)), kv)) } else { - var m: HashMap[A,B1] = new HashTrieMap[A,B1](0,new Array[HashMap[A,B1]](0),0) - // might be able to save some ops here, but it doesn't seem to be worth it - for ((k,v) <- kvs) - m = m.updated0(k, this.hash, level, v, null, merger) - m.updated0(key, hash, level, value, kv, merger) + val that = new HashMap1(key, hash, value, kv) + makeHashTrieMap(this.hash, this, hash, that, level, size + 1) } override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = if (hash == this.hash) { val kvs1 = kvs - key - if (!kvs1.isEmpty) - new HashMapCollision1(hash, kvs1) - else + if (kvs1.isEmpty) HashMap.empty[A,B] + else if(kvs1.tail.isEmpty) { + val kv = kvs1.head + new HashMap1[A,B](kv._1,hash,kv._2,kv) + } else + new HashMapCollision1(hash, kvs1) } else this override def iterator: Iterator[(A,B)] = kvs.iterator @@ -275,6 +279,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { private[collection] val size0: Int ) extends HashMap[A, B @uV] { + // assert(Integer.bitCount(bitmap) == elems.length) + // assert(elems.length > 1 || (elems.length == 1 && elems(0).isInstanceOf[HashTrieMap[_,_]])) + /* def this (level: Int, m1: HashMap1[A,B], m2: HashMap1[A,B]) = { this(((m1.hash >>> level) & 0x1f) | ((m2.hash >>> level) & 0x1f), { @@ -347,9 +354,14 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { Array.copy(elems, 0, elemsNew, 0, offset) Array.copy(elems, offset + 1, elemsNew, offset, elems.length - offset - 1) val sizeNew = size - sub.size - new HashTrieMap(bitmapNew, elemsNew, sizeNew) + if (elemsNew.length == 1 && !elemsNew(0).isInstanceOf[HashTrieMap[_,_]]) + elemsNew(0) + else + new HashTrieMap(bitmapNew, elemsNew, sizeNew) } else HashMap.empty[A,B] + } else if(elems.length == 1 && !subNew.isInstanceOf[HashTrieMap[_,_]]) { + subNew } else { val elemsNew = new Array[HashMap[A,B]](elems.length) Array.copy(elems, 0, elemsNew, 0, elems.length) @@ -480,7 +492,7 @@ time { mNew.iterator.foreach( p => ()) } } new HashTrieMap[A, B1](this.bitmap | that.bitmap, merged, totalelems) - case hm: HashMapCollision1[_, _] => that.merge0(this, level, if (merger ne null) merger.invert else null) + case hm: HashMapCollision1[_, _] => that.merge0(this, level, merger.invert) case hm: HashMap[_, _] => this case _ => sys.error("section supposed to be unreachable.") } diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index ef0173337c..d9ce7a68f7 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -102,6 +102,30 @@ object HashSet extends ImmutableSetFactory[HashSet] { private object EmptyHashSet extends HashSet[Any] { } + // utility method to create a HashTrieSet from two leaf HashSets (HashSet1 or HashSetCollision1) with non-colliding hash code) + private def makeHashTrieSet[A](hash0:Int, elem0:HashSet[A], hash1:Int, elem1:HashSet[A], level:Int) : HashTrieSet[A] = { + val index0 = (hash0 >>> level) & 0x1f + val index1 = (hash1 >>> level) & 0x1f + if(index0 != index1) { + val bitmap = (1 << index0) | (1 << index1) + val elems = new Array[HashSet[A]](2) + if(index0 < index1) { + elems(0) = elem0 + elems(1) = elem1 + } else { + elems(0) = elem1 + elems(1) = elem0 + } + new HashTrieSet[A](bitmap, elems, elem0.size + elem1.size) + } else { + val elems = new Array[HashSet[A]](1) + val bitmap = (1 << index0) + val child = makeHashTrieSet(hash0, elem0, hash1, elem1, level + 5) + elems(0) = child + new HashTrieSet[A](bitmap, elems, child.size) + } + } + // TODO: add HashSet2, HashSet3, ... class HashSet1[A](private[HashSet] val key: A, private[HashSet] val hash: Int) extends HashSet[A] { @@ -114,9 +138,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { if (hash == this.hash && key == this.key) this else { if (hash != this.hash) { - //new HashTrieSet[A](level+5, this, new HashSet1(key, hash)) - val m = new HashTrieSet[A](0,new Array[HashSet[A]](0),0) // TODO: could save array alloc - m.updated0(this.key, this.hash, level).updated0(key, hash, level) + makeHashTrieSet(this.hash, this, hash, new HashSet1(key, hash), level) } else { // 32-bit hash collision (rare, but not impossible) new HashSetCollision1(hash, ListSet.empty + this.key + key) @@ -140,13 +162,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) new HashSetCollision1(hash, ks + key) - else { - var m: HashSet[A] = new HashTrieSet[A](0,new Array[HashSet[A]](0),0) - // might be able to save some ops here, but it doesn't seem to be worth it - for (k <- ks) - m = m.updated0(k, this.hash, level) - m.updated0(key, hash, level) - } + else makeHashTrieSet(this.hash, this, hash, new HashSet1(key, hash), level) override def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) { @@ -181,6 +197,9 @@ object HashSet extends ImmutableSetFactory[HashSet] { class HashTrieSet[A](private val bitmap: Int, private[collection] val elems: Array[HashSet[A]], private val size0: Int) extends HashSet[A] { + assert(Integer.bitCount(bitmap) == elems.length) + // assertion has to remain disabled until SI-6197 is solved + // assert(elems.length > 1 || (elems.length == 1 && elems(0).isInstanceOf[HashTrieSet[_]])) override def size = size0 diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala index 091443f909..c21032603f 100644 --- a/src/library/scala/collection/immutable/ListMap.scala +++ b/src/library/scala/collection/immutable/ListMap.scala @@ -121,12 +121,12 @@ extends AbstractMap[A, B] def hasNext = !self.isEmpty def next(): (A,B) = if (!hasNext) throw new NoSuchElementException("next on empty iterator") - else { val res = (self.key, self.value); self = self.next; res } + else { val res = (self.key, self.value); self = self.tail; res } }.toList.reverseIterator protected def key: A = throw new NoSuchElementException("empty map") protected def value: B = throw new NoSuchElementException("empty map") - protected def next: ListMap[A, B] = throw new NoSuchElementException("empty map") + override def tail: ListMap[A, B] = throw new NoSuchElementException("empty map") /** This class represents an entry in the `ListMap`. */ @@ -140,7 +140,7 @@ extends AbstractMap[A, B] override def size: Int = size0(this, 0) // to allow tail recursion and prevent stack overflows - @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.next, acc + 1) + @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.tail, acc + 1) /** Is this an empty map? * @@ -157,7 +157,7 @@ extends AbstractMap[A, B] */ override def apply(k: A): B1 = apply0(this, k) - @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = if (k == cur.key) cur.value else apply0(cur.next, k) + @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = if (k == cur.key) cur.value else apply0(cur.tail, k) /** Checks if this map maps `key` to a value and return the * value if it exists. @@ -169,7 +169,7 @@ extends AbstractMap[A, B] @tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] = if (k == cur.key) Some(cur.value) - else if (cur.next.nonEmpty) get0(cur.next, k) else None + else if (cur.tail.nonEmpty) get0(cur.tail, k) else None /** This method allows one to create a new map with an additional mapping * from `key` to `value`. If the map contains already a mapping for `key`, @@ -198,7 +198,7 @@ extends AbstractMap[A, B] var lst: List[(A, B1)] = Nil while (cur.nonEmpty) { if (k != cur.key) lst ::= ((cur.key, cur.value)) - cur = cur.next + cur = cur.tail } var acc = ListMap[A, B1]() while (lst != Nil) { @@ -211,6 +211,6 @@ extends AbstractMap[A, B] } - override protected def next: ListMap[A, B1] = ListMap.this + override def tail: ListMap[A, B1] = ListMap.this } } diff --git a/src/library/scala/collection/mutable/ArrayLike.scala b/src/library/scala/collection/mutable/ArrayLike.scala index 04601845c4..172993c5c3 100644 --- a/src/library/scala/collection/mutable/ArrayLike.scala +++ b/src/library/scala/collection/mutable/ArrayLike.scala @@ -22,7 +22,7 @@ import generic._ * @version 2.8 * @since 2.8 */ -trait ArrayLike[A, +Repr] extends IndexedSeqOptimized[A, Repr] { self => +trait ArrayLike[A, +Repr] extends Any with IndexedSeqOptimized[A, Repr] { self => /** Creates a possible nested `IndexedSeq` which consists of all the elements * of this array. If the elements are arrays themselves, the `deep` transformation diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 21c2aaaec7..b3cd6a95c5 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -6,18 +6,14 @@ ** |/ ** \* */ - - package scala.collection package mutable -import compat.Platform.arraycopy +import compat.Platform.arraycopy import scala.reflect.ClassTag import scala.runtime.ScalaRunTime._ - import parallel.mutable.ParArray - /** This class serves as a wrapper for `Array`s with all the operations found in * indexed sequences. Where needed, instances of arrays are implicitly converted * into this class. @@ -36,7 +32,7 @@ import parallel.mutable.ParArray * @define mayNotTerminateInf * @define willNotTerminateInf */ -abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] { +trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] { private def elementClass: Class[_] = arrayElementClass(repr.getClass) @@ -105,7 +101,7 @@ abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with CustomParalleliza object ArrayOps { /** A class of `ArrayOps` for arrays containing reference types. */ - class ofRef[T <: AnyRef](override val repr: Array[T]) extends ArrayOps[T] with ArrayLike[T, Array[T]] { + final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] { override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr) override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr) @@ -117,7 +113,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `byte`s. */ - class ofByte(override val repr: Array[Byte]) extends ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { +final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr) @@ -129,7 +125,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `short`s. */ - class ofShort(override val repr: Array[Short]) extends ArrayOps[Short] with ArrayLike[Short, Array[Short]] { +final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr) @@ -141,7 +137,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `char`s. */ - class ofChar(override val repr: Array[Char]) extends ArrayOps[Char] with ArrayLike[Char, Array[Char]] { +final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr) @@ -153,7 +149,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `int`s. */ - class ofInt(override val repr: Array[Int]) extends ArrayOps[Int] with ArrayLike[Int, Array[Int]] { +final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr) @@ -165,7 +161,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `long`s. */ - class ofLong(override val repr: Array[Long]) extends ArrayOps[Long] with ArrayLike[Long, Array[Long]] { +final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr) @@ -177,7 +173,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `float`s. */ - class ofFloat(override val repr: Array[Float]) extends ArrayOps[Float] with ArrayLike[Float, Array[Float]] { +final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr) @@ -189,7 +185,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `double`s. */ - class ofDouble(override val repr: Array[Double]) extends ArrayOps[Double] with ArrayLike[Double, Array[Double]] { +final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr) @@ -201,7 +197,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays containing `boolean`s. */ - class ofBoolean(override val repr: Array[Boolean]) extends ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { +final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) @@ -213,7 +209,7 @@ object ArrayOps { } /** A class of `ArrayOps` for arrays of `Unit` types. */ - class ofUnit(override val repr: Array[Unit]) extends ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { +final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr) diff --git a/src/library/scala/collection/mutable/DoubleLinkedList.scala b/src/library/scala/collection/mutable/DoubleLinkedList.scala index cba4e9725e..b7c5f07502 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedList.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedList.scala @@ -63,6 +63,13 @@ class DoubleLinkedList[A]() extends AbstractSeq[A] } override def companion: GenericCompanion[DoubleLinkedList] = DoubleLinkedList + + // Accurately clone this collection. See SI-6296 + override def clone(): DoubleLinkedList[A] = { + val builder = newBuilder + builder ++= this + builder.result + } } /** $factoryInfo diff --git a/src/library/scala/collection/mutable/IndexedSeqLike.scala b/src/library/scala/collection/mutable/IndexedSeqLike.scala index 5d4b4de7b2..b3fe95ef27 100644 --- a/src/library/scala/collection/mutable/IndexedSeqLike.scala +++ b/src/library/scala/collection/mutable/IndexedSeqLike.scala @@ -36,7 +36,7 @@ import generic._ * @define willNotTerminateInf * @define mayNotTerminateInf */ -trait IndexedSeqLike[A, +Repr] extends scala.collection.IndexedSeqLike[A, Repr] { self => +trait IndexedSeqLike[A, +Repr] extends Any with scala.collection.IndexedSeqLike[A, Repr] { self => override protected[this] def thisCollection: IndexedSeq[A] = this.asInstanceOf[IndexedSeq[A]] override protected[this] def toCollection(repr: Repr): IndexedSeq[A] = repr.asInstanceOf[IndexedSeq[A]] diff --git a/src/library/scala/collection/mutable/IndexedSeqOptimized.scala b/src/library/scala/collection/mutable/IndexedSeqOptimized.scala index 819d06476a..506d2d6736 100755 --- a/src/library/scala/collection/mutable/IndexedSeqOptimized.scala +++ b/src/library/scala/collection/mutable/IndexedSeqOptimized.scala @@ -17,4 +17,4 @@ import generic._ * * @since 2.8 */ -trait IndexedSeqOptimized[A, +Repr] extends IndexedSeqLike[A, Repr] with scala.collection.IndexedSeqOptimized[A, Repr] +trait IndexedSeqOptimized[A, +Repr] extends Any with IndexedSeqLike[A, Repr] with scala.collection.IndexedSeqOptimized[A, Repr] diff --git a/src/library/scala/language.scala b/src/library/scala/language.scala index df2eb0b910..dfe27f8857 100644 --- a/src/library/scala/language.scala +++ b/src/library/scala/language.scala @@ -17,7 +17,7 @@ object language { * of programs. Furthermore, dynamic member selection often relies on reflection, * which is not available on all platforms. */ - implicit lazy val dynamics: dynamics = ??? + implicit lazy val dynamics: dynamics = languageFeature.dynamics /** Only where enabled, postfix operator notation `(expr op)` will be allowed. * @@ -26,7 +26,7 @@ object language { * _Why control it?_ Postfix operators interact poorly with semicolon inference. * Most programmers avoid them for this reason. */ - implicit lazy val postfixOps: postfixOps = ??? + implicit lazy val postfixOps: postfixOps = languageFeature.postfixOps /** Only where enabled, accesses to members of structural types that need * reflection are supported. Reminder: A structural type is a type of the form @@ -42,7 +42,7 @@ object language { * such as ProGuard have problems dealing with it. Even where reflection is available, * reflective dispatch can lead to surprising performance degradations. */ - implicit lazy val reflectiveCalls: reflectiveCalls = ??? + implicit lazy val reflectiveCalls: reflectiveCalls = languageFeature.reflectiveCalls /** Only where enabled, definitions of implicit conversions are allowed. An * implicit conversion is an implicit value of unary function type `A => B`, @@ -65,7 +65,7 @@ object language { * most situations using implicit parameters leads to a better design than * implicit conversions. */ - implicit lazy val implicitConversions: implicitConversions = ??? + implicit lazy val implicitConversions: implicitConversions = languageFeature.implicitConversions /** Only where this flag is enabled, higher-kinded types can be written. * @@ -86,7 +86,7 @@ object language { * enabling also serves as a warning that code involving higher-kinded types * might have to be slightly revised in the future. */ - implicit lazy val higherKinds: higherKinds = ??? + implicit lazy val higherKinds: higherKinds = languageFeature.higherKinds /** Only where enabled, existential types that cannot be expressed as wildcard * types can be written and are allowed in inferred types of values or return @@ -102,7 +102,7 @@ object language { * is generally perceived not to be a good idea. Also, complicated existential types * might be no longer supported in a future simplification of the language. */ - implicit lazy val existentials: existentials = ??? + implicit lazy val existentials: existentials = languageFeature.existentials object experimental { @@ -119,6 +119,6 @@ object language { * _Why control it?_ For their very power, macros can lead to code that is hard * to debug and understand. */ - implicit lazy val macros: macros = ??? + implicit lazy val macros: macros = languageFeature.experimental.macros } } diff --git a/src/library/scala/languageFeature.scala b/src/library/scala/languageFeature.scala index c32f1eb724..39540b4f49 100644 --- a/src/library/scala/languageFeature.scala +++ b/src/library/scala/languageFeature.scala @@ -6,25 +6,32 @@ object languageFeature { @meta.languageFeature("extension of type scala.Dynamic", enableRequired = true) sealed trait dynamics + object dynamics extends dynamics @meta.languageFeature("postfix operator #", enableRequired = false) sealed trait postfixOps + object postfixOps extends postfixOps @meta.languageFeature("reflective access of structural type member #", enableRequired = false) sealed trait reflectiveCalls + object reflectiveCalls extends reflectiveCalls @meta.languageFeature("implicit conversion #", enableRequired = false) sealed trait implicitConversions + object implicitConversions extends implicitConversions @meta.languageFeature("higher-kinded type", enableRequired = false) sealed trait higherKinds + object higherKinds extends higherKinds @meta.languageFeature("#, which cannot be expressed by wildcards, ", enableRequired = false) sealed trait existentials + object existentials extends existentials object experimental { @meta.languageFeature("macro definition", enableRequired = true) sealed trait macros + object macros extends macros } } diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 74daa510ca..8669b2e2e8 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -211,7 +211,7 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { catch { case _: ArithmeticException => false } } - protected[math] def isWhole = (this remainder 1) == BigDecimal(0) + def isWhole() = (this remainder 1) == BigDecimal(0) def underlying = bigDecimal /** Compares this BigDecimal with the specified BigDecimal for equality. diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 4471e417d9..09e8ae2026 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -162,7 +162,7 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo } /** Some implementations of java.math.BigInteger allow huge values with bit length greater than Int.MaxValue . * The BigInteger.bitLength method returns truncated bit length in this case . - * This method tests if result of bitLength is valid. + * This method tests if result of bitLength is valid. * This method will become unnecessary if BigInt constructors reject huge BigIntegers. */ private def bitLengthOverflow = { @@ -170,7 +170,7 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo (shifted.signum != 0) && !(shifted equals BigInt.minusOne) } - protected[math] def isWhole = true + def isWhole() = true def underlying = bigInteger /** Compares this BigInt with the specified BigInt for equality. diff --git a/src/library/scala/math/ScalaNumericConversions.scala b/src/library/scala/math/ScalaNumericConversions.scala index 2b7ef7405c..edf243e5df 100644 --- a/src/library/scala/math/ScalaNumericConversions.scala +++ b/src/library/scala/math/ScalaNumericConversions.scala @@ -13,7 +13,17 @@ import java.{ lang => jl } /** Conversions which present a consistent conversion interface * across all the numeric types. */ -trait ScalaNumericConversions extends ScalaNumber { +trait ScalaNumericConversions extends Any { + def isWhole(): Boolean + def underlying(): Any + + def byteValue(): Byte = intValue().toByte + def shortValue(): Short = intValue().toShort + def intValue(): Int + def longValue(): Long + def floatValue(): Float + def doubleValue(): Double + /** Returns the value of this as a [[scala.Char]]. This may involve * rounding or truncation. */ diff --git a/src/library/scala/reflect/base/Symbols.scala b/src/library/scala/reflect/base/Symbols.scala index 294fa19d62..3830264425 100644 --- a/src/library/scala/reflect/base/Symbols.scala +++ b/src/library/scala/reflect/base/Symbols.scala @@ -107,8 +107,8 @@ trait Symbols { self: Universe => /** Does this symbol represent the definition of a type? * Note that every symbol is either a term or a type. - * So for every symbol `sym`, either `sym.isTerm` is true - * or `sym.isType` is true. + * So for every symbol `sym` (except for `NoSymbol`), + * either `sym.isTerm` is true or `sym.isType` is true. */ def isType: Boolean = false @@ -118,9 +118,9 @@ trait Symbols { self: Universe => def asType: TypeSymbol = throw new ScalaReflectionException(s"$this is not a type") /** Does this symbol represent the definition of a term? - * Note that every symbol is either a term or a term. - * So for every symbol `sym`, either `sym.isTerm` is true - * or `sym.isTerm` is true. + * Note that every symbol is either a term or a type. + * So for every symbol `sym` (except for `NoSymbol`), + * either `sym.isTerm` is true or `sym.isTerm` is true. */ def isTerm: Boolean = false @@ -234,10 +234,10 @@ trait Symbols { self: Universe => * `PolyType(ClassInfoType(...))` that describes type parameters, value * parameters, parent types, and members of `C`. */ - def toType: Type + def toType: Type - override def isType = true - override def asType = this + final override def isType = true + final override def asType = this } /** The base API that all term symbols support */ diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala index f499350ce9..c1f245590b 100644 --- a/src/library/scala/runtime/AbstractPartialFunction.scala +++ b/src/library/scala/runtime/AbstractPartialFunction.scala @@ -8,7 +8,8 @@ package scala.runtime -/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` in terms of `isDefinedAt` and `applyOrElse`. +/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` + * in terms of `isDefinedAt` and `applyOrElse`. * * This allows more efficient implementations in many cases: * - optimized `orElse` method supports chained `orElse` in linear time, @@ -16,12 +17,7 @@ package scala.runtime * - optimized `lift` method helps to avoid double evaluation of pattern matchers & guards * of partial function literals. * - * This trait is used as a basis for implementation of all partial function literals - * with non-exhaustive matchers. - * - * Use of `AbstractPartialFunction` instead of `PartialFunction` as a base trait for - * user-defined partial functions may result in better performance - * and more predictable behavior w.r.t. side effects. + * This trait is used as a basis for implementation of all partial function literals. * * @author Pavel Pavlov * @since 2.10 @@ -35,34 +31,4 @@ abstract class AbstractPartialFunction[@specialized(scala.Int, scala.Long, scala // probably okay to make final since classes compiled before have overridden against the old version of AbstractPartialFunction // let's not make it final so as not to confuse anyone /*final*/ def apply(x: T1): R = applyOrElse(x, PartialFunction.empty) - - @annotation.unspecialized override final def andThen[C](k: R => C) : PartialFunction[T1, C] = - new AbstractPartialFunction[T1, C] { - def isDefinedAt(x: T1): Boolean = self.isDefinedAt(x) - override def applyOrElse[A1 <: T1, C1 >: C](x: A1, default: A1 => C1): C1 = - self.applyOrElse(x, PartialFunction.fallbackToken) match { - case PartialFunction.FallbackToken => default(x) - case z => k(z) - } - } - - // TODO: remove - protected def missingCase(x: T1): R = throw new MatchError(x) -} - - -/** `AbstractTotalFunction` is a partial function whose `isDefinedAt` method always returns `true`. - * - * This class is used as base class for partial function literals with - * certainly exhaustive pattern matchers. - * - * @author Pavel Pavlov - * @since 2.10 - */ -abstract class AbstractTotalFunction[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends Function1[T1, R] with PartialFunction[T1, R] { - final def isDefinedAt(x: T1): Boolean = true - @annotation.unspecialized override final def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = apply(x) - @annotation.unspecialized override final def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = this - //TODO: check generated code for PF literal here - @annotation.unspecialized override final def andThen[C](k: R => C): PartialFunction[T1, C] = { case x => k(apply(x)) } } diff --git a/src/library/scala/runtime/RichBoolean.scala b/src/library/scala/runtime/RichBoolean.scala index a14160a71e..92cc6ccf98 100644 --- a/src/library/scala/runtime/RichBoolean.scala +++ b/src/library/scala/runtime/RichBoolean.scala @@ -8,6 +8,6 @@ package scala.runtime -final class RichBoolean(val self: Boolean) extends OrderedProxy[Boolean] { - protected val ord = math.Ordering[Boolean] +final class RichBoolean(val self: Boolean) extends AnyVal with OrderedProxy[Boolean] { + protected def ord = scala.math.Ordering.Boolean } diff --git a/src/library/scala/runtime/RichByte.scala b/src/library/scala/runtime/RichByte.scala index c42a2dd183..9d88ed3689 100644 --- a/src/library/scala/runtime/RichByte.scala +++ b/src/library/scala/runtime/RichByte.scala @@ -8,4 +8,7 @@ package scala.runtime -final class RichByte(val self: Byte) extends ScalaWholeNumberProxy[Byte] { } +final class RichByte(val self: Byte) extends AnyVal with ScalaWholeNumberProxy[Byte] { + protected def num = scala.math.Numeric.ByteIsIntegral + protected def ord = scala.math.Ordering.Byte +} diff --git a/src/library/scala/runtime/RichChar.scala b/src/library/scala/runtime/RichChar.scala index ba939d6633..918fe70f5c 100644 --- a/src/library/scala/runtime/RichChar.scala +++ b/src/library/scala/runtime/RichChar.scala @@ -10,7 +10,10 @@ package scala.runtime import java.lang.Character -final class RichChar(val self: Char) extends IntegralProxy[Char] { +final class RichChar(val self: Char) extends AnyVal with IntegralProxy[Char] { + protected def num = scala.math.Numeric.CharIsIntegral + protected def ord = scala.math.Ordering.Char + def asDigit: Int = Character.digit(self, Character.MAX_RADIX) def isControl: Boolean = Character.isISOControl(self) diff --git a/src/library/scala/runtime/RichDouble.scala b/src/library/scala/runtime/RichDouble.scala index 396323d1e8..19396a3d48 100644 --- a/src/library/scala/runtime/RichDouble.scala +++ b/src/library/scala/runtime/RichDouble.scala @@ -8,8 +8,10 @@ package scala.runtime -final class RichDouble(val self: Double) extends FractionalProxy[Double] { - protected val integralNum = Numeric.DoubleAsIfIntegral +final class RichDouble(val self: Double) extends AnyVal with FractionalProxy[Double] { + protected def num = scala.math.Numeric.DoubleIsFractional + protected def ord = scala.math.Ordering.Double + protected def integralNum = scala.math.Numeric.DoubleAsIfIntegral def round: Long = math.round(self) def ceil: Double = math.ceil(self) diff --git a/src/library/scala/runtime/RichFloat.scala b/src/library/scala/runtime/RichFloat.scala index 4fc9e8864a..9fbb3c19bb 100644 --- a/src/library/scala/runtime/RichFloat.scala +++ b/src/library/scala/runtime/RichFloat.scala @@ -8,8 +8,10 @@ package scala.runtime -final class RichFloat(val self: Float) extends FractionalProxy[Float] { - protected val integralNum = Numeric.FloatAsIfIntegral +final class RichFloat(val self: Float) extends AnyVal with FractionalProxy[Float] { + protected def num = scala.math.Numeric.FloatIsFractional + protected def ord = scala.math.Ordering.Float + protected def integralNum = scala.math.Numeric.FloatAsIfIntegral def round: Int = math.round(self) def ceil: Float = math.ceil(self).toFloat diff --git a/src/library/scala/runtime/RichInt.scala b/src/library/scala/runtime/RichInt.scala index d03968212f..619574264a 100644 --- a/src/library/scala/runtime/RichInt.scala +++ b/src/library/scala/runtime/RichInt.scala @@ -12,7 +12,9 @@ import scala.collection.immutable.Range // Note that this does not implement IntegralProxy[Int] so that it can return // the Int-specific Range class from until/to. -final class RichInt(val self: Int) extends ScalaNumberProxy[Int] with RangedProxy[Int] { +final class RichInt(val self: Int) extends AnyVal with ScalaNumberProxy[Int] with RangedProxy[Int] { + protected def num = scala.math.Numeric.IntIsIntegral + protected def ord = scala.math.Ordering.Int type ResultWithoutStep = Range /** diff --git a/src/library/scala/runtime/RichLong.scala b/src/library/scala/runtime/RichLong.scala index 5784934ffd..7c052851a9 100644 --- a/src/library/scala/runtime/RichLong.scala +++ b/src/library/scala/runtime/RichLong.scala @@ -8,7 +8,10 @@ package scala.runtime -final class RichLong(val self: Long) extends IntegralProxy[Long] { +final class RichLong(val self: Long) extends AnyVal with IntegralProxy[Long] { + protected def num = scala.math.Numeric.LongIsIntegral + protected def ord = scala.math.Ordering.Long + def toBinaryString: String = java.lang.Long.toBinaryString(self) def toHexString: String = java.lang.Long.toHexString(self) def toOctalString: String = java.lang.Long.toOctalString(self) diff --git a/src/library/scala/runtime/RichShort.scala b/src/library/scala/runtime/RichShort.scala index a174438c06..4dfa237b38 100644 --- a/src/library/scala/runtime/RichShort.scala +++ b/src/library/scala/runtime/RichShort.scala @@ -8,4 +8,7 @@ package scala.runtime -final class RichShort(val self: Short) extends ScalaWholeNumberProxy[Short] { } +final class RichShort(val self: Short) extends AnyVal with ScalaWholeNumberProxy[Short] { + protected def num = scala.math.Numeric.ShortIsIntegral + protected def ord = scala.math.Ordering.Short +} diff --git a/src/library/scala/runtime/ScalaNumberProxy.scala b/src/library/scala/runtime/ScalaNumberProxy.scala index d9b9a7843f..64df4611e3 100644 --- a/src/library/scala/runtime/ScalaNumberProxy.scala +++ b/src/library/scala/runtime/ScalaNumberProxy.scala @@ -20,9 +20,8 @@ import Proxy.Typed * @version 2.9 * @since 2.9 */ -abstract class ScalaNumberProxy[T: Numeric] extends ScalaNumericConversions with Typed[T] with OrderedProxy[T] { - private val num = implicitly[Numeric[T]] - protected val ord: Ordering[T] = num +trait ScalaNumberProxy[T] extends Any with ScalaNumericConversions with Typed[T] with OrderedProxy[T] { + protected implicit def num: Numeric[T] def underlying() = self.asInstanceOf[AnyRef] def doubleValue() = num.toDouble(self) @@ -35,11 +34,11 @@ abstract class ScalaNumberProxy[T: Numeric] extends ScalaNumericConversions with def abs = num.abs(self) def signum = num.signum(self) } -abstract class ScalaWholeNumberProxy[T: Numeric] extends ScalaNumberProxy[T] { +trait ScalaWholeNumberProxy[T] extends Any with ScalaNumberProxy[T] { def isWhole() = true } -abstract class IntegralProxy[T : Integral] extends ScalaWholeNumberProxy[T] with RangedProxy[T] { - private lazy val num = implicitly[Integral[T]] +trait IntegralProxy[T] extends Any with ScalaWholeNumberProxy[T] with RangedProxy[T] { + protected implicit def num: Integral[T] type ResultWithoutStep = NumericRange[T] def until(end: T): NumericRange.Exclusive[T] = NumericRange(self, end, num.one) @@ -47,17 +46,17 @@ abstract class IntegralProxy[T : Integral] extends ScalaWholeNumberProxy[T] with def to(end: T): NumericRange.Inclusive[T] = NumericRange.inclusive(self, end, num.one) def to(end: T, step: T): NumericRange.Inclusive[T] = NumericRange.inclusive(self, end, step) } -abstract class FractionalProxy[T : Fractional] extends ScalaNumberProxy[T] with RangedProxy[T] { - def isWhole() = false +trait FractionalProxy[T] extends Any with ScalaNumberProxy[T] with RangedProxy[T] { + protected implicit def num: Fractional[T] + protected implicit def integralNum: Integral[T] /** In order to supply predictable ranges, we require an Integral[T] which provides * us with discrete operations on the (otherwise fractional) T. See Numeric.DoubleAsIfIntegral * for an example. */ - protected implicit def integralNum: Integral[T] - private lazy val num = implicitly[Fractional[T]] type ResultWithoutStep = Range.Partial[T, NumericRange[T]] + def isWhole() = false def until(end: T): ResultWithoutStep = new Range.Partial(NumericRange(self, end, _)) def until(end: T, step: T): NumericRange.Exclusive[T] = NumericRange(self, end, step) def to(end: T): ResultWithoutStep = new Range.Partial(NumericRange.inclusive(self, end, _)) diff --git a/src/library/scala/runtime/StringAdd.scala b/src/library/scala/runtime/StringAdd.scala index a7e78ea9a3..4693b0bf44 100644 --- a/src/library/scala/runtime/StringAdd.scala +++ b/src/library/scala/runtime/StringAdd.scala @@ -9,14 +9,11 @@ package scala.runtime /** A wrapper class that adds string concatenation `+` to any value */ -final class StringAdd(val self: Any) { - +final class StringAdd(val self: Any) extends AnyVal { // Note: The implicit conversion from Any to StringAdd is one of two // implicit conversions from Any to AnyRef in Predef. It is important to have at least // two such conversions, so that silent conversions from value types to AnyRef // are avoided. If StringFormat should become a value class, another // implicit conversion from Any to AnyRef has to be introduced in Predef - def +(other: String) = String.valueOf(self) + other - } diff --git a/src/library/scala/runtime/StringFormat.scala b/src/library/scala/runtime/StringFormat.scala index c120cbb14d..1f5feec9e1 100644 --- a/src/library/scala/runtime/StringFormat.scala +++ b/src/library/scala/runtime/StringFormat.scala @@ -10,8 +10,7 @@ package scala.runtime /** A wrapper class that adds a `formatted` operation to any value */ -final class StringFormat(val self: Any) { - +final class StringFormat(val self: Any) extends AnyVal { // Note: The implicit conversion from Any to StringFormat is one of two // implicit conversions from Any to AnyRef in Predef. It is important to have at least // two such conversions, so that silent conversions from value types to AnyRef @@ -23,5 +22,4 @@ final class StringFormat(val self: Any) { * (@see java.lang.String.format). */ @inline def formatted(fmtstr: String): String = fmtstr format self - } diff --git a/src/library/scala/runtime/Tuple2Zipped.scala b/src/library/scala/runtime/Tuple2Zipped.scala index dce7eef08d..182fd77133 100644 --- a/src/library/scala/runtime/Tuple2Zipped.scala +++ b/src/library/scala/runtime/Tuple2Zipped.scala @@ -16,7 +16,7 @@ import language.{ higherKinds, implicitConversions } * by the requirement to resolve type constructors, for implicit search (which only * needs to find an implicit conversion to Traversable for our purposes.) */ -trait ZippedTraversable2[+El1, +El2] { +trait ZippedTraversable2[+El1, +El2] extends Any { def foreach[U](f: (El1, El2) => U): Unit } object ZippedTraversable2 { @@ -27,16 +27,15 @@ object ZippedTraversable2 { } } -class Tuple2Zipped[El1, Repr1, El2, Repr2]( - coll1: TraversableLike[El1, Repr1], - coll2: IterableLike[El2, Repr2] -) extends ZippedTraversable2[El1, El2] { +final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1, Repr1], IterableLike[El2, Repr2])) extends AnyVal with ZippedTraversable2[El1, El2] { + // This would be better as "private def coll1 = colls._1" but + // SI-6215 precludes private methods in value classes. def map[B, To](f: (El1, El2) => B)(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(coll1.repr) - b.sizeHint(coll1) - val elems2 = coll2.iterator + val b = cbf(colls._1.repr) + b.sizeHint(colls._1) + val elems2 = colls._2.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext) b += f(el1, elems2.next) else @@ -47,10 +46,10 @@ class Tuple2Zipped[El1, Repr1, El2, Repr2]( } def flatMap[B, To](f: (El1, El2) => TraversableOnce[B])(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(coll1.repr) - val elems2 = coll2.iterator + val b = cbf(colls._1.repr) + val elems2 = colls._2.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext) b ++= f(el1, elems2.next) else @@ -61,11 +60,11 @@ class Tuple2Zipped[El1, Repr1, El2, Repr2]( } def filter[To1, To2](f: (El1, El2) => Boolean)(implicit cbf1: CBF[Repr1, El1, To1], cbf2: CBF[Repr2, El2, To2]): (To1, To2) = { - val b1 = cbf1(coll1.repr) - val b2 = cbf2(coll2.repr) - val elems2 = coll2.iterator + val b1 = cbf1(colls._1.repr) + val b2 = cbf2(colls._2.repr) + val elems2 = colls._2.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext) { val el2 = elems2.next if (f(el1, el2)) { @@ -80,9 +79,9 @@ class Tuple2Zipped[El1, Repr1, El2, Repr2]( } def exists(f: (El1, El2) => Boolean): Boolean = { - val elems2 = coll2.iterator + val elems2 = colls._2.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext) { if (f(el1, elems2.next)) return true @@ -96,9 +95,9 @@ class Tuple2Zipped[El1, Repr1, El2, Repr2]( !exists((x, y) => !f(x, y)) def foreach[U](f: (El1, El2) => U): Unit = { - val elems2 = coll2.iterator + val elems2 = colls._2.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext) f(el1, elems2.next) else @@ -108,7 +107,7 @@ class Tuple2Zipped[El1, Repr1, El2, Repr2]( } object Tuple2Zipped { - class Ops[T1, T2](x: (T1, T2)) { + final class Ops[T1, T2](val x: (T1, T2)) extends AnyVal { def invert[El1, CC1[X] <: TraversableOnce[X], El2, CC2[X] <: TraversableOnce[X], That] (implicit w1: T1 <:< CC1[El1], w2: T2 <:< CC2[El2], @@ -119,13 +118,13 @@ object Tuple2Zipped { val it2 = x._2.toIterator while (it1.hasNext && it2.hasNext) buf += ((it1.next, it2.next)) - + buf.result } def zipped[El1, Repr1, El2, Repr2] (implicit w1: T1 => TraversableLike[El1, Repr1], w2: T2 => IterableLike[El2, Repr2] - ): Tuple2Zipped[El1, Repr1, El2, Repr2] = new Tuple2Zipped(x._1, x._2) + ): Tuple2Zipped[El1, Repr1, El2, Repr2] = new Tuple2Zipped((x._1, x._2)) } } diff --git a/src/library/scala/runtime/Tuple3Zipped.scala b/src/library/scala/runtime/Tuple3Zipped.scala index f3ca08649d..f6aafe41fb 100644 --- a/src/library/scala/runtime/Tuple3Zipped.scala +++ b/src/library/scala/runtime/Tuple3Zipped.scala @@ -13,7 +13,7 @@ import scala.collection.generic.{ CanBuildFrom => CBF } import language.{ higherKinds, implicitConversions } /** See comment on ZippedTraversable2. */ -trait ZippedTraversable3[+El1, +El2, +El3] { +trait ZippedTraversable3[+El1, +El2, +El3] extends Any { def foreach[U](f: (El1, El2, El3) => U): Unit } object ZippedTraversable3 { @@ -24,17 +24,15 @@ object ZippedTraversable3 { } } -class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3]( - coll1: TraversableLike[El1, Repr1], - coll2: IterableLike[El2, Repr2], - coll3: IterableLike[El3, Repr3] -) extends ZippedTraversable3[El1, El2, El3] { +final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (TraversableLike[El1, Repr1], IterableLike[El2, Repr2], IterableLike[El3, Repr3])) + extends AnyVal with ZippedTraversable3[El1, El2, El3] { + def map[B, To](f: (El1, El2, El3) => B)(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(coll1.repr) - val elems2 = coll2.iterator - val elems3 = coll3.iterator + val b = cbf(colls._1.repr) + val elems2 = colls._2.iterator + val elems3 = colls._3.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext && elems3.hasNext) b += f(el1, elems2.next, elems3.next) else @@ -44,11 +42,11 @@ class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3]( } def flatMap[B, To](f: (El1, El2, El3) => TraversableOnce[B])(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(coll1.repr) - val elems2 = coll2.iterator - val elems3 = coll3.iterator + val b = cbf(colls._1.repr) + val elems2 = colls._2.iterator + val elems3 = colls._3.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext && elems3.hasNext) b ++= f(el1, elems2.next, elems3.next) else @@ -61,14 +59,14 @@ class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3]( implicit cbf1: CBF[Repr1, El1, To1], cbf2: CBF[Repr2, El2, To2], cbf3: CBF[Repr3, El3, To3]): (To1, To2, To3) = { - val b1 = cbf1(coll1.repr) - val b2 = cbf2(coll2.repr) - val b3 = cbf3(coll3.repr) - val elems2 = coll2.iterator - val elems3 = coll3.iterator + val b1 = cbf1(colls._1.repr) + val b2 = cbf2(colls._2.repr) + val b3 = cbf3(colls._3.repr) + val elems2 = colls._2.iterator + val elems3 = colls._3.iterator def result = (b1.result, b2.result, b3.result) - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext && elems3.hasNext) { val el2 = elems2.next val el3 = elems3.next @@ -86,10 +84,10 @@ class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3]( } def exists(f: (El1, El2, El3) => Boolean): Boolean = { - val elems2 = coll2.iterator - val elems3 = coll3.iterator + val elems2 = colls._2.iterator + val elems3 = colls._3.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext && elems3.hasNext) { if (f(el1, elems2.next, elems3.next)) return true @@ -103,10 +101,10 @@ class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3]( !exists((x, y, z) => !f(x, y, z)) def foreach[U](f: (El1, El2, El3) => U): Unit = { - val elems2 = coll2.iterator - val elems3 = coll3.iterator + val elems2 = colls._2.iterator + val elems3 = colls._3.iterator - for (el1 <- coll1) { + for (el1 <- colls._1) { if (elems2.hasNext && elems3.hasNext) f(el1, elems2.next, elems3.next) else @@ -116,7 +114,7 @@ class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3]( } object Tuple3Zipped { - class Ops[T1, T2, T3](x: (T1, T2, T3)) { + final class Ops[T1, T2, T3](val x: (T1, T2, T3)) extends AnyVal { def invert[El1, CC1[X] <: TraversableOnce[X], El2, CC2[X] <: TraversableOnce[X], El3, CC3[X] <: TraversableOnce[X], That] (implicit w1: T1 <:< CC1[El1], w2: T2 <:< CC2[El2], @@ -129,14 +127,14 @@ object Tuple3Zipped { val it3 = x._3.toIterator while (it1.hasNext && it2.hasNext && it3.hasNext) buf += ((it1.next, it2.next, it3.next)) - + buf.result } - + def zipped[El1, Repr1, El2, Repr2, El3, Repr3] (implicit w1: T1 => TraversableLike[El1, Repr1], w2: T2 => IterableLike[El2, Repr2], w3: T3 => IterableLike[El3, Repr3] - ): Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3] = new Tuple3Zipped(x._1, x._2, x._3) + ): Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3] = new Tuple3Zipped((x._1, x._2, x._3)) } } diff --git a/src/partest/scala/tools/partest/nest/SBTRunner.scala b/src/partest/scala/tools/partest/nest/SBTRunner.scala index 266153d9d3..6fa31492f3 100644 --- a/src/partest/scala/tools/partest/nest/SBTRunner.scala +++ b/src/partest/scala/tools/partest/nest/SBTRunner.scala @@ -34,7 +34,7 @@ object SBTRunner extends DirectRunner { scalacOptions: Seq[String] = Seq(), justFailedTests: Boolean = false) - def mainReflect(args: Array[String]): java.util.Map[String, TestState] = { + def mainReflect(args: Array[String]): java.util.Map[String, String] = { setProp("partest.debug", "true") val Argument = new scala.util.matching.Regex("-(.*)") @@ -73,9 +73,13 @@ object SBTRunner extends DirectRunner { (for { (testType, files) <- runs (path, result) <- reflectiveRunTestsForFiles(files,testType).asScala - } yield (path, result)).seq.asJava + } yield (path, fixResult(result))).seq.asJava + } + def fixResult(result: TestState): String = result match { + case TestState.Ok => "OK" + case TestState.Fail => "FAIL" + case TestState.Timeout => "TIMEOUT" } - def main(args: Array[String]): Unit = { val failures = ( for ((path, result) <- mainReflect(args).asScala ; if result != TestState.Ok) yield diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala index 36836e84a9..fdd43f1883 100644 --- a/src/reflect/scala/reflect/api/FlagSets.scala +++ b/src/reflect/scala/reflect/api/FlagSets.scala @@ -3,7 +3,7 @@ package api import scala.language.implicitConversions -trait FlagSets { self: Universe => +trait FlagSets extends base.FlagSets { self: Universe => type FlagSet diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala index 7d185d9879..8c4c423221 100644 --- a/src/reflect/scala/reflect/api/Mirrors.scala +++ b/src/reflect/scala/reflect/api/Mirrors.scala @@ -1,7 +1,7 @@ package scala.reflect package api -trait Mirrors { self: Universe => +trait Mirrors extends base.Mirrors { self: Universe => type RuntimeClass >: Null diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index 8617ae975d..d167099979 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -205,9 +205,6 @@ trait Symbols extends base.Symbols { self: Universe => /** ... */ def suchThat(cond: Symbol => Boolean): Symbol - - /** The string discriminator of this symbol; useful for debugging */ - def kind: String } /** The API of term symbols */ diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index bdcaadfbda..f22f8d3e75 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -159,9 +159,6 @@ trait Types extends base.Types { self: Universe => /** Does this type contain a reference to given symbol? */ def contains(sym: Symbol): Boolean - - /** The string discriminator of this type; useful for debugging */ - def kind: String } /** .. */ diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 98d42b724c..c21ebfe997 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -218,6 +218,32 @@ trait Definitions extends api.StandardDefinitions { case _ => null } + /** Fully initialize the symbol, type, or scope. + */ + def fullyInitializeSymbol(sym: Symbol): Symbol = { + sym.initialize + fullyInitializeType(sym.info) + fullyInitializeType(sym.tpe) + sym + } + def fullyInitializeType(tp: Type): Type = { + tp.typeParams foreach fullyInitializeSymbol + tp.paramss.flatten foreach fullyInitializeSymbol + tp + } + def fullyInitializeScope(scope: Scope): Scope = { + scope.sorted foreach fullyInitializeSymbol + scope + } + /** Is this type equivalent to Any, AnyVal, or AnyRef? */ + def isTrivialTopType(tp: Type) = ( + tp =:= AnyClass.tpe + || tp =:= AnyValClass.tpe + || tp =:= AnyRefClass.tpe + ) + /** Does this type have a parent which is none of Any, AnyVal, or AnyRef? */ + def hasNonTrivialParent(tp: Type) = tp.parents exists (t => !isTrivialTopType(tp)) + private def fixupAsAnyTrait(tpe: Type): Type = tpe match { case ClassInfoType(parents, decls, clazz) => if (parents.head.typeSymbol == AnyClass) tpe @@ -383,7 +409,7 @@ trait Definitions extends api.StandardDefinitions { def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe) def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf - def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) + def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params) def isJavaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isJavaRepeatedParamType(params.last.tpe) def isScalaVarArgs(params: Seq[Symbol]) = params.nonEmpty && isScalaRepeatedParamType(params.last.tpe) def isVarArgsList(params: Seq[Symbol]) = params.nonEmpty && isRepeatedParamType(params.last.tpe) diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index d5baad8ab1..4b3eb0cdc4 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -3,7 +3,7 @@ package internal import scala.collection.mutable.WeakHashMap // SI-6241: move importers to a mirror -trait Importers { self: SymbolTable => +trait Importers extends api.Importers { self: SymbolTable => def mkImporter(from0: api.Universe): Importer { val from: from0.type } = ( if (self eq from0) { diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 4d60566474..3548657c04 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -64,7 +64,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => abstract class SymbolContextApiImpl extends SymbolContextApi { this: Symbol => - def kind: String = kindString def isExistential: Boolean = this.isExistentiallyBound def isParamWithDefault: Boolean = this.hasDefault def isByNameParam: Boolean = this.isValueParameter && (this hasFlag BYNAMEPARAM) @@ -524,6 +523,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isTypeParameterOrSkolem = false def isTypeSkolem = false def isTypeMacro = false + def isInvariant = !isCovariant && !isContravariant /** Qualities of Terms, always false for TypeSymbols. */ diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 01f615c5cc..c266e26895 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -1010,7 +1010,11 @@ trait Types extends api.Types { self: SymbolTable => def toLongString = { val str = toString if (str == "type") widen.toString - else if ((str endsWith ".type") && !typeSymbol.isModuleClass) str + " (with underlying type " + widen + ")" + else if ((str endsWith ".type") && !typeSymbol.isModuleClass) + widen match { + case RefinedType(_, _) => "" + widen + case _ => s"$str (with underlying type $widen)" + } else str } @@ -1632,7 +1636,7 @@ trait Types extends api.Types { self: SymbolTable => override def safeToString: String = parentsString(parents) + ( (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) - decls.mkString("{", "; ", "}") else "") + fullyInitializeScope(decls).mkString("{", "; ", "}") else "") ) } @@ -1819,7 +1823,6 @@ trait Types extends api.Types { self: SymbolTable => false })) } - override def kind = "RefinedType" } @@ -2005,9 +2008,11 @@ trait Types extends api.Types { self: SymbolTable => /** A nicely formatted string with newlines and such. */ def formattedToString: String = - parents.mkString("\n with ") + - (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) - decls.mkString(" {\n ", "\n ", "\n}") else "") + parents.mkString("\n with ") + ( + if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) + fullyInitializeScope(decls).mkString(" {\n ", "\n ", "\n}") + else "" + ) } object ClassInfoType extends ClassInfoTypeExtractor @@ -2466,7 +2471,7 @@ trait Types extends api.Types { self: SymbolTable => def refinementString = ( if (sym.isStructuralRefinement) ( - decls filter (sym => sym.isPossibleInRefinement && sym.isPublic) + fullyInitializeScope(decls) filter (sym => sym.isPossibleInRefinement && sym.isPublic) map (_.defString) mkString("{", "; ", "}") ) @@ -3712,10 +3717,15 @@ trait Types extends api.Types { self: SymbolTable => * may or may not be poly? (It filched the standard "canonical creator" name.) */ object GenPolyType { - def apply(tparams: List[Symbol], tpe: Type): Type = ( + def apply(tparams: List[Symbol], tpe: Type): Type = { + tpe match { + case MethodType(_, _) => + assert(tparams forall (_.isInvariant), "Trying to create a method with variant type parameters: " + ((tparams, tpe))) + case _ => + } if (tparams.nonEmpty) typeFun(tparams, tpe) else tpe // it's okay to be forgiving here - ) + } def unapply(tpe: Type): Option[(List[Symbol], Type)] = tpe match { case PolyType(tparams, restpe) => Some((tparams, restpe)) case _ => Some((Nil, tpe)) diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index 967ac69148..9f2c3fc79c 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -124,7 +124,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym private def ErrorInnerModule(wannabe: Symbol) = throw new ScalaReflectionException(s"$wannabe is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror") private def ErrorStaticClass(wannabe: Symbol) = throw new ScalaReflectionException(s"$wannabe is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror") private def ErrorStaticModule(wannabe: Symbol) = throw new ScalaReflectionException(s"$wannabe is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror") - private def ErrorNotMember(wannabe: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a member of $owner, you provided ${wannabe.kind} ${wannabe.fullName}") + private def ErrorNotMember(wannabe: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a member of $owner, you provided ${wannabe.kindString} ${wannabe.fullName}") private def ErrorNotField(wannabe: Symbol) = throw new ScalaReflectionException(s"expected a field or an accessor method symbol, you provided $wannabe") private def ErrorNonExistentField(wannabe: Symbol) = throw new ScalaReflectionException(s""" |Scala field ${wannabe.name} isn't represented as a Java field, neither it has a Java accessor method |