diff options
101 files changed, 1292 insertions, 506 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 98a8359f89..d101337087 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -266,9 +266,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) log("Running operation '%s' after every phase.\n".format(msg) + describeAfterEveryPhase(op)) } - def shouldLogAtThisPhase = ( - (settings.log.isSetByUser) - && ((settings.log containsPhase globalPhase) || (settings.log containsPhase phase)) + override def shouldLogAtThisPhase = settings.log.isSetByUser && ( + (settings.log containsPhase globalPhase) || (settings.log containsPhase phase) ) // Over 200 closure objects are eliminated by inlining this. @inline final def log(msg: => AnyRef) { diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 085ce82025..bd5c9b2f68 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -48,12 +48,12 @@ trait Trees extends reflect.internal.Trees { self: Global => override def isType = definition.isType } - /** Array selection <qualifier> . <name> only used during erasure */ + /** Array selection `<qualifier> . <name>` only used during erasure */ case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type) extends RefTree with TermTree - /** Derived value class injection (equivalent to: new C(arg) after easure); only used during erasure - * The class C is stored as the symbol of the tree node. + /** Derived value class injection (equivalent to: `new C(arg)` after erasure); only used during erasure. + * The class `C` is stored as a tree attachment. */ case class InjectDerivedValue(arg: Tree) extends SymTree diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 739aa2b184..24662e2ac3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -128,7 +128,6 @@ abstract class GenICode extends SubComponent { if (staticfield != NoSymbol) { // in companion object accessors to @static fields, we access the static field directly val hostClass = m.symbol.owner.companionClass - if (m.symbol.isGetter) { ctx1.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos) ctx1.bb.closeWith(RETURN(m.returnType)) @@ -662,16 +661,16 @@ abstract class GenICode extends SubComponent { } else { val sym = tree.symbol val local = ctx.method.addLocal(new Local(sym, toTypeKind(sym.info), false)) - + if (rhs == EmptyTree) { debuglog("Uninitialized variable " + tree + " at: " + (tree.pos)); ctx.bb.emit(getZeroOf(local.kind)) } - + var ctx1 = ctx if (rhs != EmptyTree) ctx1 = genLoad(rhs, ctx, local.kind); - + ctx1.bb.emit(STORE_LOCAL(local), tree.pos) ctx1.scope.add(local) ctx1.bb.emit(SCOPE_ENTER(local)) @@ -730,10 +729,10 @@ abstract class GenICode extends SubComponent { ctx1.bb.enterIgnoreMode generatedType = expectedType ctx1 - } + } genLoadReturn - case t @ Try(_, _, _) => + case t @ Try(_, _, _) => genLoadTry(t, ctx, generatedType = _) case Throw(expr) => @@ -753,7 +752,7 @@ abstract class GenICode extends SubComponent { case Object_asInstanceOf => true case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullName + "]" + " in: " + tree) } - + val Select(obj, _) = fun val l = toTypeKind(obj.tpe) val r = toTypeKind(targs.head.tpe) @@ -797,7 +796,7 @@ abstract class GenICode extends SubComponent { ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos) val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx) - + ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos) generatedType = if (fun.symbol.isConstructor) UNIT @@ -815,7 +814,7 @@ abstract class GenICode extends SubComponent { val ctor = fun.symbol debugassert(ctor.isClassConstructor, "'new' call to non-constructor: " + ctor.name) - + generatedType = toTypeKind(tpt.tpe) debugassert(generatedType.isReferenceType || generatedType.isArrayType, "Non reference type cannot be instantiated: " + generatedType) @@ -861,7 +860,7 @@ abstract class GenICode extends SubComponent { ctx1 } ctx2 - + case _ => abort("Cannot instantiate " + tpt + " of kind: " + generatedType) } @@ -902,7 +901,7 @@ abstract class GenICode extends SubComponent { ctx1 case app @ Apply(fun @ Select(qual, _), args) - if !ctx.method.symbol.isStaticConstructor + if !ctx.method.symbol.isStaticConstructor && fun.symbol.isAccessor && fun.symbol.accessed.hasStaticAnnotation && qual.tpe.typeSymbol.orElse(fun.symbol.owner).companionClass != NoSymbol => // bypass the accessor to the companion object and load the static field directly @@ -941,11 +940,11 @@ abstract class GenICode extends SubComponent { } } genLoadApply5 - + case app @ Apply(fun, args) => def genLoadApply6 = { val sym = fun.symbol - + if (sym.isLabel) { // jump to a label val label = ctx.labels.getOrElse(sym, { // it is a forward jump, scan for labels @@ -982,7 +981,7 @@ abstract class GenICode extends SubComponent { Static(true) else Dynamic - + var ctx1 = if (invokeStyle.hasInstance) { if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym)) @@ -990,24 +989,26 @@ abstract class GenICode extends SubComponent { else genLoadQualifier(fun, ctx) } else ctx - + ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1) val cm = CALL_METHOD(sym, invokeStyle) - + /** In a couple cases, squirrel away a little extra information in the * CALL_METHOD for use by GenJVM. */ fun match { case Select(qual, _) => val qualSym = findHostClass(qual.tpe, sym) - - if (qualSym == ArrayClass) cm setTargetTypeKind toTypeKind(qual.tpe) - else cm setHostClass qualSym - - log( - if (qualSym == ArrayClass) "Stored target type kind " + toTypeKind(qual.tpe) + " for " + sym.fullName - else s"Set more precise host class for ${sym.fullName} hostClass: $qualSym" - ) + if (qualSym == ArrayClass) { + val kind = toTypeKind(qual.tpe) + cm setTargetTypeKind kind + log(s"Stored target type kind for {$sym.fullName} as $kind") + } + else { + cm setHostClass qualSym + if (qual.tpe.typeSymbol != qualSym) + log(s"Precisified host class for $sym from ${qual.tpe.typeSymbol.fullName} to ${qualSym.fullName}") + } case _ => } ctx1.bb.emit(cm, tree.pos) @@ -1143,7 +1144,7 @@ abstract class GenICode extends SubComponent { val elmKind = toTypeKind(tpt.tpe) generatedType = ARRAY(elmKind) val elems = _elems.toIndexedSeq - + ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos) ctx1.bb.emit(CREATE_ARRAY(elmKind, 1)) // inline array literals @@ -1166,7 +1167,7 @@ abstract class GenICode extends SubComponent { val afterCtx = ctx1.newBlock var caseCtx: Context = null generatedType = toTypeKind(tree.tpe) - + var targets: List[BasicBlock] = Nil var tags: List[Int] = Nil var default: BasicBlock = afterCtx.bb @@ -1193,7 +1194,7 @@ abstract class GenICode extends SubComponent { abort("Invalid case statement in switch-like pattern match: " + tree + " at: " + (tree.pos)) } - + caseCtx = genLoad(body, tmpCtx, generatedType) // close the block unless it's already been closed by the body, which closes the block if it ends in a jump (which is emitted to have alternatives share their body) caseCtx.bb.closeWith(JUMP(afterCtx.bb) setPos caze.pos) diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index d1d8e4a385..df158a29ea 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -200,7 +200,7 @@ abstract class CopyPropagation { in(b) = lattice.bottom out(b) = lattice.bottom assert(out.contains(b), out) - log("Added point: " + b) + debuglog("CopyAnalysis added point: " + b) } m.exh foreach { e => in(e.startBlock) = new copyLattice.State(copyLattice.emptyBinding, copyLattice.exceptionHandlerStack); @@ -531,11 +531,11 @@ abstract class CopyPropagation { case 0 => () case 1 if ctor.tpe.paramTypes.head == ctor.owner.rawowner.tpe => // it's an unused outer - log("considering unused outer at position 0 in " + ctor.tpe.paramTypes) + debuglog("considering unused outer at position 0 in " + ctor.tpe.paramTypes) paramTypes = paramTypes.tail values = values.tail case _ => - log("giving up on " + ctor + "(diff: " + diff + ")") + debuglog("giving up on " + ctor + "(diff: " + diff + ")") return bindings } @@ -566,7 +566,7 @@ abstract class CopyPropagation { method.blocks map { b => "\nIN(%s):\t Bindings: %s".format(b.label, in(b).bindings) + "\nIN(%s):\t Stack: %s".format(b.label, in(b).stack) - } + } ).mkString } /* class CopyAnalysis */ diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index b57f5e86a3..ea0a0148e4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -154,8 +154,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters { inform("[running phase " + name + " on icode]") if (settings.Xdce.value) - for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) + for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) { + log(s"Optimizer eliminated ${sym.fullNameString}") icodes.classes -= sym + } // For predictably ordered error messages. var sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 930791d88d..0f64a55d70 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -122,8 +122,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with inform("[running phase " + name + " on icode]") if (settings.Xdce.value) - for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) + for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) { + log(s"Optimizer eliminated ${sym.fullNameString}") icodes.classes -= sym + } // For predictably ordered error messages. val sortedClasses = classes.values.toList sortBy ("" + _.symbol.fullName) diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index 7772ccbdd5..eb2da72401 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -35,7 +35,7 @@ abstract class ClosureElimination extends SubComponent { case (STORE_LOCAL(x), LOAD_LOCAL(y)) if (x == y) => var liveOut = liveness.out(bb) if (!liveOut(x)) { - log("store/load to a dead local? " + x) + debuglog("store/load to a dead local? " + x) val instrs = bb.getArray var idx = instrs.length - 1 while (idx > 0 && (instrs(idx) ne i2)) { @@ -43,7 +43,7 @@ abstract class ClosureElimination extends SubComponent { idx -= 1 } if (!liveOut(x)) { - log("removing dead store/load " + x) + log("Removing dead store/load of " + x.sym.initialize.defString) Some(Nil) } else None } else @@ -84,6 +84,7 @@ abstract class ClosureElimination extends SubComponent { */ class ClosureElim { def analyzeClass(cls: IClass): Unit = if (settings.Xcloselim.value) { + log(s"Analyzing ${cls.methods.size} methods in $cls.") cls.methods foreach { m => analyzeMethod(m) peephole(m) @@ -95,7 +96,6 @@ abstract class ClosureElimination extends SubComponent { /* Some embryonic copy propagation. */ def analyzeMethod(m: IMethod): Unit = try {if (m.hasCode) { - log("Analyzing " + m) cpp.init(m) cpp.run @@ -110,23 +110,20 @@ abstract class ClosureElimination extends SubComponent { t match { case Deref(This) | Const(_) => bb.replaceInstruction(i, valueToInstruction(t)); - log("replaced " + i + " with " + t) + debuglog(s"replaced $i with $t") case _ => - bb.replaceInstruction(i, LOAD_LOCAL(info.getAlias(l))) - log("replaced " + i + " with " + info.getAlias(l)) - + val t = info.getAlias(l) + bb.replaceInstruction(i, LOAD_LOCAL(t)) + debuglog(s"replaced $i with $t") } case LOAD_FIELD(f, false) /* if accessible(f, m.symbol) */ => def replaceFieldAccess(r: Record) { val Record(cls, bindings) = r - info.getFieldNonRecordValue(r, f) match { - case Some(v) => - bb.replaceInstruction(i, - DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil); - log("Replaced " + i + " with " + info.getFieldNonRecordValue(r, f)); - case None => + info.getFieldNonRecordValue(r, f) foreach { v => + bb.replaceInstruction(i, DROP(REFERENCE(cls)) :: valueToInstruction(v) :: Nil) + debuglog(s"replaced $i with $v") } } @@ -157,14 +154,14 @@ abstract class ClosureElimination extends SubComponent { value match { case Boxed(LocalVar(loc2)) => bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(info.getBinding(loc2)) :: Nil) - log("replaced " + i + " with " + info.getBinding(loc2)) + debuglog("replaced " + i + " with " + info.getBinding(loc2)) case _ => () } case Boxed(LocalVar(loc1)) :: _ => val loc2 = info.getAlias(loc1) bb.replaceInstruction(i, DROP(icodes.ObjectReference) :: valueToInstruction(Deref(LocalVar(loc2))) :: Nil) - log("replaced " + i + " with " + LocalVar(loc2)) + debuglog("replaced " + i + " with " + LocalVar(loc2)) case _ => } diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index fd949576e1..36a5d61cfb 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -44,6 +44,7 @@ abstract class DeadCodeElimination extends SubComponent { class DeadCode { def analyzeClass(cls: IClass) { + log(s"Analyzing ${cls.methods.size} methods in $cls.") cls.methods.foreach { m => this.method = m dieCodeDie(m) @@ -73,7 +74,7 @@ abstract class DeadCodeElimination extends SubComponent { def dieCodeDie(m: IMethod) { if (m.hasCode) { - log("dead code elimination on " + m); + debuglog("dead code elimination on " + m); dropOf.clear() m.code.blocks.clear() accessedLocals = m.params.reverse @@ -82,8 +83,10 @@ abstract class DeadCodeElimination extends SubComponent { mark sweep(m) accessedLocals = accessedLocals.distinct - if ((m.locals diff accessedLocals).nonEmpty) { - log("Removed dead locals: " + (m.locals diff accessedLocals)) + val diff = m.locals diff accessedLocals + if (diff.nonEmpty) { + val msg = diff.map(_.sym.name)mkString(", ") + log(s"Removed ${diff.size} dead locals: $msg") m.locals = accessedLocals.reverse } } @@ -126,7 +129,7 @@ abstract class DeadCodeElimination extends SubComponent { case RETURN(_) | JUMP(_) | CJUMP(_, _, _, _) | CZJUMP(_, _, _, _) | STORE_FIELD(_, _) | THROW(_) | LOAD_ARRAY_ITEM(_) | STORE_ARRAY_ITEM(_) | SCOPE_ENTER(_) | SCOPE_EXIT(_) | STORE_THIS(_) | LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() => worklist += ((bb, idx)) - case CALL_METHOD(m1, _) if isSideEffecting(m1) => worklist += ((bb, idx)); log("marking " + m1) + case CALL_METHOD(m1, _) if isSideEffecting(m1) => worklist += ((bb, idx)); debuglog("marking " + m1) case CALL_METHOD(m1, SuperCall(_)) => worklist += ((bb, idx)) // super calls to constructor case DROP(_) => @@ -173,7 +176,7 @@ abstract class DeadCodeElimination extends SubComponent { instr match { case LOAD_LOCAL(l1) => for ((l2, bb1, idx1) <- defs((bb, idx)) if l1 == l2; if !useful(bb1)(idx1)) { - log("\tAdding " + bb1(idx1)) + debuglog("\tAdding " + bb1(idx1)) worklist += ((bb1, idx1)) } @@ -197,7 +200,7 @@ abstract class DeadCodeElimination extends SubComponent { case _ => for ((bb1, idx1) <- rdef.findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) { - log("\tAdding " + bb1(idx1)) + debuglog("\tAdding " + bb1(idx1)) worklist += ((bb1, idx1)) } } @@ -232,7 +235,7 @@ abstract class DeadCodeElimination extends SubComponent { } else { i match { case NEW(REFERENCE(sym)) => - log("skipped object creation: " + sym + "inside " + m) + log(s"Eliminated instantation of $sym inside $m") case _ => () } debuglog("Skipped: bb_" + bb + ": " + idx + "( " + i + ")") @@ -240,7 +243,7 @@ abstract class DeadCodeElimination extends SubComponent { } if (bb.nonEmpty) bb.close - else log("empty block encountered") + else log(s"empty block encountered in $m") } } @@ -252,7 +255,7 @@ abstract class DeadCodeElimination extends SubComponent { foreachWithIndex(bb.toList) { (i, idx) => if (!useful(bb)(idx)) { foreachWithIndex(i.consumedTypes.reverse) { (consumedType, depth) => - log("Finding definitions of: " + i + "\n\t" + consumedType + " at depth: " + depth) + debuglog("Finding definitions of: " + i + "\n\t" + consumedType + " at depth: " + depth) val defs = rdef.findDefs(bb, idx, 1, depth) for (d <- defs) { val (bb, idx) = d diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index f1f597322e..98120f0614 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -93,10 +93,9 @@ abstract class InlineExceptionHandlers extends SubComponent { val startTime = System.currentTimeMillis currentClass = c - log("Starting " + c) + debuglog("Starting InlineExceptionHandlers on " + c) c.methods foreach applyMethod - - log("Finished " + c + "... " + (System.currentTimeMillis - startTime) + "ms") + debuglog("Finished InlineExceptionHandlers on " + c + "... " + (System.currentTimeMillis - startTime) + "ms") currentClass = null } diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 5464b6fc3b..62bb23c3a7 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -44,7 +44,7 @@ abstract class Inliners extends SubComponent { import definitions.{ NullClass, NothingClass, ObjectClass, PredefModule, RuntimePackage, ScalaInlineClass, ScalaNoInlineClass, - isFunctionType + isFunctionType, isByNameParamType } val phaseName = "inliner" @@ -143,7 +143,6 @@ abstract class Inliners extends SubComponent { } def isBottomType(sym: Symbol) = sym == NullClass || sym == NothingClass - def posToStr(pos: scala.reflect.internal.util.Position) = if (pos.isDefined) pos.point.toString else "<nopos>" /** Is the given class a closure? */ def isClosureClass(cls: Symbol): Boolean = @@ -194,6 +193,27 @@ abstract class Inliners extends SubComponent { private var currentIClazz: IClass = _ private def warn(pos: Position, msg: String) = currentIClazz.cunit.inlinerWarning(pos, msg) + private def ownedName(sym: Symbol): String = afterUncurry { + val count = ( + if (!sym.isMethod) 1 + else if (sym.owner.isAnonymousFunction) 3 + else 2 + ) + (sym.ownerChain take count filterNot (_.isPackageClass)).reverseMap(_.nameString).mkString(".") + } + private def inlineLog(what: String, main: => String, comment: => String) { + def cstr = comment match { + case "" => "" + case str => " // " + str + } + val width = if (currentIClazz eq null) 40 else currentIClazz.symbol.enclosingPackage.fullName.length + 25 + val fmt = "%8s %-" + width + "s" + cstr + log(fmt.format(what, main)) + } + private def inlineLog(what: String, main: Symbol, comment: => String) { + inlineLog(what, ownedName(main), comment) + } + val recentTFAs = mutable.Map.empty[Symbol, Tuple2[Boolean, analysis.MethodTFA]] private def getRecentTFA(incm: IMethod, forceable: Boolean): (Boolean, analysis.MethodTFA) = { @@ -244,14 +264,15 @@ abstract class Inliners extends SubComponent { def analyzeClass(cls: IClass): Unit = if (settings.inline.value) { - debuglog("Analyzing " + cls) + inlineLog("class", s"${cls.symbol.decodedName}", s"analyzing ${cls.methods.size} methods in $cls") this.currentIClazz = cls val ms = cls.methods sorted imethodOrdering ms foreach { im => - if(hasInline(im.symbol)) { - log("Not inlining into " + im.symbol.originalName.decode + " because it is marked @inline.") - } else if(im.hasCode && !im.symbol.isBridge) { + if (hasInline(im.symbol)) { + inlineLog("skip", im.symbol, "no inlining into @inline methods") + } + else if(im.hasCode && !im.symbol.isBridge) { analyzeMethod(im) } } @@ -296,6 +317,8 @@ abstract class Inliners extends SubComponent { * */ def analyzeMethod(m: IMethod): Unit = { // m.normalize + if (settings.debug.value) + inlineLog("caller", ownedName(m.symbol), "in " + m.symbol.owner.fullName) var sizeBeforeInlining = m.code.blockCount var instrBeforeInlining = m.code.instructionCount @@ -306,8 +329,8 @@ abstract class Inliners extends SubComponent { val fresh = mutable.HashMap.empty[String, Int] withDefaultValue 0 // how many times have we already inlined this method here? val inlinedMethodCount = mutable.HashMap.empty[Symbol, Int] withDefaultValue 0 - val caller = new IMethodInfo(m) + def analyzeMessage = s"Analyzing ${caller.length} blocks of $m for inlining sites." def preInline(isFirstRound: Boolean): Int = { val inputBlocks = caller.m.linearizedBlocks() @@ -354,15 +377,17 @@ abstract class Inliners extends SubComponent { */ def analyzeInc(i: CALL_METHOD, bb: BasicBlock, receiver: Symbol, stackLength: Int, concreteMethod: Symbol): Boolean = { assert(bb.toList contains i, "Candidate callsite does not belong to BasicBlock.") - - var inlined = false val shouldWarn = hasInline(i.method) - def warnNoInline(reason: String) = { - if (shouldWarn) { - warn(i.pos, "Could not inline required method %s because %s.".format(i.method.originalName.decode, reason)) - } - } + def warnNoInline(reason: String): Boolean = { + def msg = "Could not inline required method %s because %s.".format(i.method.originalName.decode, reason) + if (settings.debug.value) + inlineLog("fail", i.method.fullName, reason) + if (shouldWarn) + warn(i.pos, msg) + + false + } var isAvailable = icodes available concreteMethod.enclClass @@ -378,92 +403,69 @@ abstract class Inliners extends SubComponent { isAvailable = icodes.load(concreteMethod.enclClass) } - def isCandidate = ( - isClosureClass(receiver) - || concreteMethod.isEffectivelyFinal - || receiver.isEffectivelyFinal - ) + def isCandidate = ( + isClosureClass(receiver) + || concreteMethod.isEffectivelyFinal + || receiver.isEffectivelyFinal + ) - def isApply = concreteMethod.name == nme.apply + def isApply = concreteMethod.name == nme.apply - def isCountable = !( - isClosureClass(receiver) - || isApply - || isMonadicMethod(concreteMethod) - || receiver.enclosingPackage == definitions.RuntimePackage - ) // only count non-closures + def isCountable = !( + isClosureClass(receiver) + || isApply + || isMonadicMethod(concreteMethod) + || receiver.enclosingPackage == definitions.RuntimePackage + ) // only count non-closures debuglog("Treating " + i + "\n\treceiver: " + receiver + "\n\ticodes.available: " + isAvailable + "\n\tconcreteMethod.isEffectivelyFinal: " + concreteMethod.isEffectivelyFinal) - if (isAvailable && isCandidate) { - lookupIMethod(concreteMethod, receiver) match { - - case Some(callee) if callee.hasCode => - val inc = new IMethodInfo(callee) - val pair = new CallerCalleeInfo(caller, inc, fresh, inlinedMethodCount) - - if(inc.hasHandlers && (stackLength == -1)) { - // no inlining is done, yet don't warn about it, stackLength == -1 indicates we're trying to inlineWithoutTFA. - // Shortly, a TFA will be computed and an error message reported if indeed inlining not possible. - return false - } - - (pair isStampedForInlining stackLength) match { - - case inlInfo if inlInfo.isSafe => - - (inlInfo: @unchecked) match { - - case FeasibleInline(accessNeeded, toBecomePublic) => - for(f <- toBecomePublic) { - debuglog("Making public (synthetic) field-symbol: " + f) - f setFlag Flags.notPRIVATE - f setFlag Flags.notPROTECTED - } - // only add to `knownSafe` after all `toBecomePublic` fields actually made public. - if(accessNeeded == NonPublicRefs.Public) { tfa.knownSafe += inc.sym } - - case InlineableAtThisCaller => () - - } - - retry = true - inlined = true - if (isCountable) { count += 1 }; + if (!isCandidate) warnNoInline("it can be overridden") + else if (!isAvailable) warnNoInline("bytecode unavailable") + else lookupIMethod(concreteMethod, receiver) filter (callee => callee.hasCode || warnNoInline("callee has no code")) exists { callee => + val inc = new IMethodInfo(callee) + val pair = new CallerCalleeInfo(caller, inc, fresh, inlinedMethodCount) - pair.doInline(bb, i) - if (!pair.isInlineForced || inc.isMonadic) { caller.inlinedCalls += 1 }; - inlinedMethodCount(inc.sym) += 1 - - // Remove the caller from the cache (this inlining might have changed its calls-private relation). - usesNonPublics -= m - recentTFAs -= m.symbol - - - case DontInlineHere(msg) => - debuglog("inline failed, reason: " + msg) - warnNoInline(msg) - - case NeverSafeToInline => () - } - - case Some(callee) => - assert(!callee.hasCode, "The case clause right before this one should have handled this case.") - warnNoInline("callee (" + callee + ") has no code") - () + if (inc.hasHandlers && (stackLength == -1)) { + // no inlining is done, yet don't warn about it, stackLength == -1 indicates we're trying to inlineWithoutTFA. + // Shortly, a TFA will be computed and an error message reported if indeed inlining not possible. + false + } + else { + val isSafe = pair isStampedForInlining stackLength match { + case DontInlineHere(msg) => warnNoInline(msg) + case NeverSafeToInline => false + case InlineableAtThisCaller => true + case inl @ FeasibleInline(_, _) if !inl.isSafe => false + case FeasibleInline(required, toPublicize) => + for (f <- toPublicize) { + inlineLog("access", f, "making public") + f setFlag Flags.notPRIVATE + f setFlag Flags.notPROTECTED + } + // only add to `knownSafe` after all `toPublicize` fields actually made public. + if (required == NonPublicRefs.Public) + tfa.knownSafe += inc.sym - case None => - warnNoInline("bytecode was not available") - debuglog("could not find icode\n\treceiver: " + receiver + "\n\tmethod: " + concreteMethod) + true + } + isSafe && { + retry = true + if (isCountable) count += 1 + pair.doInline(bb, i) + if (!pair.isInlineForced || inc.isMonadic) caller.inlinedCalls += 1 + inlinedMethodCount(inc.sym) += 1 + + // Remove the caller from the cache (this inlining might have changed its calls-private relation). + usesNonPublics -= m + recentTFAs -= m.symbol + true + } } - } else { - warnNoInline(if(!isAvailable) "bytecode was not available" else "it can be overridden") } - - inlined } /* Pre-inlining consists in invoking the usual inlining subroutine with (receiver class, concrete method) pairs as input @@ -485,7 +487,7 @@ abstract class Inliners extends SubComponent { do { retry = false - log("Analyzing " + m + " count " + count + " with " + caller.length + " blocks") + debuglog(analyzeMessage) /* it's important not to inline in unreachable basic blocks. linearizedBlocks() returns only reachable ones. */ tfa.callerLin = caller.m.linearizedBlocks() @@ -567,9 +569,16 @@ abstract class Inliners extends SubComponent { m.normalize if (sizeBeforeInlining > 0) { val instrAfterInlining = m.code.instructionCount - val prefix = if ((instrAfterInlining > 2 * instrBeforeInlining) && (instrAfterInlining > 200)) " !! " else "" - log(prefix + " %s blocks before inlining: %d (%d) after: %d (%d)".format( - m.symbol.fullName, sizeBeforeInlining, instrBeforeInlining, m.code.blockCount, instrAfterInlining)) + val prefix = if ((instrAfterInlining > 2 * instrBeforeInlining) && (instrAfterInlining > 200)) "!!" else "" + val inlinings = caller.inlinedCalls + if (inlinings > 0) { + val s1 = s"instructions $instrBeforeInlining -> $instrAfterInlining" + val s2 = if (sizeBeforeInlining == m.code.blockCount) "" else s", blocks $sizeBeforeInlining -> ${m.code.blockCount}" + val callees = inlinedMethodCount.toList map { case (k, v) => k.fullNameString + ( if (v == 1) "" else "/" + v ) } + + inlineLog("inlined", m.symbol.fullName, callees.sorted.mkString(inlinings + " inlined: ", ", ", "")) + inlineLog("<<tldr>>", m.symbol.fullName, s"${m.symbol.nameString}: $s1$s2") + } } } @@ -589,6 +598,8 @@ abstract class Inliners extends SubComponent { } class IMethodInfo(val m: IMethod) { + override def toString = m.toString + val sym = m.symbol val name = sym.name def owner = sym.owner @@ -608,10 +619,11 @@ abstract class Inliners extends SubComponent { def instructions = m.code.instructions // def linearized = linearizer linearize m - def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10 - def isLarge = length > MAX_INLINE_SIZE - def isRecursive = m.recursive - def hasHandlers = handlers.nonEmpty || m.bytecodeHasEHs + def isSmall = (length <= SMALL_METHOD_SIZE) && blocks(0).length < 10 + def isLarge = length > MAX_INLINE_SIZE + def isRecursive = m.recursive + def hasHandlers = handlers.nonEmpty || m.bytecodeHasEHs + def hasClosureParam = paramTypes exists (tp => isByNameParamType(tp) || isFunctionType(tp)) def isSynchronized = sym.hasFlag(Flags.SYNCHRONIZED) def hasNonFinalizerHandler = handlers exists { @@ -661,9 +673,9 @@ abstract class Inliners extends SubComponent { * * TODO handle more robustly the case of a trait var changed at the source-level from public to private[this] * (eg by having ICodeReader use unpickler, see SI-5442). - + DISABLED - + def potentiallyPublicized(f: Symbol): Boolean = { (m.sourceFile eq NoSourceFile) && f.name.containsChar('$') } @@ -687,7 +699,7 @@ abstract class Inliners extends SubComponent { val i = iter.next() getAccess(i) match { case Private => - log("instruction " + i + " requires private access.") + inlineLog("access", s"instruction $i requires private access", "pos=" + i.pos) toBecomePublic = Nil seen = Private case Protected => seen = Protected @@ -764,11 +776,10 @@ abstract class Inliners extends SubComponent { tfa.warnIfInlineFails.remove(instr) val targetPos = instr.pos - log("Inlining " + inc.m + " in " + caller.m + " at pos: " + posToStr(targetPos)) def blockEmit(i: Instruction) = block.emit(i, targetPos) def newLocal(baseName: String, kind: TypeKind) = - new Local(caller.sym.newVariable(freshName(baseName), targetPos), kind, false) + new Local(caller.sym.newVariable(freshName(baseName), targetPos) setInfo kind.toType, kind, false) val (hasRETURN, a) = getRecentTFA(inc.m, isInlineForced) @@ -955,6 +966,7 @@ abstract class Inliners extends SubComponent { if(reasonWhyNever != null) { tfa.knownNever += inc.sym + inlineLog("never", inc.sym, reasonWhyNever) // next time around NeverSafeToInline is returned, thus skipping (duplicate) msg, this is intended. return DontInlineHere(inc.m + " " + reasonWhyNever) } @@ -977,10 +989,15 @@ abstract class Inliners extends SubComponent { * As a result of (b), some synthetic private members can be chosen to become public. */ - if(!isInlineForced && !isScoreOK) { + val score = inlinerScore + val scoreStr = if (score > 0) "+" + score else "" + score + val what = if (score > 0) "ok to" else "don't" + inlineLog(scoreStr, inc.m.symbol, s"$what inline into ${ownedName(caller.m.symbol)}") + + if (!isInlineForced && score <= 0) { // During inlining retry, a previous caller-callee pair that scored low may pass. // Thus, adding the callee to tfa.knownUnsafe isn't warranted. - return DontInlineHere("too low score (heuristics)") + return DontInlineHere(s"inliner heuristic") } if(inc.hasHandlers && (stackLength > inc.minimumStack)) { @@ -999,7 +1016,9 @@ abstract class Inliners extends SubComponent { val accReq = inc.accessRequirements if(!canAccess(accReq.accessNeeded)) { tfa.knownUnsafe += inc.sym - return DontInlineHere("access level required by callee not matched by caller") + val msg = "access level required by callee not matched by caller" + inlineLog("fail", inc.sym, msg) + return DontInlineHere(msg) } FeasibleInline(accReq.accessNeeded, accReq.toBecomePublic) @@ -1021,9 +1040,7 @@ abstract class Inliners extends SubComponent { * - it's good to inline closures functions. * - it's bad (useless) to inline inside bridge methods */ - def isScoreOK: Boolean = { - debuglog("shouldInline: " + caller.m + " , callee:" + inc.m) - + def inlinerScore: Int = { var score = 0 // better not inline inside closures, but hope that the closure itself is repeatedly inlined @@ -1031,21 +1048,19 @@ abstract class Inliners extends SubComponent { else if (caller.inlinedCalls < 1) score -= 1 // only monadic methods can trigger the first inline if (inc.isSmall) score += 1; + // if (inc.hasClosureParam) score += 2 if (inc.isLarge) score -= 1; if (caller.isSmall && isLargeSum) { score -= 1 - debuglog("shouldInline: score decreased to " + score + " because small " + caller + " would become large") + debuglog(s"inliner score decreased to $score because small caller $caller would become large") } if (inc.isMonadic) score += 3 else if (inc.isHigherOrder) score += 1 - if (inc.isInClosure) score += 2; - if (inlinedMethodCount(inc.sym) > 2) score -= 2; - - log("shouldInline(" + inc.m + ") score: " + score) - - score > 0 + if (inc.isInClosure) score += 2 + if (inlinedMethodCount(inc.sym) > 2) score -= 2 + score } } diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 96d7dadbd7..a2df1494ef 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -387,8 +387,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends newSym <- req.definedSymbols get name oldSym <- oldReq.definedSymbols get name.companionName } { - replwarn("warning: previously defined %s is not a companion to %s.".format( - stripString("" + oldSym), stripString("" + newSym))) + afterTyper(replwarn(s"warning: previously defined $oldSym is not a companion to $newSym.")) replwarn("Companions must be defined together; you may wish to use :paste mode for this.") } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 437a5e1434..175c322786 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -37,7 +37,7 @@ abstract class ICodeReader extends ClassfileParser { cls.info // ensure accurate type information isScalaModule = cls.isModule && !cls.isJavaDefined - log("Reading class: " + cls + " isScalaModule?: " + isScalaModule) + log("ICodeReader reading " + cls) val name = cls.javaClassName classPath.findSourceFile(name) match { @@ -99,11 +99,9 @@ abstract class ICodeReader extends ClassfileParser { if (sym == NoSymbol) sym = owner.info.findMember(newTermName(name + nme.LOCAL_SUFFIX_STRING), 0, 0, false).suchThat(_.tpe =:= tpe) if (sym == NoSymbol) { - log("Could not find symbol for " + name + ": " + tpe) - log(owner.info.member(name).tpe + " : " + tpe) sym = if (field) owner.newValue(name, owner.pos, toScalaFieldFlags(jflags)) else dummySym sym setInfoAndEnter tpe - log("added " + sym + ": " + sym.tpe) + log(s"ICodeReader could not locate ${name.decode} in $owner. Created ${sym.defString}.") } (jflags, sym) } @@ -172,10 +170,7 @@ abstract class ICodeReader extends ClassfileParser { } else if (nme.isModuleName(name)) { val strippedName = nme.stripModuleSuffix(name) - val sym = forceMangledName(newTermName(strippedName.decode), true) - - if (sym == NoSymbol) rootMirror.getModule(strippedName) - else sym + forceMangledName(newTermName(strippedName.decode), true) orElse rootMirror.getModule(strippedName) } else { forceMangledName(name, false) @@ -956,7 +951,7 @@ abstract class ICodeReader extends ClassfileParser { case None => checkValidIndex val l = freshLocal(idx, kind, false) - log("Added new local for idx " + idx + ": " + kind) + debuglog("Added new local for idx " + idx + ": " + kind) locals += (idx -> List((l, kind))) l } diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index a8cdee7154..4a668d4c61 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -79,12 +79,11 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => // -optimise and not otherwise, but the classpath can use arbitrary // logic so the classpath must be queried. if (classPath.context.isValidName(implName + ".class")) { - log("unlinking impl class " + implSym) iface.owner.info.decls unlink implSym NoSymbol } else { - log("not unlinking existing " + implSym + " as the impl class is not visible on the classpath.") + log(s"not unlinking $iface's existing implClass ${implSym.name} because it is not on the classpath.") implSym } } @@ -113,9 +112,10 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => iface.info implClassMap.getOrElse(iface, atPhase(implClassPhase) { - log("Creating implClass for " + iface) - if (iface.implClass ne NoSymbol) - log("%s.implClass already exists: %s".format(iface, iface.implClass)) + if (iface.implClass eq NoSymbol) + debuglog(s"${iface.fullLocationString} has no implClass yet, creating it now.") + else + log(s"${iface.fullLocationString} impl class is ${iface.implClass.nameString}") newImplClass(iface) }) @@ -137,7 +137,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => * given the decls ifaceDecls of its interface. */ private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = { - log("LazyImplClassType calculating decls for " + implClass) + debuglog("LazyImplClassType calculating decls for " + implClass) val decls = newScope if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol) { @@ -152,16 +152,16 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => for (sym <- ifaceDecls) { if (isInterfaceMember(sym)) { if (needsImplMethod(sym)) { - log("Cloning " + sym + " for implementation method in " + implClass) val clone = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED) if (currentRun.compiles(implClass)) implMethodMap(sym) = clone decls enter clone sym setFlag lateDEFERRED + if (!sym.isSpecialized) + log(s"Cloned ${sym.name} from ${sym.owner} into implClass ${implClass.fullName}") } - else log(sym + " needs no implementation method in " + implClass) } else { - log("Destructively modifying owner of %s from %s to %s".format(sym, sym.owner, implClass)) + log(s"Destructively modifying owner of $sym from ${sym.owner} to $implClass") sym.owner = implClass // note: OK to destructively modify the owner here, // because symbol will not be accessible from outside the sourcefile. @@ -174,7 +174,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => } override def complete(implSym: Symbol) { - log("LazyImplClassType completing " + implSym) + debuglog("LazyImplClassType completing " + implSym) /** If `tp` refers to a non-interface trait, return a * reference to its implementation class. Otherwise return `tp`. diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index d97fbf5daa..ae1a2c7e8e 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -326,7 +326,7 @@ abstract class Erasure extends AddInterfaces } // Methods on Any/Object which we rewrite here while we still know what // is a primitive and what arrived boxed. - private lazy val interceptedMethods = Set[Symbol](Any_##, Object_##, Any_getClass) ++ ( + private lazy val interceptedMethods = Set[Symbol](Any_##, Object_##, Any_getClass, AnyVal_getClass) ++ ( // Each value class has its own getClass for ultra-precise class object typing. ScalaValueClasses map (_.tpe member nme.getClass_) ) @@ -490,7 +490,7 @@ abstract class Erasure extends AddInterfaces @inline private def box(tree: Tree, target: => String): Tree = { val result = box1(tree) - log("boxing "+tree+":"+tree.tpe+" to "+target+" = "+result+":"+result.tpe) + log(s"boxing ${tree.summaryString}: ${tree.tpe} into $target: ${result.tpe}") result } @@ -525,7 +525,7 @@ abstract class Erasure extends AddInterfaces * fields (see TupleX). (ID) */ case Apply(boxFun, List(arg)) if isUnbox(tree.symbol) && safeToRemoveUnbox(arg.tpe.typeSymbol) => - log("boxing an unbox: " + tree + "/" + tree.symbol + " and replying with " + arg + " of type " + arg.tpe) + log(s"boxing an unbox: ${tree.symbol} -> ${arg.tpe}") arg case _ => (REF(boxMethod(x)) APPLY tree) setPos (tree.pos) setType ObjectClass.tpe @@ -537,7 +537,7 @@ abstract class Erasure extends AddInterfaces private def unbox(tree: Tree, pt: Type): Tree = { val result = unbox1(tree, pt) - log("unboxing "+tree+":"+tree.tpe+" to "+pt+" = "+result+":"+result.tpe) + log(s"unboxing ${tree.summaryString}: ${tree.tpe} with pt=$pt as type ${result.tpe}") result } @@ -614,7 +614,7 @@ abstract class Erasure extends AddInterfaces * @return the adapted tree */ private def adaptToType(tree: Tree, pt: Type): Tree = { - //if (settings.debug.value && pt != WildcardType) + if (settings.debug.value && pt != WildcardType) log("adapting " + tree + ":" + tree.tpe + " : " + tree.tpe.parents + " to " + pt)//debug if (tree.tpe <:< pt) tree @@ -1069,9 +1069,11 @@ abstract class Erasure extends AddInterfaces case _ => global.typer.typed(gen.mkRuntimeCall(nme.hash_, List(qual))) } - } else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) { + } else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) { // Rewrite 5.getClass to ScalaRunTime.anyValClass(5) global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen)))) + } else if (fn.symbol == AnyVal_getClass) { + tree setSymbol Object_getClass } else { tree } @@ -1079,8 +1081,8 @@ abstract class Erasure extends AddInterfaces case New(tpt) if name == nme.CONSTRUCTOR && tpt.tpe.typeSymbol.isDerivedValueClass => // println("inject derived: "+arg+" "+tpt.tpe) val List(arg) = args - InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol - new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef]) + val attachment = new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef]) + InjectDerivedValue(arg) addAttachment attachment case _ => preEraseNormalApply(tree) } diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 94eaba67d7..3bbf429fc2 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -22,12 +22,14 @@ abstract class Flatten extends InfoTransform { */ private def replaceSymbolInCurrentScope(sym: Symbol): Symbol = afterFlatten { val scope = sym.owner.info.decls - val old = scope lookup sym.name - if (old ne NoSymbol) - scope unlink old - + val old = scope lookup sym.name andAlso scope.unlink scope enter sym - log("lifted " + sym.fullLocationString) + + if (old eq NoSymbol) + log(s"lifted ${sym.fullLocationString}") + else + log(s"lifted ${sym.fullLocationString} after unlinking existing $old from scope.") + old } @@ -35,9 +37,7 @@ abstract class Flatten extends InfoTransform { if (!sym.isLifted) { sym setFlag LIFTED debuglog("re-enter " + sym.fullLocationString) - val old = replaceSymbolInCurrentScope(sym) - if (old ne NoSymbol) - log("unlinked " + old.fullLocationString + " after lifting " + sym) + replaceSymbolInCurrentScope(sym) } } private def liftSymbol(sym: Symbol) { diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index fc9e611d20..5097ecc3fe 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -436,7 +436,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val sClassMap = anyrefSpecCache.getOrElseUpdate(sClass, mutable.Map[Symbol, Symbol]()) sClassMap.getOrElseUpdate(tparam, - tparam.cloneSymbol(sClass, tparam.flags, (tparam.name append tpnme.SPECIALIZED_SUFFIX).asInstanceOf[Name]) // [Eugene] why do we need this cast? + tparam.cloneSymbol(sClass, tparam.flags, tparam.name append tpnme.SPECIALIZED_SUFFIX) modifyInfo (info => TypeBounds(info.bounds.lo, AnyRefClass.tpe)) ).tpe } @@ -811,12 +811,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { specializingOn = specializingOn filterNot (unusedStvars contains) } for (env0 <- specializations(specializingOn) if needsSpecialization(env0, sym)) yield { + // !!! Can't this logic be structured so that the new symbol's name is + // known when the symbol is cloned? It is much cleaner not to be mutating + // names after the fact. And it adds about a billion lines of + // "Renaming value _1 in class Tuple2 to _1$mcZ$sp" to obscure the small + // number of other (important) actual symbol renamings. val tps = survivingParams(sym.info.typeParams, env0) - val specMember = sym.cloneSymbol(owner, (sym.flags | SPECIALIZED) & ~DEFERRED) + val specMember = sym.cloneSymbol(owner, (sym.flags | SPECIALIZED) & ~DEFERRED) // <-- this needs newName = ... val env = mapAnyRefsInSpecSym(env0, sym, specMember) val (keys, vals) = env.toList.unzip - specMember setName specializedName(sym, env) + specMember setName specializedName(sym, env) // <-- but the name is calculated based on the cloned symbol // debuglog("%s normalizes to %s%s".format(sym, specMember, // if (tps.isEmpty) "" else " with params " + tps.mkString(", "))) @@ -897,7 +902,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { private def specializedOverload(owner: Symbol, sym: Symbol, env: TypeEnv): Symbol = { val newFlags = (sym.flags | SPECIALIZED) & ~(DEFERRED | CASEACCESSOR) // this method properly duplicates the symbol's info - ( sym.cloneSymbol(owner, newFlags, specializedName(sym, env)) + ( sym.cloneSymbol(owner, newFlags, newName = specializedName(sym, env)) modifyInfo (info => subst(env, info.asSeenFrom(owner.thisType, sym.owner))) ) } @@ -912,7 +917,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * this method will return List('apply$mcII$sp') */ - private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialOverrides(" + clazz + ")", _.nonEmpty) { + private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialized overrides in " + clazz, _.nonEmpty) { /** Return the overridden symbol in syms that needs a specialized overriding symbol, * together with its specialization environment. The overridden symbol may not be * the closest to 'overriding', in a given hierarchy. diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 181463657b..5bff653499 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -484,11 +484,7 @@ abstract class UnCurry extends InfoTransform arg setType functionType(Nil, arg.tpe) } else { - log("byname | %s | %s | %s".format( - arg.pos.source.path + ":" + arg.pos.line, fun.fullName, - if (fun.isPrivate) "private" else "") - ) - + log(s"Argument '$arg' at line ${arg.pos.safeLine} is $formal from ${fun.fullName}") arg match { // don't add a thunk for by-name argument if argument already is an application of // a Function0. We can then remove the application and use the existing Function0. diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 1b3602fca2..803fb2857e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -923,10 +923,13 @@ trait Infer { /** Is sym1 (or its companion class in case it is a module) a subclass of * sym2 (or its companion class in case it is a module)? */ - def isProperSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean = - sym1 != sym2 && sym1 != NoSymbol && (sym1 isSubClass sym2) || - sym1.isModuleClass && isProperSubClassOrObject(sym1.linkedClassOfClass, sym2) || - sym2.isModuleClass && isProperSubClassOrObject(sym1, sym2.linkedClassOfClass) + def isProperSubClassOrObject(sym1: Symbol, sym2: Symbol): Boolean = ( + (sym1 != sym2) && (sym1 != NoSymbol) && ( + (sym1 isSubClass sym2) + || (sym1.isModuleClass && isProperSubClassOrObject(sym1.linkedClassOfClass, sym2)) + || (sym2.isModuleClass && isProperSubClassOrObject(sym1, sym2.linkedClassOfClass)) + ) + ) /** is symbol `sym1` defined in a proper subclass of symbol `sym2`? */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 01e773e528..59935677a8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -630,7 +630,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { macroDef.owner) } else targ.tpe - if (tpe.isConcrete) context.TypeTag(tpe) else context.AbsTypeTag(tpe) + context.AbsTypeTag(tpe) }) macroTraceVerbose("tags: ")(tags) diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 4f597f97c9..83740f1658 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -369,7 +369,7 @@ trait MethodSynthesis { } /** A synthetic method which performs the implicit conversion implied by - * the declaration of an implicit class. Yet to be written. + * the declaration of an implicit class. */ case class ImplicitClassWrapper(tree: ClassDef) extends DerivedFromClassDef { def completer(sym: Symbol): Type = ??? // not needed @@ -377,7 +377,7 @@ trait MethodSynthesis { def derivedSym: Symbol = { // Only methods will do! Don't want to pick up any stray // companion objects of the same name. - val result = enclClass.info decl name suchThat (_.isMethod) + val result = enclClass.info decl name suchThat (x => x.isMethod && x.isSynthetic) assert(result != NoSymbol, "not found: "+name+" in "+enclClass+" "+enclClass.info.decls) result } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index adced9d8c9..62f01b8afa 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -359,10 +359,39 @@ trait Namers extends MethodSynthesis { } } + /** Given a ClassDef or ModuleDef, verifies there isn't a companion which + * has been defined in a separate file. + */ + private def validateCompanionDefs(tree: ImplDef) { + val sym = tree.symbol + if (sym eq NoSymbol) return + + val ctx = if (context.owner.isPackageObjectClass) context.outer else context + val module = if (sym.isModule) sym else ctx.scope lookup tree.name.toTermName + val clazz = if (sym.isClass) sym else ctx.scope lookup tree.name.toTypeName + val fails = ( + module.isModule + && clazz.isClass + && !module.isSynthetic + && !clazz.isSynthetic + && (clazz.sourceFile ne null) + && (module.sourceFile ne null) + && !(module isCoDefinedWith clazz) + ) + if (fails) { + context.unit.error(tree.pos, ( + s"Companions '$clazz' and '$module' must be defined in same file:\n" + + s" Found in ${clazz.sourceFile.canonicalPath} and ${module.sourceFile.canonicalPath}") + ) + } + } + def enterModuleDef(tree: ModuleDef) = { val sym = enterModuleSymbol(tree) sym.moduleClass setInfo namerOf(sym).moduleClassTypeCompleter(tree) sym setInfo completerOf(tree) + validateCompanionDefs(tree) + sym } /** Enter a module symbol. The tree parameter can be either @@ -635,6 +664,7 @@ trait Namers extends MethodSynthesis { } else context.unit.error(tree.pos, "implicit classes must accept exactly one primary constructor parameter") } + validateCompanionDefs(tree) } // this logic is needed in case typer was interrupted half @@ -699,7 +729,7 @@ trait Namers extends MethodSynthesis { // } } - def moduleClassTypeCompleter(tree: Tree) = { + def moduleClassTypeCompleter(tree: ModuleDef) = { mkTypeCompleter(tree) { sym => val moduleSymbol = tree.symbol assert(moduleSymbol.moduleClass == sym, moduleSymbol.moduleClass) @@ -1545,18 +1575,11 @@ trait Namers extends MethodSynthesis { * call this method? */ def companionSymbolOf(original: Symbol, ctx: Context): Symbol = { - try { - original.companionSymbol orElse { - ctx.lookup(original.name.companionName, original.owner).suchThat(sym => - (original.isTerm || sym.hasModuleFlag) && - (sym isCoDefinedWith original) - ) - } - } - catch { - case e: InvalidCompanions => - ctx.unit.error(original.pos, e.getMessage) - NoSymbol + original.companionSymbol orElse { + ctx.lookup(original.name.companionName, original.owner).suchThat(sym => + (original.isTerm || sym.hasModuleFlag) && + (sym isCoDefinedWith original) + ) } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 166bb2d18c..d515934c58 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -430,6 +430,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R overrideError("cannot override a macro") } else { checkOverrideTypes() + checkOverrideDeprecated() if (settings.warnNullaryOverride.value) { if (other.paramss.isEmpty && !member.paramss.isEmpty) { unit.warning(member.pos, "non-nullary method overrides nullary method") @@ -508,6 +509,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } } + + def checkOverrideDeprecated() { + if (other.hasDeprecatedOverridingAnnotation) { + val suffix = other.deprecatedOverridingMessage map (": " + _) getOrElse "" + val msg = s"overriding ${other.fullLocationString} is deprecated$suffix" + unit.deprecationWarning(member.pos, msg) + } + } } val opc = new overridingPairs.Cursor(clazz) @@ -1197,6 +1206,23 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R case _ => } + // SI-6276 warn for `def foo = foo` or `val bar: X = bar`, which come up more frequently than you might think. + def checkInfiniteLoop(valOrDef: ValOrDefDef) { + def callsSelf = valOrDef.rhs match { + case t @ (Ident(_) | Select(This(_), _)) => + t hasSymbolWhich (_.accessedOrSelf == valOrDef.symbol) + case _ => false + } + val trivialInifiniteLoop = ( + !valOrDef.isErroneous + && !valOrDef.symbol.isValueParameter + && valOrDef.symbol.paramss.isEmpty + && callsSelf + ) + if (trivialInifiniteLoop) + unit.warning(valOrDef.rhs.pos, s"${valOrDef.symbol.fullLocationString} does nothing other than call itself recursively") + } + // Transformation ------------------------------------------------------------ /* Convert a reference to a case factory of type `tpe` to a new of the class it produces. */ @@ -1640,6 +1666,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R case ValDef(_, _, _, _) | DefDef(_, _, _, _, _, _) => checkDeprecatedOvers(tree) + checkInfiniteLoop(tree.asInstanceOf[ValOrDefDef]) if (settings.warnNullaryUnit.value) checkNullaryMethodReturnType(sym) if (settings.warnInaccessible.value) { diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index d227f485c2..67afb0c118 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -63,7 +63,7 @@ trait SyntheticMethods extends ast.TreeDSL { // in the original order. def accessors = clazz.caseFieldAccessors sortBy { acc => originalAccessors indexWhere { orig => - (acc.name == orig.name) || (acc.name startsWith (orig.name append "$").asInstanceOf[Name]) // [Eugene] why do we need this cast? + (acc.name == orig.name) || (acc.name startsWith (orig.name append "$")) } } val arity = accessors.size @@ -87,7 +87,7 @@ trait SyntheticMethods extends ast.TreeDSL { ) def forwardToRuntime(method: Symbol): Tree = - forwardMethod(method, getMember(ScalaRunTimeModule, (method.name prepend "_").asInstanceOf[Name]))(mkThis :: _) // [Eugene] why do we need this cast? + forwardMethod(method, getMember(ScalaRunTimeModule, (method.name prepend "_")))(mkThis :: _) def callStaticsMethod(name: String)(args: Tree*): Tree = { val method = termMember(RuntimeStaticsModule, name) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9cf5d42e00..d90141b732 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1577,6 +1577,12 @@ trait Typers extends Modes with Adaptations with Tags { if (psym.isFinal) pending += ParentFinalInheritanceError(parent, psym) + if (psym.hasDeprecatedInheritanceAnnotation) { + val suffix = psym.deprecatedInheritanceMessage map (": " + _) getOrElse "" + val msg = s"inheritance from ${psym.fullLocationString} is deprecated$suffix" + unit.deprecationWarning(parent.pos, msg) + } + if (psym.isSealed && !phase.erasedTypes) if (context.unit.source.file == psym.sourceFile) psym addChild context.owner @@ -1871,7 +1877,7 @@ trait Typers extends Modes with Adaptations with Tags { * @param rhs ... */ def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) { - log("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs)//debug + debuglog(s"computing param aliases for $clazz:${clazz.primaryConstructor.tpe}:$rhs") def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => val (superConstr, args1) = decompose(fn) @@ -2395,7 +2401,7 @@ trait Typers extends Modes with Adaptations with Tags { else targs.init def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = - if (formals.isEmpty) { MissingParameterTypeAnonMatchError(tree, pt); Nil } + if (formals.isEmpty || !formals.forall(isFullyDefined)) { MissingParameterTypeAnonMatchError(tree, pt); Nil } else methodSym newSyntheticValueParams formals def mkSel(params: List[Symbol]) = @@ -2743,12 +2749,18 @@ trait Typers extends Modes with Adaptations with Tags { // this code by associating defaults and companion objects // with the original tree instead of the new symbol. def matches(stat: Tree, synt: Tree) = (stat, synt) match { + // synt is default arg for stat case (DefDef(_, statName, _, _, _, _), DefDef(mods, syntName, _, _, _, _)) => mods.hasDefaultFlag && syntName.toString.startsWith(statName.toString) + // synt is companion module case (ClassDef(_, className, _, _), ModuleDef(_, moduleName, _)) => className.toTermName == moduleName + // synt is implicit def for implicit class (#6278) + case (ClassDef(cmods, cname, _, _), DefDef(dmods, dname, _, _, _, _)) => + cmods.isImplicit && dmods.isImplicit && cname.toTermName == dname + case _ => false } @@ -3432,7 +3444,7 @@ trait Typers extends Modes with Adaptations with Tags { } if (hasError) annotationError - else AnnotationInfo(annType, List(), nvPairs map {p => (p._1.asInstanceOf[Name], p._2.get)}).setOriginal(Apply(typedFun, args).setPos(ann.pos)) // [Eugene] why do we need this cast? + else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}).setOriginal(Apply(typedFun, args).setPos(ann.pos)) } } else if (requireJava) { reportAnnotationError(NestedAnnotationError(ann, annType)) @@ -3811,18 +3823,23 @@ trait Typers extends Modes with Adaptations with Tags { * - simplest solution: have two method calls * */ - def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = + def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { + debuglog(s"mkInvoke($cxTree, $tree, $qual, $name)") acceptsApplyDynamicWithType(qual, name) map { tp => // tp eq NoType => can call xxxDynamic, but not passing any type args (unless specified explicitly by the user) // in scala-virtualized, when not NoType, tp is passed as type argument (for selection on a staged Struct) - // strip off type application -- we're not doing much with outer, so don't bother preserving cxTree's attributes etc - val (outer, explicitTargs) = cxTree match { - case TypeApply(fun, targs) => (fun, targs) - case Apply(TypeApply(fun, targs), args) => (Apply(fun, args), targs) - case t => (t, Nil) + // strip off type application -- we're not doing much with outer, + // so don't bother preserving cxTree's attributes etc + val cxTree1 = cxTree match { + case t: ValOrDefDef => t.rhs + case t => t + } + val (outer, explicitTargs) = cxTree1 match { + case TypeApply(fun, targs) => (fun, targs) + case Apply(TypeApply(fun, targs), args) => (Apply(fun, args), targs) + case t => (t, Nil) } - @inline def hasNamedArg(as: List[Tree]) = as.collectFirst{case AssignOrNamedArg(lhs, rhs) =>}.nonEmpty // note: context.tree includes at most one Apply node @@ -3847,6 +3864,7 @@ trait Typers extends Modes with Adaptations with Tags { atPos(qual.pos)(Apply(tappSel, List(Literal(Constant(name.decode))))) } + } } @inline final def deindentTyping() = context.typingIndentLevel -= 2 diff --git a/src/library/scala/collection/GenIterableViewLike.scala b/src/library/scala/collection/GenIterableViewLike.scala index 9e3927eaf4..142561df20 100644 --- a/src/library/scala/collection/GenIterableViewLike.scala +++ b/src/library/scala/collection/GenIterableViewLike.scala @@ -25,6 +25,7 @@ self => def iterator: Iterator[B] override def foreach[U](f: B => U): Unit = iterator foreach f override def toString = viewToString + override def isEmpty = !iterator.hasNext } trait EmptyView extends Transformed[Nothing] with super.EmptyView { diff --git a/src/library/scala/concurrent/Awaitable.scala b/src/library/scala/concurrent/Awaitable.scala index 99bdfbc5a9..655115349a 100644 --- a/src/library/scala/concurrent/Awaitable.scala +++ b/src/library/scala/concurrent/Awaitable.scala @@ -16,15 +16,34 @@ import scala.concurrent.util.Duration trait Awaitable[+T] { /** - * Should throw [[scala.concurrent.TimeoutException]] if it times out + * Await the "resolved" state of this Awaitable. * This method should not be called directly. + * + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return the Awaitable itself + * @throws InterruptedException if the wait call was interrupted + * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready + * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] */ @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) def ready(atMost: Duration)(implicit permit: CanAwait): this.type /** - * Throws exceptions if it cannot produce a T within the specified time. + * Await and return the result of this Awaitable, which is either of type T or a thrown exception (any Throwable). * This method should not be called directly. + * + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return the value if the Awaitable was successful within the specific maximum wait time + * @throws InterruptedException if the wait call was interrupted + * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready + * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] */ @throws(classOf[Exception]) def result(atMost: Duration)(implicit permit: CanAwait): T diff --git a/src/library/scala/concurrent/BlockContext.scala b/src/library/scala/concurrent/BlockContext.scala index 640560a174..83333a9e94 100644 --- a/src/library/scala/concurrent/BlockContext.scala +++ b/src/library/scala/concurrent/BlockContext.scala @@ -8,9 +8,6 @@ package scala.concurrent -import java.lang.Thread -import scala.concurrent.util.Duration - /** * A context to be notified by `scala.concurrent.blocking` when * a thread is about to block. In effect this trait provides diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index 1be6050303..844ec14241 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -10,7 +10,6 @@ package scala.concurrent import java.util.concurrent.{ ExecutorService, Executor } -import scala.concurrent.util.Duration import scala.annotation.implicitNotFound import scala.util.Try diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index bc0b437a33..a5d9cdd5d1 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -16,7 +16,6 @@ import java.lang.{ Iterable => JIterable } import java.util.{ LinkedList => JLinkedList } import java.util.concurrent.atomic.{ AtomicReferenceFieldUpdater, AtomicInteger, AtomicBoolean } -import scala.concurrent.util.Duration import scala.util.control.NonFatal import scala.Option import scala.util.{Try, Success, Failure} diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 875a558887..c517a05a81 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -14,7 +14,6 @@ import java.util.concurrent.{ LinkedBlockingQueue, Callable, Executor, ExecutorS import java.util.Collection import scala.concurrent.forkjoin._ import scala.concurrent.{ BlockContext, ExecutionContext, Awaitable, CanAwait, ExecutionContextExecutor, ExecutionContextExecutorService } -import scala.concurrent.util.Duration import scala.util.control.NonFatal diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index b19bed004b..f7ab85dc0c 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -12,7 +12,7 @@ package scala.concurrent.impl import java.util.concurrent.TimeUnit.NANOSECONDS import scala.concurrent.{ ExecutionContext, CanAwait, OnCompleteRunnable, TimeoutException, ExecutionException } -import scala.concurrent.util.Duration +import scala.concurrent.util.{ Duration, Deadline } import scala.annotation.tailrec import scala.util.control.NonFatal import scala.util.{ Try, Success, Failure } @@ -64,30 +64,41 @@ private[concurrent] object Promise { protected final def tryAwait(atMost: Duration): Boolean = { @tailrec - def awaitUnsafe(waitTimeNanos: Long): Boolean = { - if (value.isEmpty && waitTimeNanos > 0) { - val ms = NANOSECONDS.toMillis(waitTimeNanos) - val ns = (waitTimeNanos % 1000000l).toInt // as per object.wait spec - val start = System.nanoTime() - try { - synchronized { - if (!isCompleted) wait(ms, ns) // previously - this was a `while`, ending up in an infinite loop - } - } catch { - case e: InterruptedException => - } + def awaitUnsafe(deadline: Deadline, nextWait: Duration): Boolean = { + if (!isCompleted && nextWait > Duration.Zero) { + val ms = nextWait.toMillis + val ns = (nextWait.toNanos % 1000000l).toInt // as per object.wait spec + + synchronized { if (!isCompleted) wait(ms, ns) } - awaitUnsafe(waitTimeNanos - (System.nanoTime() - start)) + awaitUnsafe(deadline, deadline.timeLeft) } else isCompleted } - awaitUnsafe(if (atMost.isFinite) atMost.toNanos else Long.MaxValue) + @tailrec + def awaitUnbounded(): Boolean = { + if (isCompleted) true + else { + synchronized { if (!isCompleted) wait() } + awaitUnbounded() + } + } + + if (atMost eq Duration.Undefined) + throw new IllegalArgumentException("cannot wait for Undefined period") + else if (atMost <= Duration.Zero) + isCompleted + else if (atMost == Duration.Inf) + awaitUnbounded() + else + awaitUnsafe(atMost.fromNow, atMost) } @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) def ready(atMost: Duration)(implicit permit: CanAwait): this.type = if (isCompleted || tryAwait(atMost)) this - else throw new TimeoutException("Futures timed out after [" + atMost.toMillis + "] milliseconds") + else throw new TimeoutException("Futures timed out after [" + atMost + "]") @throws(classOf[Exception]) def result(atMost: Duration)(implicit permit: CanAwait): T = diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index a2ef42fac8..1d06341d4d 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -67,26 +67,39 @@ package concurrent { */ object Await { /** + * Await the "resolved" state of this Awaitable. * Invokes ready() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. - * ready() blocks until the awaitable has completed or the timeout expires. * - * Throws a TimeoutException if the timeout expires, as that is in the contract of `Awaitable.ready`. - * @param awaitable the `Awaitable` on which `ready` is to be called - * @param atMost the maximum timeout for which to wait - * @return the result of `awaitable.ready` which is defined to be the awaitable itself. + * @param awaitable + * the `Awaitable` on which `ready` is to be called + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return the awaitable itself + * @throws InterruptedException if the wait call was interrupted + * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready + * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] */ @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type = blocking(awaitable.ready(atMost)(AwaitPermission)) /** + * Await and return the result of this Awaitable, which is either of type T or a thrown exception (any Throwable). * Invokes result() on the awaitable, properly wrapped by a call to `scala.concurrent.blocking`. - * result() blocks until the awaitable has completed or the timeout expires. * - * Throws a TimeoutException if the timeout expires, or any exception thrown by `Awaitable.result`. - * @param awaitable the `Awaitable` on which `result` is to be called - * @param atMost the maximum timeout for which to wait - * @return the result of `awaitable.result` + * @param awaitable + * the `Awaitable` on which `result` is to be called + * @param atMost + * maximum wait time, which may be negative (no waiting is done), + * [[Duration.Inf]] for unbounded waiting, or a finite positive + * duration + * @return the value if the Awaitable was successful within the specific maximum wait time + * @throws InterruptedException if the wait call was interrupted + * @throws TimeoutException if after waiting for the specified time this Awaitable is still not ready + * @throws IllegalArgumentException if `atMost` is [[Duration.Undefined]] */ @throws(classOf[Exception]) def result[T](awaitable: Awaitable[T], atMost: Duration): T = diff --git a/src/library/scala/deprecatedInheritance.scala b/src/library/scala/deprecatedInheritance.scala new file mode 100644 index 0000000000..ca1b586223 --- /dev/null +++ b/src/library/scala/deprecatedInheritance.scala @@ -0,0 +1,22 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** An annotation that designates that inheriting from a class is deprecated. + * + * This is usually done to warn about a non-final class being made final in a future version. + * Sub-classing such a class then generates a warning. + * + * @param message the message to print during compilation if the class was sub-classed + * @param since a string identifying the first version in which inheritance was deprecated + * @since 2.10 + * @see [[scala.deprecatedOverriding]] + */ +private[scala] // for now, this needs to be generalized to communicate other modifier deltas +class deprecatedInheritance(message: String = "", since: String = "") extends annotation.StaticAnnotation diff --git a/src/library/scala/deprecatedOverriding.scala b/src/library/scala/deprecatedOverriding.scala new file mode 100644 index 0000000000..566cb59431 --- /dev/null +++ b/src/library/scala/deprecatedOverriding.scala @@ -0,0 +1,21 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala + +/** An annotation that designates that overriding a member is deprecated. + * + * Overriding such a member in a sub-class then generates a warning. + * + * @param message the message to print during compilation if the member was overridden + * @param since a string identifying the first version in which overriding was deprecated + * @since 2.10 + * @see [[scala.deprecatedInheritance]] + */ +private[scala] // for the same reasons as deprecatedInheritance +class deprecatedOverriding(message: String = "", since: String = "") extends annotation.StaticAnnotation diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 8669b2e2e8..a475d663f4 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -159,6 +159,7 @@ object BigDecimal { * @author Stephane Micheloud * @version 1.0 */ +@deprecatedInheritance("This class will me made final.", "2.10.0") class BigDecimal( val bigDecimal: BigDec, val mc: MathContext) diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 09e8ae2026..e354117e14 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -114,6 +114,7 @@ object BigInt { * @author Martin Odersky * @version 1.0, 15/07/2003 */ +@deprecatedInheritance("This class will me made final.", "2.10.0") class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericConversions with Serializable { /** Returns the hash code for this BigInt. */ override def hashCode(): Int = diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 5255c44f10..e42c89d21f 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -2,7 +2,7 @@ package scala.reflect import java.lang.{ Class => jClass } import language.{implicitConversions, existentials} -import scala.runtime.ScalaRunTime.arrayClass +import scala.runtime.ScalaRunTime.{ arrayClass, arrayElementClass } /** A `ClassTag[T]` wraps a runtime class, which can be accessed via the `runtimeClass` method. * @@ -54,35 +54,59 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial * `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)` * is uncheckable, but we have an instance of `ClassTag[T]`. */ - def unapply(x: Any): Option[T] = if (x != null && runtimeClass.isAssignableFrom(x.getClass)) Some(x.asInstanceOf[T]) else None + def unapply(x: Any): Option[T] = unapply_impl(x) + def unapply(x: Byte): Option[T] = unapply_impl(x) + def unapply(x: Short): Option[T] = unapply_impl(x) + def unapply(x: Char): Option[T] = unapply_impl(x) + def unapply(x: Int): Option[T] = unapply_impl(x) + def unapply(x: Long): Option[T] = unapply_impl(x) + def unapply(x: Float): Option[T] = unapply_impl(x) + def unapply(x: Double): Option[T] = unapply_impl(x) + def unapply(x: Boolean): Option[T] = unapply_impl(x) + def unapply(x: Unit): Option[T] = unapply_impl(x) + + private def unapply_impl[U: ClassTag](x: U): Option[T] = + if (x == null) None + else { + val staticClass = classTag[U].runtimeClass + val dynamicClass = x.getClass + val effectiveClass = if (staticClass.isPrimitive) staticClass else dynamicClass + val conforms = runtimeClass.isAssignableFrom(effectiveClass) + if (conforms) Some(x.asInstanceOf[T]) else None + } /** case class accessories */ override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass override def hashCode = scala.runtime.ScalaRunTime.hash(runtimeClass) - override def toString = "ClassTag[" + runtimeClass + "]" + override def toString = { + def prettyprint(clazz: jClass[_]): String = + if (clazz.isArray) s"Array[${prettyprint(arrayElementClass(clazz))}]" else + clazz.getName + prettyprint(runtimeClass) + } } object ClassTag { + private val ObjectTYPE = classOf[java.lang.Object] private val NothingTYPE = classOf[scala.runtime.Nothing$] private val NullTYPE = classOf[scala.runtime.Null$] - private val ObjectTYPE = classOf[java.lang.Object] - val Byte : ClassTag[scala.Byte] = new ClassTag[scala.Byte]{ def runtimeClass = java.lang.Byte.TYPE; private def readResolve() = ClassTag.Byte } - val Short : ClassTag[scala.Short] = new ClassTag[scala.Short]{ def runtimeClass = java.lang.Short.TYPE; private def readResolve() = ClassTag.Short } - val Char : ClassTag[scala.Char] = new ClassTag[scala.Char]{ def runtimeClass = java.lang.Character.TYPE; private def readResolve() = ClassTag.Char } - val Int : ClassTag[scala.Int] = new ClassTag[scala.Int]{ def runtimeClass = java.lang.Integer.TYPE; private def readResolve() = ClassTag.Int } - val Long : ClassTag[scala.Long] = new ClassTag[scala.Long]{ def runtimeClass = java.lang.Long.TYPE; private def readResolve() = ClassTag.Long } - val Float : ClassTag[scala.Float] = new ClassTag[scala.Float]{ def runtimeClass = java.lang.Float.TYPE; private def readResolve() = ClassTag.Float } - val Double : ClassTag[scala.Double] = new ClassTag[scala.Double]{ def runtimeClass = java.lang.Double.TYPE; private def readResolve() = ClassTag.Double } - val Boolean : ClassTag[scala.Boolean] = new ClassTag[scala.Boolean]{ def runtimeClass = java.lang.Boolean.TYPE; private def readResolve() = ClassTag.Boolean } - val Unit : ClassTag[scala.Unit] = new ClassTag[scala.Unit]{ def runtimeClass = java.lang.Void.TYPE; private def readResolve() = ClassTag.Unit } - val Any : ClassTag[scala.Any] = new ClassTag[scala.Any]{ def runtimeClass = ObjectTYPE; private def readResolve() = ClassTag.Any } - val Object : ClassTag[java.lang.Object] = new ClassTag[java.lang.Object]{ def runtimeClass = ObjectTYPE; private def readResolve() = ClassTag.Object } - val AnyVal : ClassTag[scala.AnyVal] = ClassTag.Object.asInstanceOf[ClassTag[scala.AnyVal]] - val AnyRef : ClassTag[scala.AnyRef] = ClassTag.Object.asInstanceOf[ClassTag[scala.AnyRef]] - val Nothing : ClassTag[scala.Nothing] = new ClassTag[scala.Nothing]{ def runtimeClass = NothingTYPE; private def readResolve() = ClassTag.Nothing } - val Null : ClassTag[scala.Null] = new ClassTag[scala.Null]{ def runtimeClass = NullTYPE; private def readResolve() = ClassTag.Null } + val Byte : ClassTag[scala.Byte] = Manifest.Byte + val Short : ClassTag[scala.Short] = Manifest.Short + val Char : ClassTag[scala.Char] = Manifest.Char + val Int : ClassTag[scala.Int] = Manifest.Int + val Long : ClassTag[scala.Long] = Manifest.Long + val Float : ClassTag[scala.Float] = Manifest.Float + val Double : ClassTag[scala.Double] = Manifest.Double + val Boolean : ClassTag[scala.Boolean] = Manifest.Boolean + val Unit : ClassTag[scala.Unit] = Manifest.Unit + val Any : ClassTag[scala.Any] = Manifest.Any + val Object : ClassTag[java.lang.Object] = Manifest.Object + val AnyVal : ClassTag[scala.AnyVal] = Manifest.AnyVal + val AnyRef : ClassTag[scala.AnyRef] = Manifest.AnyRef + val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing + val Null : ClassTag[scala.Null] = Manifest.Null def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = runtimeClass1 match { @@ -96,6 +120,8 @@ object ClassTag { case java.lang.Boolean.TYPE => ClassTag.Boolean.asInstanceOf[ClassTag[T]] case java.lang.Void.TYPE => ClassTag.Unit.asInstanceOf[ClassTag[T]] case ObjectTYPE => ClassTag.Object.asInstanceOf[ClassTag[T]] + case NothingTYPE => ClassTag.Nothing.asInstanceOf[ClassTag[T]] + case NullTYPE => ClassTag.Null.asInstanceOf[ClassTag[T]] case _ => new ClassTag[T]{ def runtimeClass = runtimeClass1 } } diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 9347f5b6bb..f2a23f4372 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -155,28 +155,34 @@ object ManifestFactory { private def readResolve(): Any = Manifest.Unit } - val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any]("Any") { + private val ObjectTYPE = classOf[java.lang.Object] + private val NothingTYPE = classOf[scala.runtime.Nothing$] + private val NullTYPE = classOf[scala.runtime.Null$] + + val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any](ObjectTYPE, "Any") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) private def readResolve(): Any = Manifest.Any } - val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object]("Object") { + val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object](ObjectTYPE, "Object") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.Object } - val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal]("AnyVal") { + val AnyRef: Manifest[scala.AnyRef] = Object.asInstanceOf[Manifest[scala.AnyRef]] + + val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal](ObjectTYPE, "AnyVal") { override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.AnyVal } - val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null]("Null") { + val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null](NullTYPE, "Null") { override def <:<(that: ClassManifest[_]): Boolean = (that ne null) && (that ne Nothing) && !(that <:< AnyVal) private def readResolve(): Any = Manifest.Null } - val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing]("Nothing") { + val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing](NothingTYPE, "Nothing") { override def <:<(that: ClassManifest[_]): Boolean = (that ne null) private def readResolve(): Any = Manifest.Nothing } @@ -211,7 +217,8 @@ object ManifestFactory { def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = new ClassTypeManifest[T](Some(prefix), clazz, args.toList) - private abstract class PhantomManifest[T](override val toString: String) extends ClassTypeManifest[T](None, classOf[java.lang.Object], Nil) { + private abstract class PhantomManifest[T](_runtimeClass: Predef.Class[_], + override val toString: String) extends ClassTypeManifest[T](None, _runtimeClass, Nil) { override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] override val hashCode = System.identityHashCode(this) } diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index e5f5e9dc5d..a8635151ff 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -167,35 +167,6 @@ object ScalaRunTime { def checkInitialized[T <: AnyRef](x: T): T = if (x == null) throw new UninitializedError else x - abstract class Try[+A] { - def Catch[B >: A](handler: PartialFunction[Throwable, B]): B - def Finally(fin: => Unit): A - } - - def Try[A](block: => A): Try[A] = new Try[A] with Runnable { - private var result: A = _ - private var exception: Throwable = - try { run() ; null } - catch { - case e: ControlThrowable => throw e // don't catch non-local returns etc - case e: Throwable => e - } - - def run() { result = block } - - def Catch[B >: A](handler: PartialFunction[Throwable, B]): B = - if (exception == null) result - else if (handler isDefinedAt exception) handler(exception) - else throw exception - - def Finally(fin: => Unit): A = { - fin - - if (exception == null) result - else throw exception - } - } - def _toString(x: Product): String = x.productIterator.mkString(x.productPrefix + "(", ",", ")") diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index f381a18b0c..7afbfcdd66 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -52,6 +52,8 @@ import language.implicitConversions * ''Note'': only non-fatal exceptions are caught by the combinators on `Try` (see [[scala.util.control.NonFatal]]). * Serious system errors, on the other hand, will be thrown. * + * ''Note:'': all Try combinators will catch exceptions and return failure unless otherwise specified in the documentation. + * * `Try` comes to the Scala standard library after years of use as an integral part of Twitter's stack. * * @author based on Twitter's original implementation in com.twitter.util. @@ -68,12 +70,19 @@ sealed abstract class Try[+T] { def isSuccess: Boolean /** Returns the value from this `Success` or the given `default` argument if this is a `Failure`. + * + * ''Note:'': This will throw an exception if it is not a success and default throws an exception. */ - def getOrElse[U >: T](default: => U) = if (isSuccess) get else default + def getOrElse[U >: T](default: => U): U = + if (isSuccess) get else default /** Returns this `Try` if it's a `Success` or the given `default` argument if this is a `Failure`. */ - def orElse[U >: T](default: => Try[U]) = if (isSuccess) this else default + def orElse[U >: T](default: => Try[U]): Try[U] = + try if (isSuccess) this else default + catch { + case NonFatal(e) => Failure(e) + } /** Returns the value from this `Success` or throws the exception if this is a `Failure`. */ @@ -81,6 +90,8 @@ sealed abstract class Try[+T] { /** * Applies the given function `f` if this is a `Success`, otherwise returns `Unit` if this is a `Failure`. + * + * ''Note:'' If `f` throws, then this method may throw an exception. */ def foreach[U](f: T => U): Unit @@ -114,7 +125,7 @@ sealed abstract class Try[+T] { /** * Returns `None` if this is a `Failure` or a `Some` containing the value if this is a `Success`. */ - def toOption = if (isSuccess) Some(get) else None + def toOption: Option[T] = if (isSuccess) Some(get) else None /** * Transforms a nested `Try`, ie, a `Try` of type `Try[Try[T]]`, @@ -131,20 +142,25 @@ sealed abstract class Try[+T] { /** Completes this `Try` by applying the function `f` to this if this is of type `Failure`, or conversely, by applying * `s` if this is a `Success`. */ - def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = this match { - case Success(v) => s(v) - case Failure(e) => f(e) - } + def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = + try this match { + case Success(v) => s(v) + case Failure(e) => f(e) + } catch { + case NonFatal(e) => Failure(e) + } } object Try { - - def apply[T](r: => T): Try[T] = { - try { Success(r) } catch { + /** Constructs a `Try` using the by-name parameter. This + * method will ensure any non-fatal exception is caught and a + * `Failure` object is returned. + */ + def apply[T](r: => T): Try[T] = + try Success(r) catch { case NonFatal(e) => Failure(e) } - } } @@ -152,24 +168,25 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { def isFailure: Boolean = true def isSuccess: Boolean = false def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = - if (f.isDefinedAt(exception)) f(exception) else this + try { + if (f isDefinedAt exception) f(exception) else this + } catch { + case NonFatal(e) => Failure(e) + } def get: T = throw exception - def flatMap[U](f: T => Try[U]): Try[U] = Failure[U](exception) - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = Failure[U](exception) - def foreach[U](f: T => U): Unit = {} - def map[U](f: T => U): Try[U] = Failure[U](exception) + def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] + def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] + def foreach[U](f: T => U): Unit = () + def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] def filter(p: T => Boolean): Try[T] = this - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = { + def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = try { - if (rescueException.isDefinedAt(exception)) { + if (rescueException isDefinedAt exception) { Try(rescueException(exception)) - } else { - this - } + } else this } catch { case NonFatal(e) => Failure(e) } - } def failed: Try[Throwable] = Success(exception) } @@ -177,7 +194,7 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { final case class Success[+T](value: T) extends Try[T] { def isFailure: Boolean = false def isSuccess: Boolean = true - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = Success(value) + def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = this def get = value def flatMap[U](f: T => Try[U]): Try[U] = try f(value) diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index 20d61d0831..376e0e9bdb 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -312,8 +312,8 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP val testFiles = dir.listFiles.toList filter isJavaOrScala def isInGroup(f: File, num: Int) = SFile(f).stripExtension endsWith ("_" + num) - val groups = (0 to 9).toList map (num => testFiles filter (f => isInGroup(f, num))) - val noGroupSuffix = testFiles filterNot (groups.flatten contains) + val groups = (0 to 9).toList map (num => (testFiles filter (f => isInGroup(f, num))).sorted) + val noGroupSuffix = (testFiles filterNot (groups.flatten contains)).sorted noGroupSuffix :: groups filterNot (_.isEmpty) } diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index d167099979..1fbbc0c0a4 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -140,18 +140,6 @@ trait Symbols extends base.Symbols { self: Universe => */ def isErroneous : Boolean - /** Can this symbol be loaded by a reflective mirror? - * - * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs. - * Such annotations (also called "pickles") are applied on top-level classes and include information - * about all symbols reachable from the annotee. However, local symbols (e.g. classes or definitions local to a block) - * are typically unreachable and information about them gets lost. - * - * This method is useful for macro writers who wish to save certain ASTs to be used at runtime. - * With `isLocatable' it's possible to check whether a tree can be retained as is, or it needs special treatment. - */ - def isLocatable: Boolean - /** Is this symbol static (i.e. with no outer instance)? * Q: When exactly is a sym marked as STATIC? * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep. diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index c21ebfe997..15b74058b7 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -277,6 +277,7 @@ trait Definitions extends api.StandardDefinitions { anyval }).asInstanceOf[ClassSymbol] lazy val AnyValTpe = definitions.AnyValClass.toTypeConstructor + def AnyVal_getClass = getMemberMethod(AnyValClass, nme.getClass_) // bottom types lazy val RuntimeNothingClass = getClassByName(fulltpnme.RuntimeNothing) @@ -940,6 +941,8 @@ trait Definitions extends api.StandardDefinitions { lazy val CloneableAttr = requiredClass[scala.annotation.cloneable] lazy val DeprecatedAttr = requiredClass[scala.deprecated] lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName] + lazy val DeprecatedInheritanceAttr = requiredClass[scala.deprecatedInheritance] + lazy val DeprecatedOverridingAttr = requiredClass[scala.deprecatedOverriding] lazy val NativeAttr = requiredClass[scala.native] lazy val RemoteAttr = requiredClass[scala.remote] lazy val ScalaInlineClass = requiredClass[scala.inline] diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala index 2fdf27d847..3f85db0f54 100644 --- a/src/reflect/scala/reflect/internal/Names.scala +++ b/src/reflect/scala/reflect/internal/Names.scala @@ -149,11 +149,15 @@ trait Names extends api.Names with LowPriorityNames { type ThisNameType >: Null <: Name protected[this] def thisName: ThisNameType + // Note that "Name with ThisNameType" should be redundant + // because ThisNameType <: Name, but due to SI-6161 the + // compile loses track of this fact. + /** Index into name table */ def start: Int = index /** The next name in the same hash bucket. */ - def next: ThisNameType + def next: Name with ThisNameType /** The length of this name. */ final def length: Int = len @@ -169,13 +173,13 @@ trait Names extends api.Names with LowPriorityNames { def bothNames: List[Name] = List(toTermName, toTypeName) /** Return the subname with characters from from to to-1. */ - def subName(from: Int, to: Int): ThisNameType + def subName(from: Int, to: Int): Name with ThisNameType /** Return a new name of the same variety. */ - def newName(str: String): ThisNameType + def newName(str: String): Name with ThisNameType /** Return a new name based on string transformation. */ - def mapName(f: String => String): ThisNameType = newName(f(toString)) + def mapName(f: String => String): Name with ThisNameType = newName(f(toString)) /** Copy bytes of this name to buffer cs, starting at position `offset`. */ final def copyChars(cs: Array[Char], offset: Int) = diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index 4100e97cdd..2424e75949 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -47,6 +47,8 @@ abstract class SymbolTable extends macros.Universe def globalError(msg: String): Unit = abort(msg) def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg)) + def shouldLogAtThisPhase = false + @deprecated("Give us a reason", "2.10.0") def abort(): Nothing = abort("unknown error") diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 3548657c04..b1e81de037 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -114,7 +114,12 @@ trait Symbols extends api.Symbols { self: SymbolTable => // with the proper specific type. def rawname: NameType def name: NameType - def name_=(n: Name): Unit + def name_=(n: Name): Unit = { + if (shouldLogAtThisPhase) { + val msg = s"Renaming $fullLocationString to $n" + if (isSpecialized) debuglog(msg) else log(msg) + } + } def asNameType(n: Name): NameType private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api @@ -697,6 +702,18 @@ trait Symbols extends api.Symbols { self: SymbolTable => def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0) + def hasDeprecatedInheritanceAnnotation + = hasAnnotation(DeprecatedInheritanceAttr) + def deprecatedInheritanceMessage + = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 0) + def deprecatedInheritanceVersion + = getAnnotation(DeprecatedInheritanceAttr) flatMap (_ stringArg 1) + def hasDeprecatedOverridingAnnotation + = hasAnnotation(DeprecatedOverridingAttr) + def deprecatedOverridingMessage + = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 0) + def deprecatedOverridingVersion + = getAnnotation(DeprecatedOverridingAttr) flatMap (_ stringArg 1) // !!! when annotation arguments are not literal strings, but any sort of // assembly of strings, there is a fair chance they will turn up here not as @@ -853,7 +870,16 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isInitialized: Boolean = validTo != NoPeriod - /** Determines whether this symbol can be loaded by subsequent reflective compilation */ + /** Can this symbol be loaded by a reflective mirror? + * + * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs. + * Such annotations (also called "pickles") are applied on top-level classes and include information + * about all symbols reachable from the annotee. However, local symbols (e.g. classes or definitions local to a block) + * are typically unreachable and information about them gets lost. + * + * This method is useful for macro writers who wish to save certain ASTs to be used at runtime. + * With `isLocatable' it's possible to check whether a tree can be retained as is, or it needs special treatment. + */ final def isLocatable: Boolean = { if (this == NoSymbol) return false if (isRoot || isRootPackage) return true @@ -945,7 +971,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** If this symbol has an expanded name, its original name, otherwise its name itself. * @see expandName */ - def originalName: Name = nme.originalName(name) + def originalName: Name = nme.originalName(nme.dropLocalSuffix(name)) /** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`. */ @@ -990,7 +1016,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def fullNameInternal(separator: Char): Name = ( if (isRoot || isRootPackage || this == NoSymbol) name else if (owner.isEffectiveRoot) name - else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name + else ((effectiveOwner.enclClass.fullNameAsName(separator) append separator): Name) append name ) def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator)) @@ -1790,26 +1816,16 @@ trait Symbols extends api.Symbols { self: SymbolTable => } else owner.enclosingTopLevelClass /** Is this symbol defined in the same scope and compilation unit as `that` symbol? */ - def isCoDefinedWith(that: Symbol) = { - (this.rawInfo ne NoType) && - (this.effectiveOwner == that.effectiveOwner) && { - !this.effectiveOwner.isPackageClass || - (this.sourceFile eq null) || - (that.sourceFile eq null) || - (this.sourceFile == that.sourceFile) || { - // recognize companion object in separate file and fail, else compilation - // appears to succeed but highly opaque errors come later: see bug #1286 - if (this.sourceFile.path != that.sourceFile.path) { - // The cheaper check can be wrong: do the expensive normalization - // before failing. - if (this.sourceFile.canonicalPath != that.sourceFile.canonicalPath) - throw InvalidCompanions(this, that) - } - - false - } - } - } + def isCoDefinedWith(that: Symbol) = ( + (this.rawInfo ne NoType) + && (this.effectiveOwner == that.effectiveOwner) + && ( !this.effectiveOwner.isPackageClass + || (this.sourceFile eq null) + || (that.sourceFile eq null) + || (this.sourceFile.path == that.sourceFile.path) // Cheap possibly wrong check, then expensive normalization + || (this.sourceFile.canonicalPath == that.sourceFile.canonicalPath) + ) + ) /** The internal representation of classes and objects: * @@ -2188,10 +2204,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => * If settings.Yshowsymkinds, adds abbreviated symbol kind. */ def nameString: String = ( - if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + decodedName - else if (settings.uniqid.value && !settings.Yshowsymkinds.value) decodedName + "#" + id - else if (!settings.uniqid.value && settings.Yshowsymkinds.value) decodedName + "#" + abbreviatedKindString - else decodedName + "#" + id + "#" + abbreviatedKindString + if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + originalName.decode + else if (settings.uniqid.value && !settings.Yshowsymkinds.value) originalName.decode + "#" + id + else if (!settings.uniqid.value && settings.Yshowsymkinds.value) originalName.decode + "#" + abbreviatedKindString + else originalName.decode + "#" + id + "#" + abbreviatedKindString ) def fullNameString: String = { @@ -2301,9 +2317,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (Statistics.hotEnabled) Statistics.incCounter(nameCount) _rawname } - def name_=(name: Name) { + override def name_=(name: Name) { if (name != rawname) { - log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name)) + super.name_=(name) // logging changeNameInOwners(name) _rawname = name.toTermName } @@ -2604,9 +2620,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => // TODO - don't allow names to be renamed in this unstructured a fashion. // Rename as little as possible. Enforce invariants on all renames. - def name_=(name: Name) { + override def name_=(name: Name) { if (name != rawname) { - log("Renaming %s %s %s to %s".format(shortSymbolClass, debugFlagString, rawname, name)) + super.name_=(name) // logging changeNameInOwners(name) _rawname = name.toTypeName } @@ -3077,7 +3093,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def asNameType(n: Name) = n.toTermName def rawname = nme.NO_NAME def name = nme.NO_NAME - def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n) + override def name_=(n: Name) = abort("Cannot set NoSymbol's name to " + n) synchronized { setInfo(NoType) @@ -3202,13 +3218,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (settings.debug.value) printStackTrace() } - case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable({ - "Companions '" + sym1 + "' and '" + sym2 + "' must be defined in same file:\n" + - " Found in " + sym1.sourceFile.canonicalPath + " and " + sym2.sourceFile.canonicalPath - }) { - override def toString = getMessage - } - /** A class for type histories */ private sealed case class TypeHistory(var validFrom: Period, info: Type, prev: TypeHistory) { assert((prev eq null) || phaseId(validFrom) > phaseId(prev.validFrom), this) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index c266e26895..df44cf234e 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -317,25 +317,6 @@ trait Types extends api.Types { self: SymbolTable => def substituteSymbols(from: List[Symbol], to: List[Symbol]): Type = substSym(from, to) def substituteTypes(from: List[Symbol], to: List[Type]): Type = subst(from, to) - def isConcrete = { - def notConcreteSym(sym: Symbol) = - sym.isAbstractType && !sym.isExistential - - def notConcreteTpe(tpe: Type): Boolean = tpe match { - case ThisType(_) => false - case SuperType(_, _) => false - case SingleType(pre, sym) => notConcreteSym(sym) - case ConstantType(_) => false - case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists notConcreteTpe) - case RefinedType(_, _) => false - case ExistentialType(_, _) => false - case AnnotatedType(_, tp, _) => notConcreteTpe(tp) - case _ => true - } - - !notConcreteTpe(this) - } - // the only thingies that we want to splice are: 1) type parameters, 2) abstract type members // the thingies that we don't want to splice are: 1) concrete types (obviously), 2) existential skolems def isSpliceable = { @@ -3473,9 +3454,9 @@ trait Types extends api.Types { self: SymbolTable => } /** A temporary type representing the erasure of a user-defined value type. - * Created during phase reasure, eliminated again in posterasure. - * @param sym The value class symbol - * @param underlying The underlying type before erasure + * Created during phase erasure, eliminated again in posterasure. + * + * @param original The underlying type before erasure */ abstract case class ErasedValueType(original: TypeRef) extends UniqueType { override def safeToString = "ErasedValueType("+original+")" diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index ffb5608fd2..0e76b711de 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -11,6 +11,8 @@ import scala.concurrent.{ import scala.concurrent.{ future, promise, blocking } import scala.util.{ Try, Success, Failure } import scala.concurrent.util.Duration +import scala.reflect.{ classTag, ClassTag } +import scala.tools.partest.TestUtil.intercept trait TestBase { @@ -19,7 +21,7 @@ trait TestBase { body(() => sv put true) sv.take(2000) } - + // def assert(cond: => Boolean) { // try { // Predef.assert(cond) @@ -663,6 +665,29 @@ trait FutureProjections extends TestBase { case nsee: NoSuchElementException => done() } } + + def testAwaitPositiveDuration(): Unit = once { done => + val p = Promise[Int]() + val f = p.future + future { + intercept[IllegalArgumentException] { Await.ready(f, Duration.Undefined) } + p.success(0) + Await.ready(f, Duration.Zero) + Await.ready(f, Duration(500, "ms")) + Await.ready(f, Duration.Inf) + done() + } onFailure { case x => throw x } + } + + def testAwaitNegativeDuration(): Unit = once { done => + val f = Promise().future + future { + intercept[TimeoutException] { Await.ready(f, Duration.Zero) } + intercept[TimeoutException] { Await.ready(f, Duration.MinusInf) } + intercept[TimeoutException] { Await.ready(f, Duration(-500, "ms")) } + done() + } onFailure { case x => throw x } + } testFailedFailureOnComplete() testFailedFailureOnSuccess() @@ -670,6 +695,8 @@ trait FutureProjections extends TestBase { testFailedSuccessOnFailure() testFailedFailureAwait() testFailedSuccessAwait() + testAwaitPositiveDuration() + testAwaitNegativeDuration() } diff --git a/test/files/neg/override.check b/test/files/neg/override.check index fc152cb3b1..8be98bf4d0 100644 --- a/test/files/neg/override.check +++ b/test/files/neg/override.check @@ -1,5 +1,5 @@ override.scala:9: error: overriding type T in trait A with bounds >: Int <: Int; type T in trait B with bounds >: String <: String has incompatible type - lazy val x : A with B = x + lazy val x : A with B = {println(""); x} ^ one error found diff --git a/test/files/neg/override.scala b/test/files/neg/override.scala index 3e589b52e3..7975516061 100755 --- a/test/files/neg/override.scala +++ b/test/files/neg/override.scala @@ -6,7 +6,7 @@ trait X { trait Y extends X { trait B { type T >: String <: String } - lazy val x : A with B = x + lazy val x : A with B = {println(""); x} n = "foo" } diff --git a/test/files/neg/t5031.check b/test/files/neg/t5031.check index 8983d8daf9..2f1090c321 100644 --- a/test/files/neg/t5031.check +++ b/test/files/neg/t5031.check @@ -1,5 +1,5 @@ -Id.scala:3: error: Companions 'class Test' and 'object Test' must be defined in same file: +package.scala:2: error: Companions 'class Test' and 'object Test' must be defined in same file: Found in t5031/package.scala and t5031/Id.scala -object Test - ^ + class Test + ^ one error found diff --git a/test/files/neg/t5031b.check b/test/files/neg/t5031b.check new file mode 100644 index 0000000000..3bc2284a4d --- /dev/null +++ b/test/files/neg/t5031b.check @@ -0,0 +1,5 @@ +b.scala:3: error: Companions 'class Bippy' and 'object Bippy' must be defined in same file: + Found in t5031b/a.scala and t5031b/b.scala +object Bippy + ^ +one error found diff --git a/test/files/neg/t5031b/a.scala b/test/files/neg/t5031b/a.scala new file mode 100644 index 0000000000..0ab9aa9769 --- /dev/null +++ b/test/files/neg/t5031b/a.scala @@ -0,0 +1,3 @@ +package foo + +class Bippy diff --git a/test/files/neg/t5031b/b.scala b/test/files/neg/t5031b/b.scala new file mode 100644 index 0000000000..bdef237af5 --- /dev/null +++ b/test/files/neg/t5031b/b.scala @@ -0,0 +1,3 @@ +package foo + +object Bippy diff --git a/test/files/neg/t6162-inheritance.check b/test/files/neg/t6162-inheritance.check new file mode 100644 index 0000000000..a7d3cc3238 --- /dev/null +++ b/test/files/neg/t6162-inheritance.check @@ -0,0 +1,10 @@ +t6162-inheritance.scala:6: error: inheritance from class Foo in package t6126 is deprecated: `Foo` will be made final in a future version. +class SubFoo extends Foo + ^ +t6162-inheritance.scala:11: error: inheritance from trait T in package t6126 is deprecated +object SubT extends T + ^ +t6162-inheritance.scala:17: error: inheritance from trait S in package t6126 is deprecated + new S { + ^ +three errors found diff --git a/test/files/neg/t6162-inheritance.flags b/test/files/neg/t6162-inheritance.flags new file mode 100644 index 0000000000..65faf53579 --- /dev/null +++ b/test/files/neg/t6162-inheritance.flags @@ -0,0 +1 @@ +-Xfatal-warnings -deprecation
\ No newline at end of file diff --git a/test/files/neg/t6162-inheritance.scala b/test/files/neg/t6162-inheritance.scala new file mode 100644 index 0000000000..7b47b9285a --- /dev/null +++ b/test/files/neg/t6162-inheritance.scala @@ -0,0 +1,19 @@ +package scala.t6126 + +@deprecatedInheritance("`Foo` will be made final in a future version.", "2.10.0") +class Foo + +class SubFoo extends Foo + +@deprecatedInheritance() +trait T + +object SubT extends T + +@deprecatedInheritance() +trait S + +object O { + new S { + } +} diff --git a/test/files/neg/t6162-overriding.check b/test/files/neg/t6162-overriding.check new file mode 100644 index 0000000000..e774888d36 --- /dev/null +++ b/test/files/neg/t6162-overriding.check @@ -0,0 +1,7 @@ +t6162-overriding.scala:14: error: overriding method bar in class Bar is deprecated: `bar` will be made private in a future version. + override def bar = 43 + ^ +t6162-overriding.scala:15: error: overriding method baz in class Bar is deprecated + override def baz = 43 + ^ +two errors found diff --git a/test/files/neg/t6162-overriding.flags b/test/files/neg/t6162-overriding.flags new file mode 100644 index 0000000000..65faf53579 --- /dev/null +++ b/test/files/neg/t6162-overriding.flags @@ -0,0 +1 @@ +-Xfatal-warnings -deprecation
\ No newline at end of file diff --git a/test/files/neg/t6162-overriding.scala b/test/files/neg/t6162-overriding.scala new file mode 100644 index 0000000000..4cab0c2dee --- /dev/null +++ b/test/files/neg/t6162-overriding.scala @@ -0,0 +1,17 @@ +package scala.t6162 + +class Bar { + @deprecatedOverriding("`bar` will be made private in a future version.", "2.10.0") + def bar = 42 + + @deprecatedOverriding() + def baz = 42 + + def baz(a: Any) = 0 +} + +class SubBar extends Bar { + override def bar = 43 + override def baz = 43 + override def baz(a: Any) = 43 // okay +} diff --git a/test/files/neg/t6258.check b/test/files/neg/t6258.check new file mode 100644 index 0000000000..73363d8280 --- /dev/null +++ b/test/files/neg/t6258.check @@ -0,0 +1,16 @@ +t6258.scala:2: error: missing parameter type for expanded function +The argument types of an anonymous function must be fully known. (SLS 8.5) +Expected type was: PartialFunction[?, Int] + val f : PartialFunction[_, Int] = { case a : Int => a } // undefined param + ^ +t6258.scala:5: error: missing parameter type for expanded function +The argument types of an anonymous function must be fully known. (SLS 8.5) +Expected type was: PartialFunction[?,Int] + foo { case a : Int => a } // undefined param + ^ +t6258.scala:22: error: missing parameter type for expanded function +The argument types of an anonymous function must be fully known. (SLS 8.5) +Expected type was: PartialFunction[?,Any] + bar[M[Any]] (foo { // undefined param + ^ +three errors found diff --git a/test/files/neg/t6258.scala b/test/files/neg/t6258.scala new file mode 100644 index 0000000000..5046a4750a --- /dev/null +++ b/test/files/neg/t6258.scala @@ -0,0 +1,25 @@ +object Test { + val f : PartialFunction[_, Int] = { case a : Int => a } // undefined param + + def foo[A](pf: PartialFunction[A, Int]) {}; + foo { case a : Int => a } // undefined param + + val g : PartialFunction[Int, _] = { case a : Int => a } // okay +} + + +// Another variation, seen in the wild with Specs2. +class X { + trait Matcher[-T] + + def bar[T](m: Matcher[T]) = null + def bar[T](i: Int) = null + + def foo[T](p: PartialFunction[T, Any]): Matcher[T] = null + + case class M[X](a: X) + + bar[M[Any]] (foo { // undefined param + case M(_) => null + }) +} diff --git a/test/files/neg/t6276.check b/test/files/neg/t6276.check new file mode 100644 index 0000000000..0b3dfa5531 --- /dev/null +++ b/test/files/neg/t6276.check @@ -0,0 +1,19 @@ +t6276.scala:4: error: method a in class C does nothing other than call itself recursively + def a: Any = a // warn + ^ +t6276.scala:5: error: value b in class C does nothing other than call itself recursively + val b: Any = b // warn + ^ +t6276.scala:7: error: method c in class C does nothing other than call itself recursively + def c: Any = this.c // warn + ^ +t6276.scala:8: error: method d in class C does nothing other than call itself recursively + def d: Any = C.this.d // warn + ^ +t6276.scala:13: error: method a does nothing other than call itself recursively + def a: Any = a // warn + ^ +t6276.scala:22: error: method a does nothing other than call itself recursively + def a = a // warn + ^ +6 errors found diff --git a/test/files/neg/t6276.flags b/test/files/neg/t6276.flags new file mode 100644 index 0000000000..85d8eb2ba2 --- /dev/null +++ b/test/files/neg/t6276.flags @@ -0,0 +1 @@ +-Xfatal-warnings diff --git a/test/files/neg/t6276.scala b/test/files/neg/t6276.scala new file mode 100644 index 0000000000..bd0a473f71 --- /dev/null +++ b/test/files/neg/t6276.scala @@ -0,0 +1,44 @@ +object Test { + def foo(a: Int, b: Int, c: Int) { + class C { + def a: Any = a // warn + val b: Any = b // warn + + def c: Any = this.c // warn + def d: Any = C.this.d // warn + } + + def method { + // method local + def a: Any = a // warn + } + + trait T { + def a: Any + } + + new T { + // inherited return type + def a = a // warn + } + + // no warnings below + new { + def a: Any = {println(""); a} + val b: Any = {println(""); b} + def c(i: Int): Any = c(i - 0) + } + + class D { + def other: D = null + def foo: Any = other.foo + } + + class E { + def foo: Any = 0 + class D extends E { + override def foo: Any = E.this.foo + } + } + } +} diff --git a/test/files/neg/t6335.check b/test/files/neg/t6335.check new file mode 100644 index 0000000000..1727a05eb2 --- /dev/null +++ b/test/files/neg/t6335.check @@ -0,0 +1,9 @@ +t6335.scala:6: error: method Z is defined twice + conflicting symbols both originated in file 't6335.scala' + implicit class Z[A](val i: A) { def zz = i } + ^ +t6335.scala:3: error: method X is defined twice + conflicting symbols both originated in file 't6335.scala' + implicit class X(val x: Int) { def xx = x } + ^ +two errors found diff --git a/test/files/neg/t6335.scala b/test/files/neg/t6335.scala new file mode 100644 index 0000000000..5c41e81ef5 --- /dev/null +++ b/test/files/neg/t6335.scala @@ -0,0 +1,7 @@ +object ImplicitClass { + def X(i: Int) {} + implicit class X(val x: Int) { def xx = x } + + def Z[A](i: A) {} + implicit class Z[A](val i: A) { def zz = i } +}
\ No newline at end of file diff --git a/test/files/pos/t6278-synth-def.scala b/test/files/pos/t6278-synth-def.scala new file mode 100644 index 0000000000..b8b660fbe3 --- /dev/null +++ b/test/files/pos/t6278-synth-def.scala @@ -0,0 +1,30 @@ + +package t6278 + +import language.implicitConversions + +object test { + def ok() { + class Foo(val i: Int) { + def foo[A](body: =>A): A = body + } + implicit def toFoo(i: Int): Foo = new Foo(i) + + val k = 1 + k foo println("k?") + val j = 2 + } + def nope() { + implicit class Foo(val i: Int) { + def foo[A](body: =>A): A = body + } + + val k = 1 + k foo println("k?") + //lazy + val j = 2 + } + def main(args: Array[String]) { + ok(); nope() + } +} diff --git a/test/files/pos/t6335.scala b/test/files/pos/t6335.scala new file mode 100644 index 0000000000..50e34092d1 --- /dev/null +++ b/test/files/pos/t6335.scala @@ -0,0 +1,25 @@ +object E extends Z { + def X = 3 + implicit class X(val i: Int) { + def xx = i + } + + def Y(a: Any) = 0 + object Y + implicit class Y(val i: String) { def yy = i } + + implicit class Z(val i: Boolean) { def zz = i } +} + +trait Z { + def Z = 0 +} + +object Test { + import E._ + 0.xx + + "".yy + + true.zz +} diff --git a/test/files/run/classtags_core.check b/test/files/run/classtags_core.check index 6519db2178..5a9b41fd6d 100644 --- a/test/files/run/classtags_core.check +++ b/test/files/run/classtags_core.check @@ -1,30 +1,30 @@ true
-ClassTag[byte]
+Byte
true
-ClassTag[short]
+Short
true
-ClassTag[char]
+Char
true
-ClassTag[int]
+Int
true
-ClassTag[long]
+Long
true
-ClassTag[float]
+Float
true
-ClassTag[double]
+Double
true
-ClassTag[boolean]
+Boolean
true
-ClassTag[void]
+Unit
true
-ClassTag[class java.lang.Object]
+Any
true
-ClassTag[class java.lang.Object]
+AnyVal
true
-ClassTag[class java.lang.Object]
+Object
true
-ClassTag[class java.lang.Object]
+Object
true
-ClassTag[class scala.runtime.Null$]
+Null
true
-ClassTag[class scala.runtime.Nothing$]
+Nothing
diff --git a/test/files/run/classtags_multi.check b/test/files/run/classtags_multi.check index 3a7f16c3a0..68cee4841d 100644 --- a/test/files/run/classtags_multi.check +++ b/test/files/run/classtags_multi.check @@ -1,5 +1,5 @@ -ClassTag[int]
-ClassTag[class [I]
-ClassTag[class [[I]
-ClassTag[class [[[I]
-ClassTag[class [[[[I]
+Int
+Array[int]
+Array[Array[int]]
+Array[Array[Array[int]]]
+Array[Array[Array[Array[int]]]]
diff --git a/test/files/run/compiler-asSeenFrom.check b/test/files/run/compiler-asSeenFrom.check index 96e257d303..47d40b0331 100644 --- a/test/files/run/compiler-asSeenFrom.check +++ b/test/files/run/compiler-asSeenFrom.check @@ -269,8 +269,8 @@ value jZ { // after parser value jZ { // after explicitouter protected val $outer: D.this.type - val ll$D$J$$$outer(): D.this.type - val ll$C$I$$$outer(): C.this.type + val $outer(): D.this.type + val $outer(): C.this.type def thisI(): I.this.type def thisC(): C.this.type def t2(): T2 @@ -279,9 +279,9 @@ value jZ { // after explicitouter value jZ { // after erasure protected val $outer: ll.D - val ll$D$J$$$outer(): ll.D + val $outer(): ll.D protected val $outer: ll.C - val ll$C$I$$$outer(): ll.C + val $outer(): ll.C def thisI(): ll.C#I def thisC(): ll.C def t2(): Object @@ -290,9 +290,9 @@ value jZ { // after erasure value jZ { // after flatten protected val $outer: ll.D - val ll$D$J$$$outer(): ll.D + val $outer(): ll.D protected val $outer: ll.C - val ll$C$I$$$outer(): ll.C + val $outer(): ll.C def thisI(): ll.C#C$I def thisC(): ll.C def t2(): Object diff --git a/test/files/run/getClassTest-valueClass.check b/test/files/run/getClassTest-valueClass.check new file mode 100644 index 0000000000..7608d92b4e --- /dev/null +++ b/test/files/run/getClassTest-valueClass.check @@ -0,0 +1,2 @@ +int +class V diff --git a/test/files/run/getClassTest-valueClass.scala b/test/files/run/getClassTest-valueClass.scala new file mode 100644 index 0000000000..05a116dfff --- /dev/null +++ b/test/files/run/getClassTest-valueClass.scala @@ -0,0 +1,10 @@ +class V(val x: Int) extends AnyVal + +object Test { + def main(args: Array[String]) = { + val v = new V(2) + val s: Any = 2 + println(2.getClass) + println(v.getClass) + } +} diff --git a/test/files/run/interop_classtags_are_classmanifests.check b/test/files/run/interop_classtags_are_classmanifests.check index 7a0a829af2..c07ed0e657 100644 --- a/test/files/run/interop_classtags_are_classmanifests.check +++ b/test/files/run/interop_classtags_are_classmanifests.check @@ -1,3 +1,3 @@ -ClassTag[int]
-ClassTag[class java.lang.String]
-ClassTag[class [I]
+Int
+java.lang.String
+Array[int]
diff --git a/test/files/run/macro-expand-tparams-implicit.check b/test/files/run/macro-expand-tparams-implicit.check index 80c6b826ba..1c1a785706 100644 --- a/test/files/run/macro-expand-tparams-implicit.check +++ b/test/files/run/macro-expand-tparams-implicit.check @@ -1,2 +1,2 @@ TypeTag[Int]
-TypeTag[String]
+AbsTypeTag[String]
diff --git a/test/files/run/macro-expand-tparams-prefix-a.check b/test/files/run/macro-expand-tparams-prefix-a.check index 6c23b47d64..6a7f9c5f52 100644 --- a/test/files/run/macro-expand-tparams-prefix-a.check +++ b/test/files/run/macro-expand-tparams-prefix-a.check @@ -1,4 +1,4 @@ TypeTag[Int]
TypeTag[Int]
-TypeTag[String]
+AbsTypeTag[String]
TypeTag[Boolean]
diff --git a/test/files/run/macro-expand-tparams-prefix-b.check b/test/files/run/macro-expand-tparams-prefix-b.check index 67dabff11e..daae32bd0a 100644 --- a/test/files/run/macro-expand-tparams-prefix-b.check +++ b/test/files/run/macro-expand-tparams-prefix-b.check @@ -1,2 +1,2 @@ TypeTag[Boolean] TypeTag[Int]
-TypeTag[Boolean] TypeTag[String]
+TypeTag[Boolean] AbsTypeTag[String]
diff --git a/test/files/run/macro-expand-tparams-prefix-c1.check b/test/files/run/macro-expand-tparams-prefix-c1.check index 8d1c4e3416..5356b3e6d1 100644 --- a/test/files/run/macro-expand-tparams-prefix-c1.check +++ b/test/files/run/macro-expand-tparams-prefix-c1.check @@ -1,3 +1,3 @@ TypeTag[Int]
-TypeTag[String]
+AbsTypeTag[String]
TypeTag[Boolean]
diff --git a/test/files/run/macro-expand-tparams-prefix-c2.check b/test/files/run/macro-expand-tparams-prefix-c2.check index 8d1c4e3416..5356b3e6d1 100644 --- a/test/files/run/macro-expand-tparams-prefix-c2.check +++ b/test/files/run/macro-expand-tparams-prefix-c2.check @@ -1,3 +1,3 @@ TypeTag[Int]
-TypeTag[String]
+AbsTypeTag[String]
TypeTag[Boolean]
diff --git a/test/files/run/macro-undetparams-macroitself.check b/test/files/run/macro-undetparams-macroitself.check index 80c6b826ba..1c1a785706 100644 --- a/test/files/run/macro-undetparams-macroitself.check +++ b/test/files/run/macro-undetparams-macroitself.check @@ -1,2 +1,2 @@ TypeTag[Int]
-TypeTag[String]
+AbsTypeTag[String]
diff --git a/test/files/run/t5881.check b/test/files/run/t5881.check index 477fb935a8..8e596e9323 100644 --- a/test/files/run/t5881.check +++ b/test/files/run/t5881.check @@ -1,2 +1,2 @@ -ClassTag[class scala.collection.immutable.List]
-ClassTag[class scala.collection.immutable.List]
+scala.collection.immutable.List
+scala.collection.immutable.List
diff --git a/test/files/run/t6246.check b/test/files/run/t6246.check new file mode 100644 index 0000000000..9532185ead --- /dev/null +++ b/test/files/run/t6246.check @@ -0,0 +1,90 @@ +runtimeClass = byte, toString = Byte +true +true +true +false +true +false +false +false +false +runtimeClass = short, toString = Short +true +true +true +false +true +false +false +false +false +runtimeClass = char, toString = Char +true +true +true +false +true +false +false +false +false +runtimeClass = int, toString = Int +true +true +true +false +true +false +false +false +false +runtimeClass = long, toString = Long +true +true +true +false +true +false +false +false +false +runtimeClass = float, toString = Float +true +true +true +false +true +false +false +false +false +runtimeClass = double, toString = Double +true +true +true +false +true +false +false +false +false +runtimeClass = void, toString = Unit +true +true +true +false +true +false +false +false +false +runtimeClass = boolean, toString = Boolean +true +true +true +false +true +false +false +false +false
\ No newline at end of file diff --git a/test/files/run/t6246.scala b/test/files/run/t6246.scala new file mode 100644 index 0000000000..28765e1adf --- /dev/null +++ b/test/files/run/t6246.scala @@ -0,0 +1,26 @@ +import scala.reflect.{ClassTag, classTag} + +object Test extends App { + def testValueClass(tag: ClassTag[_]) { + println(s"runtimeClass = ${tag.runtimeClass}, toString = ${tag.toString}") + println(tag <:< tag) + println(tag <:< ClassTag.AnyVal) + println(tag <:< ClassTag.Any) + println(tag <:< ClassTag.Nothing) + println(ClassTag.Nothing <:< tag) + println(tag <:< ClassTag.Null) + println(ClassTag.Null <:< tag) + println(tag <:< ClassTag.Object) + println(ClassTag.Object <:< tag) + } + + testValueClass(ClassTag.Byte) + testValueClass(ClassTag.Short) + testValueClass(ClassTag.Char) + testValueClass(ClassTag.Int) + testValueClass(ClassTag.Long) + testValueClass(ClassTag.Float) + testValueClass(ClassTag.Double) + testValueClass(ClassTag.Unit) + testValueClass(ClassTag.Boolean) +}
\ No newline at end of file diff --git a/test/files/run/t6271.scala b/test/files/run/t6271.scala new file mode 100644 index 0000000000..8ebf7ad8b5 --- /dev/null +++ b/test/files/run/t6271.scala @@ -0,0 +1,32 @@ +object Test extends App { + def filterIssue = { + val viewed : Iterable[Iterable[Int]] = List(List(0).view).view + val filtered = viewed flatMap { x => List( x filter (_ > 0) ) } + filtered.iterator.toIterable.flatten + } + def takenIssue = { + val viewed : Iterable[Iterable[Int]] = List(List(0).view).view + val filtered = viewed flatMap { x => List( x take 0 ) } + filtered.iterator.toIterable.flatten + } + def droppedIssue = { + val viewed : Iterable[Iterable[Int]] = List(List(0).view).view + val filtered = viewed flatMap { x => List( x drop 1 ) } + filtered.iterator.toIterable.flatten + } + def flatMappedIssue = { + val viewed : Iterable[Iterable[Int]] = List(List(0).view).view + val filtered = viewed flatMap { x => List( x flatMap (_ => List()) ) } + filtered.iterator.toIterable.flatten + } + def slicedIssue = { + val viewed : Iterable[Iterable[Int]] = List(List(0).view).view + val filtered = viewed flatMap { x => List( x slice (2,3) ) } + filtered.iterator.toIterable.flatten + } + filterIssue + takenIssue + droppedIssue + flatMappedIssue + slicedIssue +} diff --git a/test/files/run/t6318_derived.check b/test/files/run/t6318_derived.check new file mode 100644 index 0000000000..ad43b6579b --- /dev/null +++ b/test/files/run/t6318_derived.check @@ -0,0 +1,3 @@ +Some(X)
+true
+Some(X)
diff --git a/test/files/run/t6318_derived.scala b/test/files/run/t6318_derived.scala new file mode 100644 index 0000000000..ccdc18daee --- /dev/null +++ b/test/files/run/t6318_derived.scala @@ -0,0 +1,15 @@ +import scala.reflect.{ClassTag, classTag} + +object Test extends App { + def test[T: ClassTag](x: T) { + println(classTag[T].runtimeClass.isAssignableFrom(x.getClass)) + println(classTag[T].unapply(x)) + } + + class X(val x: Int) extends AnyVal { override def toString = "X" } + val x = new X(1) + // the commented line crashes because of SI-6326 + //println(classTag[X].runtimeClass.isAssignableFrom(x.getClass)) + println(classTag[X].unapply(x)) + test(x) +}
\ No newline at end of file diff --git a/test/files/run/t6318_primitives.check b/test/files/run/t6318_primitives.check new file mode 100644 index 0000000000..bb474c3bdc --- /dev/null +++ b/test/files/run/t6318_primitives.check @@ -0,0 +1,36 @@ +true
+Some(1)
+false
+None
+true
+Some(1)
+false
+None
+true
+Some()
+false
+None
+true
+Some(1)
+false
+None
+true
+Some(1)
+false
+None
+true
+Some(1.0)
+false
+None
+true
+Some(1.0)
+false
+None
+true
+Some(true)
+false
+None
+true
+Some(())
+false
+None
diff --git a/test/files/run/t6318_primitives.scala b/test/files/run/t6318_primitives.scala new file mode 100644 index 0000000000..30f27120b3 --- /dev/null +++ b/test/files/run/t6318_primitives.scala @@ -0,0 +1,71 @@ +import scala.reflect.{ClassTag, classTag} + +object Test extends App { + def test[T: ClassTag](x: T) { + println(classTag[T].runtimeClass.isAssignableFrom(x.getClass)) + println(classTag[T].unapply(x)) + } + + { + val x = 1.toByte + println(ClassTag.Byte.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Byte.unapply(x)) + test(x) + } + + { + val x = 1.toShort + println(ClassTag.Short.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Short.unapply(x)) + test(x) + } + + { + val x = 1.toChar + println(ClassTag.Char.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Char.unapply(x)) + test(x) + } + + { + val x = 1.toInt + println(ClassTag.Int.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Int.unapply(x)) + test(x) + } + + { + val x = 1.toLong + println(ClassTag.Long.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Long.unapply(x)) + test(x) + } + + { + val x = 1.toFloat + println(ClassTag.Float.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Float.unapply(x)) + test(x) + } + + { + val x = 1.toDouble + println(ClassTag.Double.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Double.unapply(x)) + test(x) + } + + { + val x = true + println(ClassTag.Boolean.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Boolean.unapply(x)) + test(x) + } + + { + val x = () + println(ClassTag.Unit.runtimeClass.isAssignableFrom(x.getClass)) + println(ClassTag.Unit.unapply(x)) + test(x) + } +}
\ No newline at end of file diff --git a/test/files/run/t6327.check b/test/files/run/t6327.check new file mode 100644 index 0000000000..f7bacac931 --- /dev/null +++ b/test/files/run/t6327.check @@ -0,0 +1,4 @@ +A +A +A +A diff --git a/test/files/run/t6327.scala b/test/files/run/t6327.scala new file mode 100644 index 0000000000..7683101f14 --- /dev/null +++ b/test/files/run/t6327.scala @@ -0,0 +1,22 @@ +import language._ + +object Test extends App { + + case class R[+T](s: String) { def x() = println(s) } + + // Implicits in contention; StringR is nested to avoid ambiguity + object R { implicit val StringR = R[String]("A") } + implicit val Default = R[Any]("B") + + class B() extends Dynamic { + def selectDynamic[T](f: String)(implicit r: R[T]): Unit = r.x() + } + + val b = new B() + + // These should all produce the same output, but they don't + b.selectDynamic[String]("baz") + b.baz[String] + val c = b.selectDynamic[String]("baz") + val d = b.baz[String] +} diff --git a/test/files/run/t6333.scala b/test/files/run/t6333.scala new file mode 100644 index 0000000000..266d95ce69 --- /dev/null +++ b/test/files/run/t6333.scala @@ -0,0 +1,29 @@ +object Test extends App { + import util.Try + + val a = "apple" + def fail: String = throw new Exception("Fail!") + def argh: Try[String] = throw new Exception("Argh!") + + // No throw tests + def tryMethods(expr: => String): Unit = { + Try(expr) orElse argh + Try(expr).transform(_ => argh, _ => argh) + Try(expr).recoverWith { case e if (a == fail) => Try(a) } + Try(expr).recoverWith { case _ => argh } + Try(expr).getOrElse(a) + // TODO - Fail getOrElse? + Try(expr) orElse argh + Try(expr) orElse Try(a) + Try(expr) map (_ => fail) + Try(expr) map (_ => a) + Try(expr) flatMap (_ => argh) + Try(expr) flatMap (_ => Try(a)) + Try(expr) filter (_ => throw new Exception("O NOES")) + Try(expr) filter (_ => true) + Try(expr) recover { case _ => fail } + Try(expr).failed + } + tryMethods(a) + tryMethods(fail) +} diff --git a/test/files/run/valueclasses-classtag-basic.check b/test/files/run/valueclasses-classtag-basic.check index 0c13986b32..554c75e074 100644 --- a/test/files/run/valueclasses-classtag-basic.check +++ b/test/files/run/valueclasses-classtag-basic.check @@ -1 +1 @@ -ClassTag[class Foo]
+Foo
diff --git a/test/files/run/valueclasses-classtag-existential.check b/test/files/run/valueclasses-classtag-existential.check index 95e94e7aee..15ac02630f 100644 --- a/test/files/run/valueclasses-classtag-existential.check +++ b/test/files/run/valueclasses-classtag-existential.check @@ -1 +1 @@ -ClassTag[class java.lang.Object]
+Object
diff --git a/test/files/run/valueclasses-classtag-generic.check b/test/files/run/valueclasses-classtag-generic.check index 0c13986b32..554c75e074 100644 --- a/test/files/run/valueclasses-classtag-generic.check +++ b/test/files/run/valueclasses-classtag-generic.check @@ -1 +1 @@ -ClassTag[class Foo]
+Foo
diff --git a/test/files/run/virtpatmat_typetag.check b/test/files/run/virtpatmat_typetag.check index f9800b84d0..eaa9f3361f 100644 --- a/test/files/run/virtpatmat_typetag.check +++ b/test/files/run/virtpatmat_typetag.check @@ -1,10 +1,10 @@ -1 is not a ClassTag[int]; it's a class java.lang.Integer -1 is a ClassTag[class java.lang.Integer] -1 is not a ClassTag[class java.lang.String]; it's a class java.lang.Integer -true is a ClassTag[class java.lang.Object] -woele is a ClassTag[class java.lang.String] -1 is not a ClassTag[int]; it's a class java.lang.Integer -1 is a ClassTag[class java.lang.Integer] -1 is not a ClassTag[class java.lang.String]; it's a class java.lang.Integer -true is a ClassTag[class java.lang.Object] -woele is a ClassTag[class java.lang.String] +1 is not a Int; it's a class java.lang.Integer
+1 is a java.lang.Integer
+1 is not a java.lang.String; it's a class java.lang.Integer
+true is a Any
+woele is a java.lang.String
+1 is not a Int; it's a class java.lang.Integer
+1 is a java.lang.Integer
+1 is not a java.lang.String; it's a class java.lang.Integer
+true is a Any
+woele is a java.lang.String
diff --git a/test/files/pos/t2868.cmds b/test/flaky/pos/t2868.cmds index ed8124a9e0..ed8124a9e0 100644 --- a/test/files/pos/t2868.cmds +++ b/test/flaky/pos/t2868.cmds diff --git a/test/files/pos/t2868/Jann.java b/test/flaky/pos/t2868/Jann.java index f5b68de7b0..f5b68de7b0 100644 --- a/test/files/pos/t2868/Jann.java +++ b/test/flaky/pos/t2868/Jann.java diff --git a/test/files/pos/t2868/Nest.java b/test/flaky/pos/t2868/Nest.java index 53652291ad..53652291ad 100644 --- a/test/files/pos/t2868/Nest.java +++ b/test/flaky/pos/t2868/Nest.java diff --git a/test/files/pos/t2868/pick_1.scala b/test/flaky/pos/t2868/pick_1.scala index a211687432..a211687432 100644 --- a/test/files/pos/t2868/pick_1.scala +++ b/test/flaky/pos/t2868/pick_1.scala diff --git a/test/files/pos/t2868/t2868_src_2.scala b/test/flaky/pos/t2868/t2868_src_2.scala index f11ef0fae2..f11ef0fae2 100644 --- a/test/files/pos/t2868/t2868_src_2.scala +++ b/test/flaky/pos/t2868/t2868_src_2.scala |