diff options
author | Martin Odersky <odersky@gmail.com> | 2012-04-05 17:17:39 -0700 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2012-04-05 17:17:39 -0700 |
commit | 115f5467e3f3ff07abbba2b23c40c2ff0d7ddd1b (patch) | |
tree | 15265c311900918c79c5eda8d54c58fc145ef4a8 | |
parent | 7f79ef0e30f088b41b14763f44338c240acf1a63 (diff) | |
parent | 754b4a85e4093f25cc10f092fefdb34215097c94 (diff) | |
download | scala-115f5467e3f3ff07abbba2b23c40c2ff0d7ddd1b.tar.gz scala-115f5467e3f3ff07abbba2b23c40c2ff0d7ddd1b.tar.bz2 scala-115f5467e3f3ff07abbba2b23c40c2ff0d7ddd1b.zip |
Merge branch 'master' into topic/reflect
53 files changed, 1216 insertions, 250 deletions
@@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="sabbus" default="build"> +<project name="sabbus" default="build" xmlns:artifact="urn:maven-artifact-ant"> <description> SuperSabbus for Scala core, builds the scala library and compiler. It can also package it as a simple distribution, tests it for stable bootstrapping and against the Scala test suite. </description> @@ -238,6 +238,21 @@ INITIALISATION </touch> </target> + <!-- Add our maven ant tasks --> + <target name="init.maven.tasks" depends="init.jars.check" unless="init.maven.tasks.finished"> + <path id="maven-ant-tasks.classpath" path="${lib.dir}/ant/maven-ant-tasks-2.1.1.jar" /> + <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" /> + + <property name="init.maven.tasks.finished" value="true" /> + </target> + + <!-- Resolve maven dependencies --> + <target name="init.maven.jars" depends="init.maven.tasks"> + <artifact:dependencies pathId="dependency.classpath" filesetId="dependency.fileset"> + <dependency groupId="org.skife.com.typesafe.config" artifactId="typesafe-config" version="0.3.0"/> + </artifact:dependencies> + </target> + <!-- Determines OSGi string + maven extension. --> <target name="init.hasbuildnum"> <condition property="version.hasbuildnum"> @@ -296,7 +311,7 @@ INITIALISATION <target name="init.version.done" depends="init.version.release, init.version.snapshot"/> - <target name="init" depends="init.jars, init.version.done"> + <target name="init" depends="init.jars, init.maven.jars, init.version.done"> <!-- scalac.args.optimise is selectively overridden in certain antcall tasks. --> <property name="scalac.args.optimise" value=""/> <!-- scalac.args.quickonly are added to quick.* targets but not others (particularly, locker.) @@ -337,6 +352,7 @@ INITIALISATION </fileset> <pathelement location="${ant.jar}"/> <path refid="lib.extra"/> + <path refid="dependency.classpath"/> </path> <!-- And print-out what we are building --> @@ -1002,6 +1018,11 @@ PACKED QUICK BUILD (PACK) <target name="pack.lib" depends="pack.pre-lib" unless="pack.lib.available"> <mkdir dir="${build-pack.dir}/lib"/> + <!-- First copy maven dependencies --> + <copy todir="${build-pack.dir}/lib"> + <fileset refid="dependency.fileset" /> + <mapper type="flatten" /> + </copy> <jar destfile="${build-pack.dir}/lib/scala-library.jar"> <fileset dir="${build-quick.dir}/classes/library"> <exclude name="scala/dbc/**"/> diff --git a/src/build/maven/scala-library-pom.xml b/src/build/maven/scala-library-pom.xml index 673c3dfada..c3f8a4531c 100644 --- a/src/build/maven/scala-library-pom.xml +++ b/src/build/maven/scala-library-pom.xml @@ -30,17 +30,24 @@ <system>JIRA</system> <url>https://issues.scala-lang.org/</url> </issueManagement> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> + <dependencies> + <dependency> + <groupId>org.skife.com.typesafe.config</groupId> + <artifactId>typesafe-config</artifactId> + <version>0.3.0</version> + </dependency> + </dependencies> + <distributionManagement> + <repository> + <id>scala-tools.org</id> + <url>@RELEASE_REPOSITORY@</url> + </repository> + <snapshotRepository> + <id>scala-tools.org</id> + <url>@SNAPSHOT_REPOSITORY@</url> + <uniqueVersion>false</uniqueVersion> + </snapshotRepository> + </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index bb11ca634a..256c1a6ced 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -62,6 +62,11 @@ abstract class SymbolTable extends api.Universe result } + final val traceSymbolActivity = sys.props contains "scalac.debug.syms" + object traceSymbols extends { + val global: SymbolTable.this.type = SymbolTable.this + } with util.TraceSymbolActivity + /** Are we compiling for Java SE? */ // def forJVM: Boolean diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 4842d47e4d..63d030531d 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -3,7 +3,6 @@ * @author Martin Odersky */ - package scala.reflect package internal @@ -166,9 +165,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => private var rawpos = initPos val id = nextId() // identity displayed when -uniqid - private[this] var _validTo: Period = NoPeriod + if (traceSymbolActivity) + traceSymbols.recordNewSymbol(this) + def validTo = _validTo def validTo_=(x: Period) { _validTo = x} @@ -863,6 +864,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => else originalOwner(this) = rawowner } assert(!inReflexiveMirror, "owner_= is not thread-safe; cannot be run in reflexive code") + if (traceSymbolActivity) + traceSymbols.recordNewSymbolOwner(this, owner) _rawowner = owner } diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 5afa5343ed..786b680ff8 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -5059,6 +5059,8 @@ trait Types extends api.Types { self: SymbolTable => case (_, tv @ TypeVar(_,_)) => tv.registerTypeSelection(tr2.sym, tr1) case _ => false }) + case _: SingleType => + return isSameType2(tp2, tp1) // put singleton type on the left, caught below case _ => } case tt1: ThisType => @@ -5071,6 +5073,8 @@ trait Types extends api.Types { self: SymbolTable => tp2 match { case st2: SingleType => if (equalSymsAndPrefixes(st1.sym, st1.pre, st2.sym, st2.pre)) return true + case TypeRef(pre2, sym2, Nil) => + if (sym2.isModuleClass && equalSymsAndPrefixes(st1.sym, st1.pre, sym2.sourceModule, pre2)) return true case _ => } case ct1: ConstantType => @@ -5481,7 +5485,7 @@ trait Types extends api.Types { self: SymbolTable => * - handle typerefs, refined types, notnull and singleton types. */ def fourthTry = tp1 match { - case tr1 @ TypeRef(_, sym1, _) => + case tr1 @ TypeRef(pre1, sym1, _) => sym1 match { case NothingClass => true case NullClass => @@ -5495,8 +5499,8 @@ trait Types extends api.Types { self: SymbolTable => if (isRaw(sym1, tr1.args)) isSubType(rawToExistential(tp1), tp2, depth) else if (sym1.isModuleClass) tp2 match { - case SingleType(_, sym2) => sym1 == sym2 - case _ => false + case SingleType(pre2, sym2) => equalSymsAndPrefixes(sym1.sourceModule, pre1, sym2, pre2) + case _ => false } else if (sym1.isRefinementClass) isSubType(sym1.info, tp2, depth) diff --git a/src/compiler/scala/reflect/internal/util/TraceSymbolActivity.scala b/src/compiler/scala/reflect/internal/util/TraceSymbolActivity.scala new file mode 100644 index 0000000000..eb384f9a85 --- /dev/null +++ b/src/compiler/scala/reflect/internal/util/TraceSymbolActivity.scala @@ -0,0 +1,168 @@ +package scala.reflect.internal +package util + +import scala.collection.{ mutable, immutable } + +trait TraceSymbolActivity { + val global: SymbolTable + import global._ + + if (traceSymbolActivity) + scala.sys addShutdownHook showAllSymbols() + + private type Set[T] = scala.collection.immutable.Set[T] + private val Set = scala.collection.immutable.Set + + val allSymbols = mutable.Map[Int, Symbol]() + val allChildren = mutable.Map[Int, List[Int]]() withDefaultValue Nil + val prevOwners = mutable.Map[Int, List[(Int, Phase)]]() withDefaultValue Nil + val symsCaused = mutable.Map[Int, Int]() withDefaultValue 0 + val allTrees = mutable.Set[Tree]() + + def recordSymbolsInTree(tree: Tree) { + allTrees += tree + } + + def recordNewSymbol(sym: Symbol) { + if (sym.id > 1) { + allSymbols(sym.id) = sym + allChildren(sym.owner.id) ::= sym.id + } + } + def recordNewSymbolOwner(sym: Symbol, newOwner: Symbol) { + val sid = sym.id + val oid = sym.owner.id + val nid = newOwner.id + + prevOwners(sid) ::= (oid -> phase) + allChildren(oid) = allChildren(oid) filterNot (_ == sid) + allChildren(nid) ::= sid + } + + /** TODO. + */ + private def reachableDirectlyFromSymbol(sym: Symbol): List[Symbol] = ( + List(sym.owner, sym.alias, sym.thisSym) + ++ sym.children + ++ sym.info.parents.map(_.typeSymbol) + ++ sym.typeParams + ++ sym.paramss.flatten + ) + private def reachable[T](inputs: Traversable[T], mkSymbol: T => Symbol): Set[Symbol] = { + def loop(seen: Set[Symbol], remaining: List[Symbol]): Set[Symbol] = { + remaining match { + case Nil => seen + case head :: rest => + if ((head eq null) || (head eq NoSymbol) || seen(head)) loop(seen, rest) + else loop(seen + head, rest ++ reachableDirectlyFromSymbol(head).filterNot(seen)) + } + } + loop(immutable.Set(), inputs.toList map mkSymbol filterNot (_ eq null) distinct) + } + private def treeList(t: Tree) = { + val buf = mutable.ListBuffer[Tree]() + t foreach (buf += _) + buf.toList + } + + private def reachableFromSymbol(root: Symbol): Set[Symbol] = + reachable[Symbol](List(root, root.info.typeSymbol), x => x) + + private def reachableFromTree(tree: Tree): Set[Symbol] = + reachable[Tree](treeList(tree), _.symbol) + + private def signature(id: Int) = runBeforeErasure(allSymbols(id).defString) + + private def dashes(s: Any): String = ("" + s) map (_ => '-') + private def show(s1: Any, ss: Any*) { + println("%-12s".format(s1) +: ss mkString " ") + } + private def showHeader(s1: Any, ss: Any*) { + show(s1, ss: _*) + show(dashes(s1), ss map dashes: _*) + } + private def showSym(sym: Symbol) { + def prefix = (" " * (sym.ownerChain.length - 1)) + sym.id + try println("%s#%s %s".format(prefix, sym.accurateKindString, sym.name.decode)) + catch { + case x => println(prefix + " failed: " + x) + } + allChildren(sym.id).sorted foreach showIdAndRemove + } + private def showIdAndRemove(id: Int) { + allSymbols remove id foreach showSym + } + private def symbolStr(id: Int): String = { + if (id == 1) "NoSymbol" else { + val sym = allSymbols(id) + sym.accurateKindString + " " + sym.name.decode + } + } + private def ownerStr(id: Int): String = { + val sym = allSymbols(id) + sym.name.decode + "#" + sym.id + } + + private def freq[T, U](xs: collection.Traversable[T])(fn: T => U): List[(U, Int)] = { + val ys = xs groupBy fn mapValues (_.size) + ys.toList sortBy (-_._2) + } + + private def showMapFreq[T](xs: collection.Map[T, Traversable[_]])(showFn: T => String) { + xs.mapValues(_.size).toList.sortBy(-_._2) take 100 foreach { case (k, size) => + show(size, showFn(k)) + } + println("\n") + } + private def showFreq[T, U](xs: Traversable[T])(groupFn: T => U, showFn: U => String = (x: U) => "" + x) = { + showMapFreq(xs.toList groupBy groupFn)(showFn) + } + private lazy val findErasurePhase: Phase = { + var ph = phase + while (ph != NoPhase && ph.name != "erasure") { + ph = ph.prev + } + ph + } + private def runBeforeErasure[T](body: => T): T = atPhase(findErasurePhase)(body) + + def showAllSymbols() { + if (!traceSymbolActivity) return + allSymbols(1) = NoSymbol + + println("" + allSymbols.size + " symbols created.") + println("") + + showHeader("descendants", "symbol") + showFreq(allSymbols.values flatMap (_.ownerChain drop 1))(_.id, symbolStr) + + showHeader("children", "symbol") + showMapFreq(allChildren)(symbolStr) + + if (prevOwners.nonEmpty) { + showHeader("prev owners", "symbol") + showMapFreq(prevOwners) { k => + val owners = (((allSymbols(k).owner.id, NoPhase)) :: prevOwners(k)) map { + case (oid, NoPhase) => "-> owned by " + ownerStr(oid) + case (oid, ph) => "-> owned by %s (until %s)".format(ownerStr(oid), ph) + } + signature(k) :: owners mkString "\n " + } + } + + val nameFreq = allSymbols.values.toList groupBy (_.name) + showHeader("frequency", "%-15s".format("name"), "owners") + showMapFreq(nameFreq) { name => + "%-15s %s".format(name.decode, { + val owners = freq(nameFreq(name))(_.owner) + + "%4s owners (%s)".format( + owners.size, + owners.take(3).map({ case (k, v) => v + "/" + k }).mkString(", ") + ", ..." + ) + }) + } + + allSymbols.keys.toList.sorted foreach showIdAndRemove + } +} diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 9ccd0c28db..6a30dc2a0f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1356,6 +1356,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb inform(unitTimingsFormatted) } + if (traceSymbolActivity) + units map (_.body) foreach (traceSymbols recordSymbolsInTree _) + // In case no phase was specified for -Xshow-class/object, show it now for sure. if (opt.noShow) showMembers() diff --git a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala index 7be115e777..9dc2a8de10 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/InteractiveTest.scala @@ -55,6 +55,7 @@ abstract class InteractiveTest with AskShutdown with AskReload with AskLoadedTyped + with AskType with PresentationCompilerInstance with CoreTestDefs with InteractiveTestSettings { self => diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/AskCommand.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/AskCommand.scala index 35d6723818..657ef23eed 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/AskCommand.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/AskCommand.scala @@ -101,13 +101,13 @@ trait AskTypeAt extends AskCommand { trait AskType extends AskCommand { import compiler.Tree - private[tests] def askType(source: SourceFile, forceReload: Boolean)(implicit reporter: Reporter): Response[Tree] = { + protected def askType(source: SourceFile, forceReload: Boolean)(implicit reporter: Reporter): Response[Tree] = { ask { compiler.askType(source, forceReload, _) } } - private[tests] def askType(sources: Seq[SourceFile], forceReload: Boolean)(implicit reporter: Reporter): Seq[Response[Tree]] = { + protected def askType(sources: Seq[SourceFile], forceReload: Boolean)(implicit reporter: Reporter): Seq[Response[Tree]] = { for(source <- sources) yield askType(source, forceReload) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index a1ca4904f4..dba31f7bca 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -484,8 +484,7 @@ trait Infer { else Some( if (targ.typeSymbol == RepeatedParamClass) targ.baseType(SeqClass) else if (targ.typeSymbol == JavaRepeatedParamClass) targ.baseType(ArrayClass) - // this infers Foo.type instead of "object Foo" (see also widenIfNecessary) - else if (targ.typeSymbol.isModuleClass || ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden)) targ + else if ((opt.experimental || opt.virtPatmat) && tvar.constr.avoidWiden) targ else targ.widen ) )) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 8604366bf2..1b505d1e5d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -793,10 +793,7 @@ trait Namers extends MethodSynthesis { val tpe1 = dropRepeatedParamType(tpe.deconst) val tpe2 = tpe1.widen - // This infers Foo.type instead of "object Foo" - // See Infer#adjustTypeArgs for the polymorphic case. - if (tpe.typeSymbolDirect.isModuleClass) tpe1 - else if (sym.isVariable || sym.isMethod && !sym.hasAccessorFlag) + if (sym.isVariable || sym.isMethod && !sym.hasAccessorFlag) if (tpe2 <:< pt) tpe2 else tpe1 else if (isHidden(tpe)) tpe2 // In an attempt to make pattern matches involving method local vals diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 045614e773..54b711cebc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -951,17 +951,20 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R override def traverse(tree: Tree) { tree match { - case ClassDef(_, _, _, _) | - TypeDef(_, _, _, _) => + case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) => validateVariance(tree.symbol) super.traverse(tree) // ModuleDefs need not be considered because they have been eliminated already case ValDef(_, _, _, _) => - validateVariance(tree.symbol) + if (!tree.symbol.hasLocalFlag) + validateVariance(tree.symbol) case DefDef(_, _, tparams, vparamss, _, _) => - validateVariance(tree.symbol) - traverseTrees(tparams) - traverseTreess(vparamss) + // No variance check for object-private/protected methods/values. + if (!tree.symbol.hasLocalFlag) { + validateVariance(tree.symbol) + traverseTrees(tparams) + traverseTreess(vparamss) + } case Template(_, _, _) => super.traverse(tree) case _ => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2aff00f6a5..36c81b09cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2089,7 +2089,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { for (Apply(_, xs) <- cdef.pat ; x <- xs dropRight 1 ; if treeInfo isStar x) StarPositionInPatternError(x) - val pat1 = typedPattern(cdef.pat, pattpe) + // withoutAnnotations - see continuations-run/z1673.scala + // This adjustment is awfully specific to continuations, but AFAICS the + // whole AnnotationChecker framework is. + val pat1 = typedPattern(cdef.pat, pattpe.withoutAnnotations) // When case classes have more than two parameter lists, the pattern ends // up typed as a method. We only pattern match on the first parameter // list, so substitute the final result type of the method, i.e. the type @@ -2199,7 +2202,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { vparams map {p => if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe} } - def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = { + def mkParams(methodSym: Symbol, formals: List[Type]/* = deriveFormals*/) = { selOverride match { case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree) case None => @@ -2225,7 +2228,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // rig the show so we can get started typing the method body -- later we'll correct the infos... anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass) val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL) - val (paramSyms, selector) = mkParams(methodSym) + val (paramSyms, selector) = mkParams(methodSym, deriveFormals) if (selector eq EmptyTree) EmptyTree else { @@ -2289,7 +2292,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def isDefinedAtMethod = { val methodSym = anonClass.newMethod(nme.isDefinedAt, tree.pos, FINAL) - val (paramSyms, selector) = mkParams(methodSym) + val (paramSyms, selector) = mkParams(methodSym, deriveFormals) if (selector eq EmptyTree) EmptyTree else { val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala index 075009ce5e..67ea6e15f0 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala @@ -24,6 +24,7 @@ trait CPSUtils { val shift = newTermName("shift") val shiftR = newTermName("shiftR") val shiftSuffix = newTermName("$shift") + val shiftUnit0 = newTermName("shiftUnit0") val shiftUnit = newTermName("shiftUnit") val shiftUnitR = newTermName("shiftUnitR") } @@ -38,6 +39,7 @@ trait CPSUtils { lazy val ModCPS = definitions.getRequiredModule("scala.util.continuations") lazy val MethShiftUnit = definitions.getMember(ModCPS, cpsNames.shiftUnit) + lazy val MethShiftUnit0 = definitions.getMember(ModCPS, cpsNames.shiftUnit0) lazy val MethShiftUnitR = definitions.getMember(ModCPS, cpsNames.shiftUnitR) lazy val MethShift = definitions.getMember(ModCPS, cpsNames.shift) lazy val MethShiftR = definitions.getMember(ModCPS, cpsNames.shiftR) diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index 1189cc2e38..a6737573ea 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -310,15 +310,23 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with try { val Some((a, b)) = cpsR - - val res = localTyper.typed(atPos(tree.pos) { - Apply(TypeApply(gen.mkAttributedRef(MethShiftUnit), - List(TypeTree(plainTpe), TypeTree(a), TypeTree(b))), - List(expr)) - }) - return (stms, res) - - } catch { + /** Since shiftUnit is bounded [A,B,C>:B] this may not typecheck + * if C is overly specific. So if !(B <:< C), call shiftUnit0 + * instead, which takes only two type arguments. + */ + val conforms = a <:< b + val call = localTyper.typedPos(tree.pos)( + Apply( + TypeApply( + gen.mkAttributedRef( if (conforms) MethShiftUnit else MethShiftUnit0 ), + List(TypeTree(plainTpe), TypeTree(a)) ++ ( if (conforms) List(TypeTree(b)) else Nil ) + ), + List(expr) + ) + ) + return ((stms, call)) + } + catch { case ex:TypeError => unit.error(ex.pos, "cannot cps-transform expression " + tree + ": " + ex.msg) } diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index 6db4904b93..2d87ccb261 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -130,6 +130,18 @@ sealed abstract class Option[+A] extends Product with Serializable { @inline final def map[B](f: A => B): Option[B] = if (isEmpty) None else Some(f(this.get)) + /** Returns the result of applying $f to this $option's + * value if the $option is nonempty. Otherwise, evaluates + * expression $ifEmpty. + * + * @note This is equivalent to `$option map f getOrElse ifEmpty`. + * + * @param ifEmpty the expression to evaluate if empty. + * @param f the function to apply if nonempty. + */ + @inline final def fold[B](ifEmpty: => B)(f: A => B): B = + if (isEmpty) ifEmpty else f(this.get) + /** Returns the result of applying $f to this $option's value if * this $option is nonempty. * Returns $none if this $option is empty. diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 75ab3f28f5..a978a9a783 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -127,3 +127,5 @@ object JavaConversions extends WrapAsScala with WrapAsJava { @deprecated("use propertiesAsScalaMap instead", "2.9.0") def asScalaMap(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) } + + diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 13f1f19f81..f8a9466caf 100755 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -100,4 +100,4 @@ object JavaConverters extends DecorateAsJava with DecorateAsScala { @deprecated("Use propertiesAsScalaMapConverter instead", "2.9.0") def asScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = propertiesAsScalaMapConverter(p) -}
\ No newline at end of file +} diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index 76837d937c..e05bfc41cd 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -291,6 +291,26 @@ trait DecorateAsJava { * @return An object with an `asJava` method that returns a Java * `ConcurrentMap` view of the argument. */ + @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") implicit def asJavaConcurrentMapConverter[A, B](m: mutable.ConcurrentMap[A, B]): AsJava[juc.ConcurrentMap[A, B]] = new AsJava(asJavaConcurrentMap(m)) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable + * `concurrent.Map` to a Java `ConcurrentMap`. + * + * The returned Java `ConcurrentMap` is backed by the provided Scala + * `concurrent.Map` and any side-effects of using it via the Java interface + * will be visible via the Scala interface and vice versa. + * + * If the Scala `concurrent.Map` was previously obtained from an implicit or + * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)` + * then the original Java `ConcurrentMap` will be returned. + * + * @param m The Scala `concurrent.Map` to be converted. + * @return An object with an `asJava` method that returns a Java + * `ConcurrentMap` view of the argument. + */ + implicit def asJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] = + new AsJava(asJavaConcurrentMap(m)) } diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala index bb14228e67..722f0b9af9 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -156,10 +156,29 @@ trait DecorateAsScala { * @return An object with an `asScala` method that returns a Scala mutable * `ConcurrentMap` view of the argument. */ - implicit def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] = + @deprecated("Use `mapAsScalaConcurrentMapConverter` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") + def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] = new AsScala(asScalaConcurrentMap(m)) /** + * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` + * to a Scala mutable `concurrent.Map`. The returned Scala `concurrent.Map` is + * backed by the provided Java `ConcurrentMap` and any side-effects of using + * it via the Scala interface will be visible via the Java interface and + * vice versa. + * + * If the Java `ConcurrentMap` was previously obtained from an implicit or + * explicit call of `mapAsScalaConcurrentMap(scala.collection.mutable.ConcurrentMap)` + * then the original Scala `concurrent.Map` will be returned. + * + * @param m The `ConcurrentMap` to be converted. + * @return An object with an `asScala` method that returns a Scala mutable + * `concurrent.Map` view of the argument. + */ + implicit def mapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] = + new AsScala(mapAsScalaConcurrentMap(m)) + + /** * Adds an `asScala` method that implicitly converts a Java `Dictionary` * to a Scala mutable `Map[String, String]`. The returned Scala * `Map[String, String]` is backed by the provided Java `Dictionary` and diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 6274518d1a..cdec72b9fe 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -241,16 +241,45 @@ trait WrapAsJava { * will be visible via the Scala interface and vice versa. * * If the Scala `ConcurrentMap` was previously obtained from an implicit or - * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)` + * explicit call of `asScalaConcurrentMap(java.util.concurrect.ConcurrentMap)` * then the original Java ConcurrentMap will be returned. * * @param m The `ConcurrentMap` to be converted. * @return A Java `ConcurrentMap` view of the argument. */ + @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") implicit def asJavaConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match { + case JConcurrentMapDeprecatedWrapper(wrapped) => wrapped + case _ => new ConcurrentMapDeprecatedWrapper(m) + } + + /** + * Implicitly converts a Scala mutable `concurrent.Map` to a Java + * `ConcurrentMap`. + * + * The returned Java `ConcurrentMap` is backed by the provided Scala + * `concurrent.Map` and any side-effects of using it via the Java interface + * will be visible via the Scala interface and vice versa. + * + * If the Scala `concurrent.Map` was previously obtained from an implicit or + * explicit call of `mapAsScalaConcurrentMap(java.util.concurrect.ConcurrentMap)` + * then the original Java ConcurrentMap will be returned. + * + * @param m The Scala `concurrent.Map` to be converted. + * @return A Java `ConcurrentMap` view of the argument. + */ + implicit def asJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { case JConcurrentMapWrapper(wrapped) => wrapped case _ => new ConcurrentMapWrapper(m) } } object WrapAsJava extends WrapAsJava { } + + + + + + + + diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index 02b58f55a4..56e13b2105 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -154,9 +154,28 @@ trait WrapAsScala { * @param m The ConcurrentMap to be converted. * @return A Scala mutable ConcurrentMap view of the argument. */ - implicit def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { - case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying - case _ => new JConcurrentMapWrapper(m) + @deprecated("Use `mapAsScalaConcurrentMap` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") + def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { + case cmw: ConcurrentMapDeprecatedWrapper[a, b] => cmw.underlying + case _ => new JConcurrentMapDeprecatedWrapper(m) + } + + /** + * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap. + * The returned Scala ConcurrentMap is backed by the provided Java + * ConcurrentMap and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * + * If the Java ConcurrentMap was previously obtained from an implicit or + * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)` + * then the original Scala ConcurrentMap will be returned. + * + * @param m The ConcurrentMap to be converted. + * @return A Scala mutable ConcurrentMap view of the argument. + */ + implicit def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match { + case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) } /** diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index 8136e462cb..b1b48b760f 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -268,7 +268,7 @@ private[collection] trait Wrappers { override def empty = JMapWrapper(new ju.HashMap[A, B]) } - class ConcurrentMapWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { + class ConcurrentMapDeprecatedWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { case Some(v) => v @@ -290,7 +290,54 @@ private[collection] trait Wrappers { def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) } - case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with mutable.ConcurrentMap[A, B] { + class ConcurrentMapWrapper[A, B](override val underlying: concurrent.Map[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { + + def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def remove(k: AnyRef, v: AnyRef) = try { + underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B]) + } catch { + case ex: ClassCastException => + false + } + + def replace(k: A, v: B): B = underlying.replace(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) + } + + case class JConcurrentMapDeprecatedWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapDeprecatedWrapper[A, B]] with mutable.ConcurrentMap[A, B] { + override def get(k: A) = { + val v = underlying get k + if (v != null) Some(v) + else None + } + + override def empty = new JConcurrentMapDeprecatedWrapper(new juc.ConcurrentHashMap[A, B]) + + def putIfAbsent(k: A, v: B): Option[B] = { + val r = underlying.putIfAbsent(k, v) + if (r != null) Some(r) else None + } + + def remove(k: A, v: B): Boolean = underlying.remove(k, v) + + def replace(k: A, v: B): Option[B] = { + val prev = underlying.replace(k, v) + if (prev != null) Some(prev) else None + } + + def replace(k: A, oldvalue: B, newvalue: B): Boolean = + underlying.replace(k, oldvalue, newvalue) + } + + case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[A, B] { override def get(k: A) = { val v = underlying get k if (v != null) Some(v) diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index cc0aed6963..06b7d40bfc 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -366,7 +366,7 @@ private[collection] object HashTable { private[collection] final def newThreshold(_loadFactor: Int, size: Int) = ((size.toLong * _loadFactor) / loadFactorDenum).toInt - private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = thr * loadFactorDenum / _loadFactor + private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = ((thr.toLong * loadFactorDenum) / _loadFactor).toInt private[collection] final def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala index ba98757906..0f882540f2 100644 --- a/src/library/scala/concurrent/ConcurrentPackageObject.scala +++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala @@ -8,11 +8,8 @@ package scala.concurrent - - -import java.util.concurrent.{ Executors, ExecutorService } -import scala.concurrent.forkjoin.ForkJoinPool -import scala.util.{ Try, Success, Failure } +import java.util.concurrent.{ Executors, ExecutorService, ThreadFactory } +import scala.concurrent.forkjoin.{ ForkJoinPool, ForkJoinWorkerThread } import scala.concurrent.util.Duration import ConcurrentPackageObject._ @@ -24,14 +21,9 @@ abstract class ConcurrentPackageObject { /** A global execution environment for executing lightweight tasks. */ lazy val executionContext = - new impl.ExecutionContextImpl(getExecutorService) - - private[concurrent] def getExecutorService: AnyRef = - if (scala.util.Properties.isJavaAtLeast("1.6")) { - val vendor = scala.util.Properties.javaVmVendor - if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) new ForkJoinPool - else Executors.newCachedThreadPool() - } else Executors.newCachedThreadPool() + new impl.ExecutionContextImpl() + + private val currentExecutionContext = new ThreadLocal[ExecutionContext] val handledFutureException: PartialFunction[Throwable, Throwable] = { case t: Throwable if isFutureThrowable(t) => t @@ -45,23 +37,23 @@ abstract class ConcurrentPackageObject { case _ => true } - private[concurrent] def resolve[T](source: Try[T]): Try[T] = source match { - case Failure(t: scala.runtime.NonLocalReturnControl[_]) => Success(t.value.asInstanceOf[T]) - case Failure(t: scala.util.control.ControlThrowable) => Failure(new ExecutionException("Boxed ControlThrowable", t)) - case Failure(t: InterruptedException) => Failure(new ExecutionException("Boxed InterruptedException", t)) - case Failure(e: Error) => Failure(new ExecutionException("Boxed Error", e)) + private[concurrent] def resolve[T](source: Either[Throwable, T]): Either[Throwable, T] = source match { + case Left(t: scala.runtime.NonLocalReturnControl[_]) => Right(t.value.asInstanceOf[T]) + case Left(t: scala.util.control.ControlThrowable) => Left(new ExecutionException("Boxed ControlThrowable", t)) + case Left(t: InterruptedException) => Left(new ExecutionException("Boxed InterruptedException", t)) + case Left(e: Error) => Left(new ExecutionException("Boxed Error", e)) case _ => source } private[concurrent] def resolver[T] = - resolverFunction.asInstanceOf[PartialFunction[Throwable, Try[T]]] + resolverFunction.asInstanceOf[PartialFunction[Throwable, Either[Throwable, T]]] /* concurrency constructs */ - def future[T](body: =>T)(implicit execCtx: ExecutionContext = executionContext): Future[T] = + def future[T](body: =>T)(implicit execctx: ExecutionContext = executionContext): Future[T] = Future[T](body) - def promise[T]()(implicit execCtx: ExecutionContext = executionContext): Promise[T] = + def promise[T]()(implicit execctx: ExecutionContext = executionContext): Promise[T] = Promise[T]() /** Wraps a block of code into an awaitable object. */ @@ -82,8 +74,8 @@ abstract class ConcurrentPackageObject { * - InterruptedException - in the case that a wait within the blockable object was interrupted * - TimeoutException - in the case that the blockable object timed out */ - def blocking[T](body: =>T)(implicit execCtx: ExecutionContext): T = - executionContext.blocking(body) + def blocking[T](body: =>T): T = + blocking(body2awaitable(body), Duration.fromNanos(0)) /** Blocks on an awaitable object. * @@ -94,8 +86,11 @@ abstract class ConcurrentPackageObject { * - InterruptedException - in the case that a wait within the blockable object was interrupted * - TimeoutException - in the case that the blockable object timed out */ - def blocking[T](awaitable: Awaitable[T], atMost: Duration)(implicit execCtx: ExecutionContext = executionContext): T = - executionContext.blocking(awaitable, atMost) + def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = + currentExecutionContext.get match { + case null => Await.result(awaitable, atMost) + case ec => ec.internalBlockingCall(awaitable, atMost) + } @inline implicit final def int2durationops(x: Int): DurationOps = new DurationOps(x) } @@ -106,11 +101,11 @@ private[concurrent] object ConcurrentPackageObject { // compiling a subset of sources; it seems that the wildcard is not // properly handled, and you get messages like "type _$1 defined twice". // This is consistent with other package object breakdowns. - private val resolverFunction: PartialFunction[Throwable, Try[_]] = { - case t: scala.runtime.NonLocalReturnControl[_] => Success(t.value) - case t: scala.util.control.ControlThrowable => Failure(new ExecutionException("Boxed ControlThrowable", t)) - case t: InterruptedException => Failure(new ExecutionException("Boxed InterruptedException", t)) - case e: Error => Failure(new ExecutionException("Boxed Error", e)) - case t => Failure(t) + private val resolverFunction: PartialFunction[Throwable, Either[Throwable, _]] = { + case t: scala.runtime.NonLocalReturnControl[_] => Right(t.value) + case t: scala.util.control.ControlThrowable => Left(new ExecutionException("Boxed ControlThrowable", t)) + case t: InterruptedException => Left(new ExecutionException("Boxed InterruptedException", t)) + case e: Error => Left(new ExecutionException("Boxed Error", e)) + case t => Left(t) } } diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index a206a2d4ea..16d9a1f980 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -13,7 +13,6 @@ package scala.concurrent import java.util.concurrent.atomic.{ AtomicInteger } import java.util.concurrent.{ Executors, Future => JFuture, Callable } import scala.concurrent.util.Duration -import scala.util.{ Try, Success, Failure } import scala.concurrent.forkjoin.{ ForkJoinPool, RecursiveTask => FJTask, RecursiveAction, ForkJoinWorkerThread } import scala.collection.generic.CanBuildFrom import collection._ @@ -26,10 +25,8 @@ trait ExecutionContext { def execute[U](body: () => U): Unit - def blocking[T](body: =>T): T - - def blocking[T](awaitable: Awaitable[T], atMost: Duration): T - + def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T + def reportFailure(t: Throwable): Unit /* implementations follow */ diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index d73801aa90..5f703ac23b 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -17,7 +17,6 @@ import java.util.{ LinkedList => JLinkedList } import java.{ lang => jl } import java.util.concurrent.atomic.{ AtomicReferenceFieldUpdater, AtomicInteger, AtomicBoolean } -import scala.util.{ Try, Success, Failure } import scala.concurrent.util.Duration import scala.Option @@ -97,8 +96,8 @@ self => * $multipleCallbacks */ def onSuccess[U](pf: PartialFunction[T, U]): this.type = onComplete { - case Failure(t) => // do nothing - case Success(v) => if (pf isDefinedAt v) pf(v) else { /*do nothing*/ } + case Left(t) => // do nothing + case Right(v) => if (pf isDefinedAt v) pf(v) else { /*do nothing*/ } } /** When this future is completed with a failure (i.e. with a throwable), @@ -114,8 +113,8 @@ self => * $multipleCallbacks */ def onFailure[U](callback: PartialFunction[Throwable, U]): this.type = onComplete { - case Failure(t) => if (isFutureThrowable(t) && callback.isDefinedAt(t)) callback(t) else { /*do nothing*/ } - case Success(v) => // do nothing + case Left(t) => if (isFutureThrowable(t) && callback.isDefinedAt(t)) callback(t) else { /*do nothing*/ } + case Right(v) => // do nothing } /** When this future is completed, either through an exception, a timeout, or a value, @@ -126,7 +125,7 @@ self => * * $multipleCallbacks */ - def onComplete[U](func: Try[T] => U): this.type + def onComplete[U](func: Either[Throwable, T] => U): this.type /* Miscellaneous */ @@ -151,7 +150,7 @@ self => * if it contains a valid result, or `Some(Failure(error))` if it contains * an exception. */ - def value: Option[Try[T]] + def value: Option[Either[Throwable, T]] /* Projections */ @@ -175,8 +174,8 @@ self => val p = newPromise[Throwable] onComplete { - case Failure(t) => p success t - case Success(v) => p failure noSuchElem(v) + case Left(t) => p success t + case Right(v) => p failure noSuchElem(v) } p.future @@ -190,8 +189,8 @@ self => * Will not be called if the future fails. */ def foreach[U](f: T => U): Unit = onComplete { - case Success(r) => f(r) - case Failure(_) => // do nothing + case Right(r) => f(r) + case Left(_) => // do nothing } /** Creates a new future by applying a function to the successful result of @@ -204,8 +203,8 @@ self => val p = newPromise[S] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try p success f(v) catch { case t => p complete resolver(t) @@ -226,12 +225,12 @@ self => val p = newPromise[S] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try { f(v) onComplete { - case Failure(t) => p failure t - case Success(v) => p success v + case Left(t) => p failure t + case Right(v) => p success v } } catch { case t: Throwable => p complete resolver(t) @@ -261,8 +260,8 @@ self => val p = newPromise[T] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try { if (pred(v)) p success v else p failure new NoSuchElementException("Future.filter predicate is not satisfied by: " + v) @@ -274,6 +273,18 @@ self => p.future } + /** Used by for-comprehensions. + */ + final def withFilter(p: T => Boolean): Future[T] = filter(p) + // final def withFilter(p: T => Boolean) = new FutureWithFilter[T](this, p) + + // final class FutureWithFilter[+S](self: Future[S], p: S => Boolean) { + // def foreach(f: S => Unit): Unit = self filter p foreach f + // def map[R](f: S => R) = self filter p map f + // def flatMap[R](f: S => Future[R]) = self filter p flatMap f + // def withFilter(q: S => Boolean): FutureWithFilter[S] = new FutureWithFilter[S](self, x => p(x) && q(x)) + // } + /** Creates a new future by mapping the value of the current future if the given partial function is defined at that value. * * If the current future contains a value for which the partial function is defined, the new future will also hold that value. @@ -298,8 +309,8 @@ self => val p = newPromise[S] onComplete { - case Failure(t) => p failure t - case Success(v) => + case Left(t) => p failure t + case Right(v) => try { if (pf.isDefinedAt(v)) p success pf(v) else p failure new NoSuchElementException("Future.collect partial function is not defined at: " + v) @@ -327,7 +338,7 @@ self => val p = newPromise[U] onComplete { - case Failure(t) if pf isDefinedAt t => + case Left(t) if pf isDefinedAt t => try { p success pf(t) } catch { case t: Throwable => p complete resolver(t) } case otherwise => p complete otherwise @@ -353,7 +364,7 @@ self => val p = newPromise[U] onComplete { - case Failure(t) if pf isDefinedAt t => + case Left(t) if pf isDefinedAt t => try { p completeWith pf(t) } catch { @@ -377,8 +388,8 @@ self => val p = newPromise[(T, U)] this onComplete { - case Failure(t) => p failure t - case Success(r) => that onSuccess { + case Left(t) => p failure t + case Right(r) => that onSuccess { case r2 => p success ((r, r2)) } } @@ -408,16 +419,35 @@ self => val p = newPromise[U] onComplete { - case Failure(t) => that onComplete { - case Failure(_) => p failure t - case Success(v) => p success v + case Left(t) => that onComplete { + case Left(_) => p failure t + case Right(v) => p success v } - case Success(v) => p success v + case Right(v) => p success v } p.future } - + + /** Creates a new `Future[S]` which is completed with this `Future`'s result if + * that conforms to `S`'s erased type or a `ClassCastException` otherwise. + */ + def mapTo[S](implicit m: Manifest[S]): Future[S] = { + val p = newPromise[S] + + onComplete { + case l: Left[Throwable, _] => p complete l.asInstanceOf[Either[Throwable, S]] + case Right(t) => + p complete (try { + Right(impl.Future.boxedType(m.erasure).cast(t).asInstanceOf[S]) + } catch { + case e: ClassCastException => Left(e) + }) + } + + p.future + } + /** Applies the side-effecting function to the result of this future, and returns * a new future with the result of this future. * @@ -441,7 +471,7 @@ self => * } * }}} */ - def andThen[U](pf: PartialFunction[Try[T], U]): Future[T] = { + def andThen[U](pf: PartialFunction[Either[Throwable, T], U]): Future[T] = { val p = newPromise[T] onComplete { @@ -469,9 +499,9 @@ self => def either[U >: T](that: Future[U]): Future[U] = { val p = self.newPromise[U] - val completePromise: PartialFunction[Try[U], _] = { - case Failure(t) => p tryFailure t - case Success(v) => p trySuccess v + val completePromise: PartialFunction[Either[Throwable, U], _] = { + case Left(t) => p tryFailure t + case Right(v) => p trySuccess v } self onComplete completePromise @@ -510,7 +540,7 @@ object Future { def firstCompletedOf[T](futures: Traversable[Future[T]])(implicit executor: ExecutionContext): Future[T] = { val p = Promise[T]() - val completeFirst: Try[T] => Unit = p tryComplete _ + val completeFirst: Either[Throwable, T] => Unit = p tryComplete _ futures.foreach(_ onComplete completeFirst) p.future @@ -523,14 +553,14 @@ object Future { else { val result = Promise[Option[T]]() val ref = new AtomicInteger(futures.size) - val search: Try[T] => Unit = v => try { + val search: Either[Throwable, T] => Unit = v => try { v match { - case Success(r) => if (predicate(r)) result tryComplete Success(Some(r)) + case Right(r) => if (predicate(r)) result tryComplete Right(Some(r)) case _ => } } finally { if (ref.decrementAndGet == 0) - result tryComplete Success(None) + result tryComplete Right(None) } futures.foreach(_ onComplete search) diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala index 61e21606e6..8f2bce5d1a 100644 --- a/src/library/scala/concurrent/Promise.scala +++ b/src/library/scala/concurrent/Promise.scala @@ -8,11 +8,6 @@ package scala.concurrent -import scala.util.{ Try, Success, Failure } - - - - /** Promise is an object which can be completed with a value or failed * with an exception. * @@ -40,7 +35,7 @@ trait Promise[T] { * * $promiseCompletion */ - def complete(result:Try[T]): this.type = if (tryComplete(result)) this else throwCompleted + def complete(result: Either[Throwable, T]): this.type = if (tryComplete(result)) this else throwCompleted /** Tries to complete the promise with either a value or the exception. * @@ -48,7 +43,7 @@ trait Promise[T] { * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ - def tryComplete(result: Try[T]): Boolean + def tryComplete(result: Either[Throwable, T]): Boolean /** Completes this promise with the specified future, once that future is completed. * @@ -75,7 +70,7 @@ trait Promise[T] { * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ - def trySuccess(value: T): Boolean = tryComplete(Success(value)) + def trySuccess(value: T): Boolean = tryComplete(Right(value)) /** Completes the promise with an exception. * @@ -93,7 +88,7 @@ trait Promise[T] { * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ - def tryFailure(t: Throwable): Boolean = tryComplete(Failure(t)) + def tryFailure(t: Throwable): Boolean = tryComplete(Left(t)) /** Wraps a `Throwable` in an `ExecutionException` if necessary. TODO replace with `resolver` from scala.concurrent * @@ -118,11 +113,11 @@ object Promise { /** Creates an already completed Promise with the specified exception */ - def failed[T](exception: Throwable)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception)) + def failed[T](exception: Throwable)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Left(exception)) /** Creates an already completed Promise with the specified result */ - def successful[T](result: T)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Success(result)) + def successful[T](result: T)(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.KeptPromise[T](Right(result)) } diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 5dc440f42b..9a94bfca4f 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -10,16 +10,49 @@ package scala.concurrent.impl -import java.util.concurrent.{Callable, ExecutorService} +import java.util.concurrent.{Callable, ExecutorService, Executors, ThreadFactory} import scala.concurrent.forkjoin._ import scala.concurrent.{ExecutionContext, resolver, Awaitable, body2awaitable} -import scala.util.{ Try, Success, Failure } import scala.concurrent.util.{ Duration } -private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends ExecutionContext { +private[scala] class ExecutionContextImpl() extends ExecutionContext { import ExecutionContextImpl._ + + val executorService: AnyRef = getExecutorService + + // to ensure that the current execution context thread local is properly set + private def executorsThreadFactory = new ThreadFactory { + def newThread(r: Runnable) = new Thread(new Runnable { + override def run() { + currentExecutionContext.set(ExecutionContextImpl.this) + r.run() + } + }) + } + + // to ensure that the current execution context thread local is properly set + private def forkJoinPoolThreadFactory = new ForkJoinPool.ForkJoinWorkerThreadFactory { + def newThread(fjp: ForkJoinPool) = new ForkJoinWorkerThread(fjp) { + override def onStart() { + currentExecutionContext.set(ExecutionContextImpl.this) + } + } + } + + private def getExecutorService: AnyRef = + if (scala.util.Properties.isJavaAtLeast("1.6")) { + val vendor = scala.util.Properties.javaVmVendor + if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) + new ForkJoinPool( + Runtime.getRuntime.availableProcessors(), + forkJoinPoolThreadFactory, + null, + false) + else + Executors.newCachedThreadPool(executorsThreadFactory) + } else Executors.newCachedThreadPool(executorsThreadFactory) def execute(runnable: Runnable): Unit = executorService match { case fj: ForkJoinPool => @@ -37,9 +70,7 @@ private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends E def run() = body() }) - def blocking[T](body: =>T): T = blocking(body2awaitable(body), Duration.fromNanos(0)) - - def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = { + def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = { Future.releaseStack(this) awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index 6833b2467f..615ab061a5 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -11,11 +11,8 @@ package scala.concurrent.impl import scala.concurrent.{Awaitable, ExecutionContext} -import scala.util.{ Try, Success, Failure } import scala.collection.mutable.Stack - - private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] { implicit def executor: ExecutionContext @@ -36,39 +33,9 @@ private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awa * if it contains a valid result, or Some(Left(error)) if it contains * an exception. */ - def value: Option[Try[T]] - - def onComplete[U](func: Try[T] => U): this.type - - /** Creates a new Future[A] which is completed with this Future's result if - * that conforms to A's erased type or a ClassCastException otherwise. - */ - final def mapTo[T](implicit m: Manifest[T]) = { - val p = new Promise.DefaultPromise[T] - - onComplete { - case f @ Failure(t) => p complete f.asInstanceOf[Try[T]] - case Success(v) => - p complete (try { - Success(Future.boxedType(m.erasure).cast(v).asInstanceOf[T]) - } catch { - case e: ClassCastException => Failure(e) - }) - } + def value: Option[Either[Throwable, T]] - p.future - } - - /** Used by for-comprehensions. - */ - final def withFilter(p: T => Boolean) = new FutureWithFilter[T](this, p) - - final class FutureWithFilter[+A](self: Future[A], p: A => Boolean) { - def foreach(f: A => Unit): Unit = self filter p foreach f - def map[B](f: A => B) = self filter p map f - def flatMap[B](f: A => Future[B]) = self filter p flatMap f - def withFilter(q: A => Boolean): FutureWithFilter[A] = new FutureWithFilter[A](self, x ⇒ p(x) && q(x)) - } + def onComplete[U](func: Either[Throwable, T] => U): this.type } @@ -97,7 +64,7 @@ object Future { def run = { promise complete { try { - Success(body) + Right(body) } catch { case e => scala.concurrent.resolver(e) } diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index c79b0d02cc..f7e073cb78 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -15,7 +15,6 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater import scala.concurrent.{Awaitable, ExecutionContext, resolve, resolver, blocking, CanAwait, TimeoutException} //import scala.util.continuations._ import scala.concurrent.util.Duration -import scala.util.Try import scala.util import scala.annotation.tailrec //import scala.concurrent.NonDeterministic @@ -84,18 +83,18 @@ object Promise { * * [adriaan] it's unsound to make FState covariant (tryComplete won't type check) */ - sealed trait FState[T] { def value: Option[Try[T]] } + sealed trait FState[T] { def value: Option[Either[Throwable, T]] } - case class Pending[T](listeners: List[Try[T] => Any] = Nil) extends FState[T] { - def value: Option[Try[T]] = None + case class Pending[T](listeners: List[Either[Throwable, T] => Any] = Nil) extends FState[T] { + def value: Option[Either[Throwable, T]] = None } - case class Success[T](value: Option[util.Success[T]] = None) extends FState[T] { - def result: T = value.get.get + case class Success[T](value: Option[Either[Throwable, T]] = None) extends FState[T] { + def result: T = value.get.right.get } - case class Failure[T](value: Option[util.Failure[T]] = None) extends FState[T] { - def exception: Throwable = value.get.exception + case class Failure[T](value: Option[Either[Throwable, T]] = None) extends FState[T] { + def exception: Throwable = value.get.left.get } private val emptyPendingValue = Pending[Nothing](Nil) @@ -127,7 +126,7 @@ object Promise { value.isDefined } - executor.blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), atMost) + blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), atMost) } def ready(atMost: Duration)(implicit permit: CanAwait): this.type = @@ -136,11 +135,11 @@ object Promise { def result(atMost: Duration)(implicit permit: CanAwait): T = ready(atMost).value.get match { - case util.Failure(e) => throw e - case util.Success(r) => r + case Left(e) => throw e + case Right(r) => r } - def value: Option[Try[T]] = getState.value + def value: Option[Either[Throwable, T]] = getState.value @inline private[this] final def updater = AbstractPromise.updater.asInstanceOf[AtomicReferenceFieldUpdater[AbstractPromise, FState[T]]] @@ -151,16 +150,16 @@ object Promise { @inline protected final def getState: FState[T] = updater.get(this) - def tryComplete(value: Try[T]): Boolean = { - val callbacks: List[Try[T] => Any] = { + def tryComplete(value: Either[Throwable, T]): Boolean = { + val callbacks: List[Either[Throwable, T] => Any] = { try { @tailrec - def tryComplete(v: Try[T]): List[Try[T] => Any] = { + def tryComplete(v: Either[Throwable, T]): List[Either[Throwable, T] => Any] = { getState match { case cur @ Pending(listeners) => val newState = - if (v.isFailure) Failure(Some(v.asInstanceOf[util.Failure[T]])) - else Success(Some(v.asInstanceOf[util.Success[T]])) + if (v.isLeft) Failure(Some(v.asInstanceOf[Left[Throwable, T]])) + else Success(Some(v.asInstanceOf[Right[Throwable, T]])) if (updateState(cur, newState)) listeners else tryComplete(v) @@ -184,7 +183,7 @@ object Promise { } } - def onComplete[U](func: Try[T] => U): this.type = { + def onComplete[U](func: Either[Throwable, T] => U): this.type = { @tailrec // Returns whether the future has already been completed or not def tryAddCallback(): Boolean = { val cur = getState @@ -206,7 +205,7 @@ object Promise { this } - private final def notifyCompleted(func: Try[T] => Any, result: Try[T]) { + private final def notifyCompleted(func: Either[Throwable, T] => Any, result: Either[Throwable, T]) { try { func(result) } catch { @@ -219,12 +218,13 @@ object Promise { * * Useful in Future-composition when a value to contribute is already available. */ - final class KeptPromise[T](suppliedValue: Try[T])(implicit val executor: ExecutionContext) extends Promise[T] { + final class KeptPromise[T](suppliedValue: Either[Throwable, T])(implicit val executor: ExecutionContext) extends Promise[T] { + val value = Some(resolve(suppliedValue)) - def tryComplete(value: Try[T]): Boolean = false + def tryComplete(value: Either[Throwable, T]): Boolean = false - def onComplete[U](func: Try[T] => U): this.type = { + def onComplete[U](func: Either[Throwable, T] => U): this.type = { val completedAs = value.get Future.dispatchFuture(executor, { () => func(completedAs) @@ -235,8 +235,8 @@ object Promise { def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this def result(atMost: Duration)(implicit permit: CanAwait): T = value.get match { - case util.Failure(e) => throw e - case util.Success(r) => r + case Left(e) => throw e + case Right(r) => r } } diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index c1f45eccfb..cb42b76b51 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -183,7 +183,8 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { override def equals (that: Any): Boolean = that match { case that: BigDecimal => this equals that case that: BigInt => this.toBigIntExact exists (that equals _) - case _: Float | _: Double => unifiedPrimitiveEquals(that) + case that: Double => isValidDouble && toDouble == that + case that: Float => isValidFloat && toFloat == that case _ => isValidLong && unifiedPrimitiveEquals(that) } override def isValidByte = noArithmeticException(toByteExact) @@ -191,6 +192,18 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { override def isValidChar = isValidInt && toIntExact >= Char.MinValue && toIntExact <= Char.MaxValue override def isValidInt = noArithmeticException(toIntExact) def isValidLong = noArithmeticException(toLongExact) + /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`. + */ + def isValidFloat = { + val f = toFloat + !f.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(f)) == 0 + } + /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`. + */ + def isValidDouble = { + val d = toDouble + !d.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(d)) == 0 + } private def noArithmeticException(body: => Unit): Boolean = { try { body ; true } diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 8a53afaa62..dbec30b2fe 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -20,6 +20,7 @@ object BigInt { private val minCached = -1024 private val maxCached = 1024 private val cache = new Array[BigInt](maxCached - minCached + 1) + private val minusOne = BigInteger.valueOf(-1) @deprecated("Use Long.MinValue", "2.9.0") val MinLong = BigInt(Long.MinValue) @@ -122,6 +123,8 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo override def equals(that: Any): Boolean = that match { case that: BigInt => this equals that case that: BigDecimal => that.toBigIntExact exists (this equals _) + case that: Double => isValidDouble && toDouble == that + case that: Float => isValidFloat && toFloat == that case x => isValidLong && unifiedPrimitiveEquals(x) } override def isValidByte = this >= Byte.MinValue && this <= Byte.MaxValue @@ -129,6 +132,41 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo override def isValidChar = this >= Char.MinValue && this <= Char.MaxValue override def isValidInt = this >= Int.MinValue && this <= Int.MaxValue def isValidLong = this >= Long.MinValue && this <= Long.MaxValue + /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`. + */ + def isValidFloat = { + val bitLen = bitLength + (bitLen <= 24 || + { + val lowest = lowestSetBit + bitLen <= java.lang.Float.MAX_EXPONENT + 1 && // exclude this < -2^128 && this >= 2^128 + lowest >= bitLen - 24 && + lowest < java.lang.Float.MAX_EXPONENT + 1 // exclude this == -2^128 + } + ) && !bitLengthOverflow + } + /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`. + */ + def isValidDouble = { + val bitLen = bitLength + (bitLen <= 53 || + { + val lowest = lowestSetBit + bitLen <= java.lang.Double.MAX_EXPONENT + 1 && // exclude this < -2^1024 && this >= 2^1024 + lowest >= bitLen - 53 && + lowest < java.lang.Double.MAX_EXPONENT + 1 // exclude this == -2^1024 + } + ) && !bitLengthOverflow + } + /** Some implementations of java.math.BigInteger allow huge values with bit length greater than Int.MaxValue . + * The BigInteger.bitLength method returns truncated bit length in this case . + * This method tests if result of bitLength is valid. + * This method will become unnecessary if BigInt constructors reject huge BigIntegers. + */ + private def bitLengthOverflow = { + val shifted = bigInteger.shiftRight(Int.MaxValue) + (shifted.signum != 0) && !(shifted equals BigInt.minusOne) + } protected[math] def isWhole = true def underlying = bigInteger diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index c9bde81317..efa2fcabb8 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -101,9 +101,9 @@ sealed abstract class Try[+T] { } -final case class Failure[+T](val exception: Throwable) extends Try[T] { - def isFailure = true - def isSuccess = false +final class Failure[+T](val exception: Throwable) extends Try[T] { + def isFailure: Boolean = true + def isSuccess: Boolean = false def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = { try { if (rescueException.isDefinedAt(exception)) rescueException(exception) else this @@ -129,30 +129,49 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { } -final case class Success[+T](r: T) extends Try[T] { - def isFailure = false - def isSuccess = true - def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = Success(r) - def get = r +final class Success[+T](value: T) extends Try[T] { + def isFailure: Boolean = false + def isSuccess: Boolean = true + def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = Success(value) + def get = value def flatMap[U](f: T => Try[U]): Try[U] = - try f(r) + try f(value) catch { case e => Failure(e) } - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = r - def foreach[U](f: T => U): Unit = f(r) - def map[U](f: T => U): Try[U] = Try[U](f(r)) + def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value + def foreach[U](f: T => U): Unit = f(value) + def map[U](f: T => U): Try[U] = Try[U](f(value)) def collect[U](pf: PartialFunction[T, U]): Try[U] = - if (pf isDefinedAt r) Success(pf(r)) - else Failure[U](new NoSuchElementException("Partial function not defined at " + r)) + if (pf isDefinedAt value) Success(pf(value)) + else Failure[U](new NoSuchElementException("Partial function not defined at " + value)) def filter(p: T => Boolean): Try[T] = - if (p(r)) this - else Failure(new NoSuchElementException("Predicate does not hold for " + r)) + if (p(value)) this + else Failure(new NoSuchElementException("Predicate does not hold for " + value)) def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this - def exists(p: T => Boolean): Boolean = p(r) + def exists(p: T => Boolean): Boolean = p(value) def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) } +object Failure { + def apply[T](e: Throwable): Failure[T] = new Failure(e) + def unapply(scrutinizee: Any): Option[Throwable] = scrutinizee match { + case Right(_) => None + case Left(e) => Some(e.asInstanceOf[Throwable]) + case s: Success[_] => None + case f: Failure[_] => Some(f.exception) + } +} + +object Success { + def apply[T](value: T): Success[T] = new Success(value) + def unapply[T](scrutinizee: Any): Option[T] = scrutinizee match { + case Right(v) => Some(v.asInstanceOf[T]) + case Left(_) => None + case s: Success[_] => Some(s.get.asInstanceOf[T]) + case f: Failure[Throwable] => None + } +} object Try { diff --git a/test/files/continuations-neg/infer0.check b/test/disabled/continuations-neg/infer0.check index 1dd072ef09..1dd072ef09 100644 --- a/test/files/continuations-neg/infer0.check +++ b/test/disabled/continuations-neg/infer0.check diff --git a/test/files/continuations-neg/infer0.scala b/test/disabled/continuations-neg/infer0.scala index 9cf69c5d35..6d97d7504d 100644 --- a/test/files/continuations-neg/infer0.scala +++ b/test/disabled/continuations-neg/infer0.scala @@ -4,11 +4,9 @@ import scala.util.continuations._ object Test { - def test(x: => Int @cpsParam[String,Int]) = 7 - - def main(args: Array[String]): Any = { + + def main(args: Array[String]) { test(8) } - -}
\ No newline at end of file +} diff --git a/test/files/continuations-run/shift-pct.check b/test/files/continuations-run/shift-pct.check new file mode 100644 index 0000000000..fb190e770a --- /dev/null +++ b/test/files/continuations-run/shift-pct.check @@ -0,0 +1,25 @@ +d = 1, d2 = 1.0, pct = 1.000 +d = 2, d2 = 4.0, pct = 0.500 +d = 3, d2 = 9.0, pct = 0.333 +d = 4, d2 = 16.0, pct = 0.250 +d = 5, d2 = 25.0, pct = 0.200 +d = 6, d2 = 36.0, pct = 0.167 +d = 7, d2 = 49.0, pct = 0.143 +d = 8, d2 = 64.0, pct = 0.125 +d = 9, d2 = 81.0, pct = 0.111 +d = 10, d2 = 100.0, pct = 0.100 +d = 11, d2 = 121.0, pct = 0.091 +d = 12, d2 = 144.0, pct = 0.083 +d = 13, d2 = 169.0, pct = 0.077 +d = 14, d2 = 196.0, pct = 0.071 +d = 15, d2 = 225.0, pct = 0.067 +d = 16, d2 = 256.0, pct = 0.063 +d = 17, d2 = 289.0, pct = 0.059 +d = 18, d2 = 324.0, pct = 0.056 +d = 19, d2 = 361.0, pct = 0.053 +d = 20, d2 = 400.0, pct = 0.050 +d = 21, d2 = 441.0, pct = 0.048 +d = 22, d2 = 484.0, pct = 0.045 +d = 23, d2 = 529.0, pct = 0.043 +d = 24, d2 = 576.0, pct = 0.042 +d = 25, d2 = 625.0, pct = 0.040 diff --git a/test/files/continuations-run/shift-pct.scala b/test/files/continuations-run/shift-pct.scala new file mode 100644 index 0000000000..7ef9922168 --- /dev/null +++ b/test/files/continuations-run/shift-pct.scala @@ -0,0 +1,30 @@ +import scala.util.continuations._ + +object Test { + abstract class IfReturnRepro { + def s1: Double @cpsParam[Any, Unit] + def s2: Double @cpsParam[Any, Unit] + + def p(i: Int): Double @cpsParam[Unit, Any] = { + val px = s1 + val pct = if (px > 100) px else px / s2 + println("pct = %.3f".format(pct)) + pct + } + } + + def main(args: Array[String]) : Unit = { + var d: Double = 0d + def d2 = d * d + + val irr = new IfReturnRepro { + def s1 = shift(f => f(d)) + def s2 = shift(f => f(d2)) + } + 1 to 25 foreach { i => + d = i + print("d = " + i + ", d2 = " + d2 + ", ") + run(irr p i) + } + } +} diff --git a/test/files/continuations-run/z1673.check b/test/files/continuations-run/z1673.check new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/files/continuations-run/z1673.check diff --git a/test/files/continuations-run/z1673.scala b/test/files/continuations-run/z1673.scala new file mode 100644 index 0000000000..716b374860 --- /dev/null +++ b/test/files/continuations-run/z1673.scala @@ -0,0 +1,31 @@ +import scala.util.continuations._ + +class MatchRepro { + def s: String @cps[Any] = shift { k => k("foo") } + + def p = { + val k = s + s match { case lit0 => } + } + + def q = { + val k = s + k match { case lit1 => } + } + + def r = { + s match { case "FOO" => } + } + + def t = { + val k = s + k match { case "FOO" => } + } +} + +object Test { + def main(args: Array[String]): Unit = { + val m = new MatchRepro + () + } +} diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index 75e2b92ff6..b3470d275d 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -1,6 +1,3 @@ - - - import scala.concurrent.{ Future, Promise, @@ -398,6 +395,80 @@ trait Exceptions extends TestBase { } +trait TryEitherExtractor extends TestBase { + + import scala.util.{Try, Success, Failure} + + def testSuccessMatch(): Unit = once { + done => + val thisIsASuccess = Success(42) + thisIsASuccess match { + case Success(v) => + done() + assert(v == 42) + case Failure(e) => + done() + assert(false) + case other => + done() + assert(false) + } + } + + def testRightMatch(): Unit = once { + done => + val thisIsNotASuccess: Right[Throwable, Int] = Right(43) + thisIsNotASuccess match { + case Success(v) => + done() + assert(v == 43) + case Failure(e) => + done() + assert(false) + case other => + done() + assert(false) + } + } + + def testFailureMatch(): Unit = once { + done => + val thisIsAFailure = Failure(new Exception("I'm an exception")) + thisIsAFailure match { + case Success(v) => + done() + assert(false) + case Failure(e) => + done() + assert(e.getMessage == "I'm an exception") + case other => + done() + assert(false) + } + } + + def testLeftMatch(): Unit = once { + done => + val thisIsNotAFailure: Left[Throwable, Int] = Left(new Exception("I'm an exception")) + thisIsNotAFailure match { + case Success(v) => + done() + assert(false) + case Failure(e) => + done() + assert(e.getMessage == "I'm an exception") + case other => + done() + assert(false) + } + + } + + testSuccessMatch() + testRightMatch() + testFailureMatch() + testLeftMatch() +} object Test extends App @@ -406,8 +477,11 @@ with FutureCombinators with FutureProjections with Promises with Exceptions +with TryEitherExtractor { System.exit(0) } + + diff --git a/test/files/neg/variances.check b/test/files/neg/variances.check index dc72b05e1e..0643e533b7 100644 --- a/test/files/neg/variances.check +++ b/test/files/neg/variances.check @@ -1,16 +1,19 @@ variances.scala:4: error: covariant type A occurs in contravariant position in type test.Vector[A] of value x - def append(x: Vector[A]): Vector[A] + def append(x: Vector[A]): Vector[A] ^ -variances.scala:14: error: covariant type A occurs in contravariant position in type A of value a - private[this] def setA(a : A) = this.a = a - ^ -variances.scala:16: error: covariant type A occurs in invariant position in supertype test.C[A] of object Baz +variances.scala:18: error: covariant type A occurs in contravariant position in type A of value a + private def setA3(a : A) = this.a = a + ^ +variances.scala:19: error: covariant type A occurs in contravariant position in type A of value a + protected def setA4(a : A) = this.a = a + ^ +variances.scala:21: error: covariant type A occurs in invariant position in supertype test.C[A] of object Baz object Baz extends C[A] ^ -variances.scala:63: error: covariant type A occurs in contravariant position in type => test.Covariant.T[A]{val m: A => A} of value x +variances.scala:74: error: covariant type A occurs in contravariant position in type => test.Covariant.T[A]{val m: A => A} of value x val x: T[A] { ^ -variances.scala:79: error: covariant type T occurs in contravariant position in type => test.TestAlias.B[C.this.A] of method foo +variances.scala:90: error: covariant type T occurs in contravariant position in type => test.TestAlias.B[C.this.A] of method foo def foo: B[A] ^ -5 errors found +6 errors found diff --git a/test/files/neg/variances.scala b/test/files/neg/variances.scala index 726bc35270..10ca111cd0 100644 --- a/test/files/neg/variances.scala +++ b/test/files/neg/variances.scala @@ -1,7 +1,7 @@ package test trait Vector[+A] { - def append(x: Vector[A]): Vector[A] + def append(x: Vector[A]): Vector[A] private[this] def append3(x: Vector[A]): Vector[A] = append(x) } @@ -11,19 +11,27 @@ object Covariant { class Foo[+A] { private[this] var a : A = _ def getA : A = a - private[this] def setA(a : A) = this.a = a - + // allowed + private[this] def setA1(a : A) = this.a = a + protected[this] def setA2(a : A) = this.a = a + // forbidden + private def setA3(a : A) = this.a = a + protected def setA4(a : A) = this.a = a + object Baz extends C[A] trait Convert[B] { def b2a(b : B) : A - def doit(b : B) = setA(b2a(b)) + def doit1(b : B) = setA1(b2a(b)) + def doit2(b : B) = setA2(b2a(b)) + def doit3(b : B) = setA3(b2a(b)) + def doit4(b : B) = setA4(b2a(b)) } } class Foo2[+A] { private[this] var a : A = _ def getA : A = a - private[this] def setA(a : A) = this.a = a - + private[this] def setA(a : A) = this.a = a + { trait Convert[B] { def b2a(b : B) : A @@ -35,8 +43,8 @@ object Covariant { class Foo3[+A] { private[this] var a : A = _ def getA : A = a - private[this] def setA(a : A) = this.a = a - + private[this] def setA(a : A) = this.a = a + private[this] trait Convert[B] { def b2a(b : B) : A def doit(b : B) = setA(b2a(b)) @@ -54,7 +62,10 @@ object Covariant { } def main(args : Array[String]) { val test = new Test - test.c.doit(test.b) + test.c.doit1(test.b) + test.c.doit2(test.b) + test.c.doit3(test.b) + test.c.doit4(test.b) val x : java.lang.Character = test.a.getA Console.println("XXX " + x) } diff --git a/test/files/pos/t3272.scala b/test/files/pos/t3272.scala new file mode 100644 index 0000000000..8efd5ded2c --- /dev/null +++ b/test/files/pos/t3272.scala @@ -0,0 +1,8 @@ +trait A { + trait C[+T] { + protected[this] def f(t: T) {} + } + trait D[T] extends C[T] { + def g(t: T) { f(t) } + } +} diff --git a/test/files/pos/t4910.scala b/test/files/pos/t4910.scala new file mode 100644 index 0000000000..c66fd523f5 --- /dev/null +++ b/test/files/pos/t4910.scala @@ -0,0 +1,6 @@ +class A { + implicit object foo + // it compiles if we uncomment this + // implicit val bar = foo + implicitly[foo.type] +} diff --git a/test/files/presentation/memory-leaks.check b/test/files/presentation/memory-leaks.check new file mode 100644 index 0000000000..9d8cbb4da4 --- /dev/null +++ b/test/files/presentation/memory-leaks.check @@ -0,0 +1,14 @@ +reload: Trees.scala, Typers.scala, Types.scala +reload: Trees.scala +reload: Types.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +reload: Typers.scala +No leaks detected. diff --git a/test/files/presentation/memory-leaks/MemoryLeaksTest.scala b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala new file mode 100644 index 0000000000..e24f36d7b6 --- /dev/null +++ b/test/files/presentation/memory-leaks/MemoryLeaksTest.scala @@ -0,0 +1,125 @@ +import java.io.PrintWriter +import java.io.FileOutputStream +import java.util.Calendar + +import scala.tools.nsc.interactive.tests._ +import scala.tools.nsc.util._ +import scala.tools.nsc.io._ + +/** This test runs the presentation compiler on the Scala compiler project itself and records memory consumption. + * + * The test scenario is to open Typers, Trees and Types, then repeatedly add and remove one character + * in Typers.scala. Each step causes the parser, namer, and type checker to run. + * + * At each step we record the memory usage after the GC has run. At the end of the test, + * simple linear regression is used to compute the straight line that best fits the + * curve, and if the slope is higher than 1 (meaning a leak of 1MB/run), we fail the test. + * + * The Scala compiler sources are assumed to be under 'basedir/src/compiler'. + * + * The individual data points are saved under 'usedMem-<date>.txt', under the test project + * directory. Use the cool graph-it.R (https://github.com/scala-ide/scala-ide/blob/master/org.scala-ide.sdt.core.tests/graph-it.R) + * script to see the memory curve for the given test run. + */ +object Test extends InteractiveTest { + final val mega = 1024 * 1024 + + override def main(args: Array[String]) { + memoryConsumptionTest() + compiler.askShutdown() + } + + def batchSource(name: String) = + new BatchSourceFile(AbstractFile.getFile(name)) + + def memoryConsumptionTest() { + val N = 10 + val filename = "usedmem-%tF.txt".format(Calendar.getInstance.getTime) + + val typerUnit = AbstractFile.getFile(baseDir.parent.parent.parent.parent / "src/compiler/scala/tools/nsc/typechecker/Typers.scala") + val typesUnit = AbstractFile.getFile(baseDir.parent.parent.parent.parent / "src/compiler/scala/reflect/internal/Types.scala") + val treesUnit = AbstractFile.getFile(baseDir.parent.parent.parent.parent / "src/compiler/scala/reflect/internal/Trees.scala") + + askReload(Seq(new BatchSourceFile(typerUnit), new BatchSourceFile(typesUnit), new BatchSourceFile(treesUnit))) + typeCheckWith(treesUnit, new String(treesUnit.toCharArray)) + typeCheckWith(typesUnit, new String(typesUnit.toCharArray)) + + val originalTyper = new String(typerUnit.toCharArray) + + val (prefix, postfix) = originalTyper.splitAt(originalTyper.indexOf("import global._")) + val changedTyper = prefix + " a\n " + postfix + + val usedMem = for (i <- 1 to N) yield { + val src = if (i % 2 == 0) originalTyper else changedTyper + + val usedMem = withGC { + typeCheckWith(typerUnit, src) + } + +// println("UsedMem:\t%d\t%d".format(i, usedMem / mega)) + usedMem / mega // report size in MB + } + + // println("=" * 80) + + val outputFile = new PrintWriter(new FileOutputStream(filename)) + outputFile.println("\tusedMem") + for ((dataPoint, i) <- usedMem.zipWithIndex) { + outputFile.println("%d\t%d".format(i, dataPoint)) + } + outputFile.close() + // drop the first two measurements, since the compiler needs some memory when initializing + val (a, b) = linearModel((3L to N).toSeq, usedMem.drop(2)) + //println("LinearModel: constant: %.4f\tslope:%.4f".format(a, b)) + + if (b > 1.0) + println("Rate of memory consumption is alarming! %.4f MB/run".format(b)) + else + println("No leaks detected.") + } + + private def typeCheckWith(file: AbstractFile, src: String) = { + val sourceFile = new BatchSourceFile(file, src.toCharArray) + askReload(Seq(sourceFile)) + askLoadedTyped(sourceFile).get // block until it's here + } + + + /** Return the linear model of these values, (a, b). First value is the constant factor, + * second value is the slope, i.e. `y = a + bx` + * + * The linear model of a set of points is a straight line that minimizes the square distance + * between the each point and the line. + * + * See: http://en.wikipedia.org/wiki/Simple_linear_regression + */ + def linearModel(xs: Seq[Long], ys: Seq[Long]): (Double, Double) = { + require(xs.length == ys.length) + + def mean(v: Seq[Long]): Double = v.sum.toDouble / v.length + + val meanXs = mean(xs) + val meanYs = mean(ys) + + val beta = (mean((xs, ys).zipped.map(_ * _)) - meanXs * meanYs) / (mean(xs.map(x => x * x)) - meanXs * meanXs) + val alfa = meanYs - beta * meanXs + + (alfa, beta) + } + + /** Run the given closure and return the amount of used memory at the end of its execution. + * + * Runs the GC before and after the execution of `f'. + */ + def withGC(f: => Unit): Long = { + val r = Runtime.getRuntime + System.gc() + + f; + + System.gc() + + r.totalMemory() - r.freeMemory() + } + +}
\ No newline at end of file diff --git a/test/files/run/concurrent-map-conversions.scala b/test/files/run/concurrent-map-conversions.scala new file mode 100644 index 0000000000..0350b69642 --- /dev/null +++ b/test/files/run/concurrent-map-conversions.scala @@ -0,0 +1,36 @@ + + + + + +object Test { + + def main(args: Array[String]) { + testConversions() + testConverters() + } + + def needPackageConcurrentMap(map: collection.concurrent.Map[Int, Int]) { + } + def needJavaConcurrent(map: java.util.concurrent.ConcurrentMap[Int, Int]) { + } + + def testConversions() { + import collection.JavaConversions._ + val skiplist = new java.util.concurrent.ConcurrentSkipListMap[Int, Int] + val ctrie = new collection.concurrent.TrieMap[Int, Int] + + needPackageConcurrentMap(skiplist) + needJavaConcurrent(ctrie) + } + + def testConverters() { + import collection.JavaConverters._ + val skiplist = new java.util.concurrent.ConcurrentSkipListMap[Int, Int] + val ctrie = new collection.concurrent.TrieMap[Int, Int] + + needPackageConcurrentMap(skiplist.asScala) + needJavaConcurrent(ctrie.asJava) + } + +} diff --git a/test/files/run/is-valid-num.scala b/test/files/run/is-valid-num.scala index f919a21dee..9c43e98911 100644 --- a/test/files/run/is-valid-num.scala +++ b/test/files/run/is-valid-num.scala @@ -1,11 +1,15 @@ object Test { def x = BigInt("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") def y = BigDecimal("" + (Short.MaxValue + 1) + ".0") + def y1 = BigDecimal("0.1") + def y2 = BigDecimal("0.5") def l1 = Int.MaxValue.toLong + 1 def l2 = Int.MinValue.toLong - 1 def main(args: Array[String]): Unit = { + assert(!x.isValidDouble, x) + assert(!x.isValidFloat, x) assert(!x.isValidLong, x) assert(!x.isValidInt, x) assert(!x.isValidChar, x) @@ -13,8 +17,81 @@ object Test { assert(!y.isValidShort, y) assert(y.isValidChar, y) assert(y.isValidInt, y) + assert(y.isValidFloat, y) + assert(y.isValidDouble, y) + assert(!y1.isValidLong, y1) + assert(!y1.isValidFloat, y1) + assert(!y1.isValidDouble, y1) + assert(!y2.isValidLong, y2) + assert(y2.isValidFloat, y2) + assert(y2.isValidDouble, y2) + + testBigIntIsFloat() + testBigIntIsDouble() assert(!l1.isValidInt && (l1 - 1).isValidInt, l1) assert(!l2.isValidInt && (l2 + 1).isValidInt, l2) } + + def biExp2(e: Int) = BigInt(1) << e + + def testBigIntIsFloat() { + val prec = 24 + def checkFloatT(x: BigInt) = { + assert(x.isValidFloat, x) + assert((-x).isValidFloat, -x) + } + def checkFloatF(x: BigInt) = { + assert(!x.isValidFloat, x) + assert(!(-x).isValidFloat, -x) + } + checkFloatT(biExp2(prec) - 1) + checkFloatT(biExp2(prec)) + checkFloatF(biExp2(prec) + 1) + checkFloatT(biExp2(prec) + 2) + checkFloatT(biExp2(prec) - 2) + checkFloatF(biExp2(prec + 1) - 1) + checkFloatT(biExp2(prec + 1)) + checkFloatF(biExp2(prec + 1) + 1) + checkFloatF(biExp2(prec + 1) + 2) + checkFloatF(biExp2(prec + 1) + 3) + checkFloatT(biExp2(prec + 1) + 4) + checkFloatT(biExp2(64)) + checkFloatF(biExp2(64) + biExp2(64 - prec)) + checkFloatT(biExp2(64) + biExp2(64 - prec + 1)) + checkFloatT(biExp2(127)) + checkFloatT(biExp2(128) - biExp2(128 - prec)) + checkFloatF(biExp2(128) - biExp2(128 - prec - 1)) + checkFloatF(biExp2(128)) + } + + def testBigIntIsDouble() { + val prec = 53 + def checkDoubleT(x: BigInt) = { + assert(x.isValidDouble, x) + assert((-x).isValidDouble, -x) + } + def checkDoubleF(x: BigInt) = { + assert(!x.isValidDouble, x) + assert(!(-x).isValidDouble, -x) + } + checkDoubleT(biExp2(prec) - 1) + checkDoubleT(biExp2(prec)) + checkDoubleF(biExp2(prec) + 1) + checkDoubleT(biExp2(prec) + 2) + checkDoubleT(biExp2(prec + 1) - 2) + checkDoubleF(biExp2(prec + 1) - 1) + checkDoubleT(biExp2(prec + 1)) + checkDoubleF(biExp2(prec + 1) + 1) + checkDoubleF(biExp2(prec + 1) + 2) + checkDoubleF(biExp2(prec + 1) + 3) + checkDoubleT(biExp2(prec + 1) + 4) + checkDoubleT(biExp2(64)) + checkDoubleF(biExp2(64) + biExp2(64 - prec)) + checkDoubleT(biExp2(64) + biExp2(64 - prec + 1)) + checkDoubleT(biExp2(1023)) + checkDoubleT(biExp2(1024) - biExp2(1024 - prec)) + checkDoubleF(biExp2(1024) - biExp2(1024 - prec - 1)) + checkDoubleF(biExp2(1024)) + } } diff --git a/test/files/run/numbereq.scala b/test/files/run/numbereq.scala index 77a217df36..a1f11da205 100644 --- a/test/files/run/numbereq.scala +++ b/test/files/run/numbereq.scala @@ -16,7 +16,20 @@ object Test { base ::: extras } - + + def mkNumbers(x: BigInt): List[AnyRef] = { + List( + List(BigDecimal(x, java.math.MathContext.UNLIMITED)), + List(x), + if (x.isValidDouble) List(new java.lang.Double(x.toDouble)) else Nil, + if (x.isValidFloat) List(new java.lang.Float(x.toFloat)) else Nil, + if (x.isValidLong) List(new java.lang.Long(x.toLong)) else Nil, + if (x.isValidInt) List(new java.lang.Integer(x.toInt)) else Nil, + if (x.isValidShort) List(new java.lang.Short(x.toShort)) else Nil, + if (x.isValidByte) List(new java.lang.Byte(x.toByte)) else Nil, + if (x.isValidChar) List(new java.lang.Character(x.toChar)) else Nil + ).flatten + } def main(args: Array[String]): Unit = { val ints = (0 to 15).toList map (Short.MinValue >> _) @@ -37,5 +50,23 @@ object Test { assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) } + + val bigInts = (0 to 1024).toList map (BigInt(-1) << _) + val bigInts2 = bigInts map (x => -x) + val bigInts3 = bigInts map (_ + 1) + val bigInts4 = bigInts2 map (_ - 1) + + val setneg1b = bigInts map mkNumbers + val setneg2b = bigInts3 map mkNumbers + val setpos1b = bigInts2 map mkNumbers + val setpos2b = bigInts4 map mkNumbers + + val sets2 = setneg1 ++ setneg1b ++ setneg2 ++ setneg2b ++ List(zero) ++ setpos1 ++ setpos1b ++ setpos2 ++ setpos2b + + for (set <- sets2 ; x <- set ; y <- set) { +// println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##)) + assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) +// assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) Disable until Double.## is fixed (SI-5640) + } } -}
\ No newline at end of file +} diff --git a/test/files/run/option-fold.check b/test/files/run/option-fold.check new file mode 100644 index 0000000000..4e3fe99f98 --- /dev/null +++ b/test/files/run/option-fold.check @@ -0,0 +1,5 @@ +List() +List(5) +-1 +0 +1 diff --git a/test/files/run/option-fold.scala b/test/files/run/option-fold.scala new file mode 100644 index 0000000000..d554ba4f9b --- /dev/null +++ b/test/files/run/option-fold.scala @@ -0,0 +1,19 @@ +object Test { + sealed class A + case object B extends A + case class C(x: Int) extends A + + def f[T](x: Option[T]) = x.fold(List.empty[T])(List(_)) + def g(x: Option[A]) = x.fold(-1) { + case B => 0 + case C(x) => x + } + + def main(args: Array[String]): Unit = { + println(f(None)) + println(f(Some(5))) + println(g(None)) + println(g(Some(B))) + println(g(Some(C(1)))) + } +} diff --git a/test/files/run/reflect-overload.scala b/test/files/run/reflect-overload.scala new file mode 100644 index 0000000000..af82a1948d --- /dev/null +++ b/test/files/run/reflect-overload.scala @@ -0,0 +1,16 @@ +object Test extends App { + import reflect.mirror._ + + val s = "hello world" + val sc = symbolOfInstance(s) + val st = sc.asType + val m = st member newTermName("indexOf") + val IntType = definitions.IntClass.asType + val indexOf = m resolveOverloaded(actuals = List(IntType)) + assert(invoke(s, indexOf)('w') == 6) + assert((invoke(s, indexOf)('w') match { case x: Int => x }) == 6) + + val m2 = st member newTermName("substring") + val substring = m2 resolveOverloaded(actuals = List(IntType, IntType)) + assert(invoke(s, substring)(2, 6) == "llo ") +} |