summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--classpath.SAMPLE5
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala6
-rw-r--r--src/compiler/scala/reflect/internal/Symbols.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala141
-rw-r--r--src/library/scala/concurrent/Awaitable.scala9
-rw-r--r--src/library/scala/concurrent/ConcurrentPackageObject.scala14
-rw-r--r--src/library/scala/concurrent/ExecutionContext.scala91
-rw-r--r--src/library/scala/concurrent/Future.scala128
-rw-r--r--src/library/scala/concurrent/Promise.scala16
-rw-r--r--src/library/scala/concurrent/impl/ExecutionContextImpl.scala84
-rw-r--r--src/library/scala/concurrent/impl/Future.scala74
-rw-r--r--src/library/scala/concurrent/impl/Promise.scala29
-rw-r--r--src/library/scala/concurrent/package.scala28
-rw-r--r--test/files/jvm/scala-concurrent-tck.scala2
-rw-r--r--test/pending/pos/t1476.scala23
-rw-r--r--test/pending/pos/t5626.scala12
-rw-r--r--test/pending/run/t5629.check2
-rw-r--r--test/pending/run/t5629.scala25
18 files changed, 391 insertions, 309 deletions
diff --git a/classpath.SAMPLE b/classpath.SAMPLE
index 69c2baeba7..9e607a41d9 100644
--- a/classpath.SAMPLE
+++ b/classpath.SAMPLE
@@ -3,10 +3,9 @@
<classpathentry kind="src" path="src/compiler"/>
<classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry exported="true" kind="lib" path="lib/msil.jar"/>
+ <classpathentry kind="lib" path="lib/msil.jar"/>
<classpathentry kind="lib" path="lib/jline.jar"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry exported="true" kind="lib" path="lib/fjbg.jar"/>
+ <classpathentry kind="lib" path="lib/fjbg.jar"/>
<classpathentry kind="lib" path="lib/forkjoin.jar"/>
<classpathentry kind="lib" path="lib/ant/ant.jar"/>
<classpathentry kind="output" path="build/quick/classes/compiler"/>
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index b58a0ef7d5..bb11ca634a 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -55,6 +55,12 @@ abstract class SymbolTable extends api.Universe
log(msg + ": " + result)
result
}
+ private[scala] def logResultIf[T](msg: String, cond: T => Boolean)(result: T): T = {
+ if (cond(result))
+ log(msg + ": " + result)
+
+ result
+ }
/** 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 f4039cf6d3..2019b92836 100644
--- a/src/compiler/scala/reflect/internal/Symbols.scala
+++ b/src/compiler/scala/reflect/internal/Symbols.scala
@@ -543,7 +543,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Conditions where we omit the prefix when printing a symbol, to avoid
* unpleasantries like Predef.String, $iw.$iw.Foo and <empty>.Bippy.
*/
- final def isOmittablePrefix = !settings.debug.value && (
+ final def isOmittablePrefix = /*!settings.debug.value &&*/ (
UnqualifiedOwners(skipPackageObject)
|| isEmptyPrefix
)
@@ -1191,9 +1191,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
var ph = phase
while (ph.prev.keepsTypeParams)
ph = ph.prev
-
- if (ph ne phase)
- debuglog("checking unsafeTypeParams(" + this + ") at: " + phase + " reading at: " + ph)
+ //
+ // if (ph ne phase)
+ // debuglog("checking unsafeTypeParams(" + this + ") at: " + phase + " reading at: " + ph)
ph
}
@@ -2119,7 +2119,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else ""
def defaultFlagMask =
- if (settings.debug.value) -1L
+ if (isAbstractType) ExplicitFlags
+ else if (settings.debug.value) -1L
else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE
else ExplicitFlags
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 7b0f5254b6..185cf4f533 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -318,7 +318,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else specializedTypeVars(sym).intersect(env.keySet)
)
val (methparams, others) = tvars.toList sortBy ("" + _.name) partition (_.owner.isMethod)
- debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars)
+ // debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars)
specializedName(sym.name, methparams map env, others map env)
}
@@ -518,7 +518,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// better evaluate it before creating the new class symbol
val clazzName = specializedName(clazz, env0).toTypeName
val bytecodeClazz = clazz.owner.info.decl(clazzName)
- debuglog("Specializing " + clazz + " found " + bytecodeClazz + " already there")
+ // debuglog("Specializing " + clazz + ", but found " + bytecodeClazz + " already there")
bytecodeClazz.info
val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE)
@@ -574,7 +574,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
parents = parents.head.parents.head :: parents
val extraSpecializedMixins = specializedParents(clazz.info.parents map applyContext)
if (extraSpecializedMixins.nonEmpty)
- debuglog("specializeClass on " + clazz + " founds extra specialized mixins: " + extraSpecializedMixins.mkString(", "))
+ debuglog("extra specialized mixins for %s: %s".format(clazz.name.decode, extraSpecializedMixins.mkString(", ")))
// If the class being specialized has a self-type, the self type may
// require specialization. First exclude classes whose self types have
// the same type constructor as the class itself, since they will
@@ -652,7 +652,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val NormalizedMember(original) = info(m)
if (nonConflicting(env ++ typeEnv(m))) {
if (info(m).degenerate) {
- debuglog("degenerate normalized member " + m + " info(m): " + info(m))
+ debuglog("degenerate normalized member " + m.defString)
val specMember = enterMember(cloneInSpecializedClass(m, _ & ~DEFERRED))
info(specMember) = Implementation(original)
@@ -660,7 +660,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
else debuglog({
val om = forwardToOverload(m)
- "normalizedMember " + m + " om: " + om + " typeEnv(om): " + typeEnv(om)
+ "normalizedMember " + m + " om: " + om + " " + pp(typeEnv(om))
})
}
else
@@ -668,7 +668,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
else if (m.isDeferred) { // abstract methods
val specMember = enterMember(cloneInSpecializedClass(m, _ | DEFERRED))
- debuglog("deferred " + specMember.fullName + " remains abstract")
+ // debuglog("deferred " + specMember.fullName + " remains abstract")
info(specMember) = new Abstract(specMember)
// was: new Forward(specMember) {
@@ -698,20 +698,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
enterMember(specVal)
// create accessors
- debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name))
+ // debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name))
+
if (nme.isLocalName(m.name)) {
val specGetter = mkAccessor(specVal, nme.localToGetter(specVal.name)) setInfo MethodType(Nil, specVal.info)
val origGetter = overrideIn(sClass, m.getter(clazz))
info(origGetter) = Forward(specGetter)
enterMember(specGetter)
enterMember(origGetter)
- debuglog("created accessors: " + specGetter + " orig: " + origGetter)
+ debuglog("specialize accessor in %s: %s -> %s".format(sClass.name.decode, origGetter.name.decode, specGetter.name.decode))
clazz.caseFieldAccessors.find(_.name.startsWith(m.name)) foreach { cfa =>
val cfaGetter = overrideIn(sClass, cfa)
info(cfaGetter) = SpecializedAccessor(specVal)
enterMember(cfaGetter)
- debuglog("found case field accessor for " + m + " added override " + cfaGetter);
+ debuglog("override case field accessor %s -> %s".format(m.name.decode, cfaGetter.name.decode))
}
if (specVal.isVariable && m.setter(clazz) != NoSymbol) {
@@ -724,11 +725,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
enterMember(specSetter)
enterMember(origSetter)
}
- } else { // if there are no accessors, specialized methods will need to access this field in specialized subclasses
+ }
+ else { // if there are no accessors, specialized methods will need to access this field in specialized subclasses
m.resetFlag(PRIVATE)
specVal.resetFlag(PRIVATE)
+ debuglog("no accessors for %s/%s, specialized methods must access field in subclass".format(
+ m.name.decode, specVal.name.decode))
}
- } else if (m.isClass) {
+ }
+ else if (m.isClass) {
val specClass: Symbol = cloneInSpecializedClass(m, x => x)
typeEnv(specClass) = fullEnv
specClass.name = specializedName(specClass, fullEnv).toTypeName
@@ -787,10 +792,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* // etc.
*/
private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = {
- debuglog("normalizeMember: " + sym.fullName)
sym :: (
if (!sym.isMethod || beforeTyper(sym.typeParams.isEmpty)) Nil
else {
+ // debuglog("normalizeMember: " + sym.fullNameAsName('.').decode)
var specializingOn = specializedParams(sym)
val unusedStvars = specializingOn filterNot specializedTypeVars(sym.info)
@@ -810,7 +815,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val (keys, vals) = env.toList.unzip
specMember.name = specializedName(sym, env)
- debuglog("normalizing: " + sym + " to " + specMember + " with params " + tps)
+ // debuglog("%s normalizes to %s%s".format(sym, specMember,
+ // if (tps.isEmpty) "" else " with params " + tps.mkString(", ")))
typeEnv(specMember) = outerEnv ++ env
val tps1 = produceTypeParameters(tps, specMember, env)
@@ -820,11 +826,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val methodType = sym.info.resultType.instantiateTypeParams(keys ++ tps, vals ++ tps1.map(_.tpe)).cloneInfo(specMember)
specMember setInfo GenPolyType(tps1, methodType)
- debuglog("expanded member: " + sym + ": " + sym.info +
- " -> " + specMember +
- ": " + specMember.info +
- " env: " + env
- )
+ debuglog("%s expands to %s in %s".format(sym, specMember.name.decode, pp(env)))
info(specMember) = NormalizedMember(sym)
overloads(sym) ::= Overload(specMember, env)
specMember
@@ -833,6 +835,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
)
}
+ // concise printing of type env
+ private def pp(env: TypeEnv): String = {
+ env.toList.sortBy(_._1.name.toString) map {
+ case (k, v) =>
+ val vsym = v.typeSymbol
+ if (k == vsym) "" + k.name
+ else k.name + ":" + vsym.name
+
+ } mkString ("env(", ", ", ")")
+ }
+
/** Specialize member `m` w.r.t. to the outer environment and the type
* parameters of the innermost enclosing class.
*
@@ -841,37 +854,38 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
* Return a list of symbols that are specializations of 'sym', owned by 'owner'.
*/
private def specializeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv, tps: List[Symbol]): List[Symbol] = {
- def specializeOn(tparams: List[Symbol]): List[Symbol] =
- for (spec0 <- specializations(tparams)) yield {
- val spec = mapAnyRefsInOrigCls(spec0, owner)
- if (sym.isPrivate/* || sym.isProtected*/) {
- //sym.privateWithin = sym.enclosingPackage
- sym.resetFlag(PRIVATE).setFlag(PROTECTED)
- debuglog("-->d SETTING PRIVATE WITHIN TO " + sym.enclosingPackage + " for " + sym)
- }
+ def specializeOn(tparams: List[Symbol]): List[Symbol] = specializations(tparams) map { spec0 =>
+ val spec = mapAnyRefsInOrigCls(spec0, owner)
+ if (sym.isPrivate) {
+ sym.resetFlag(PRIVATE).setFlag(PROTECTED)
+ debuglog("Set %s to private[%s]".format(sym, sym.enclosingPackage))
+ }
- val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec))
- typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec
- wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s }
+ val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec))
+ typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec
+ wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s }
- debuglog("sym " + specMember + " was specialized for type vars " + wasSpecializedForTypeVars(specMember))
- debuglog("added specialized overload: %s in env: %s".format(specMember, typeEnv(specMember)))
+ val wasSpec = wasSpecializedForTypeVars(specMember)
+ if (wasSpec.nonEmpty)
+ debuglog("specialized overload for %s in %s".format(specMember, pp(typeEnv(specMember))))
- overloads(sym) ::= Overload(specMember, spec)
- specMember
- }
+ overloads(sym) ::= Overload(specMember, spec)
+ info(specMember) = SpecialOverload(sym, typeEnv(specMember))
+
+ specMember
+ }
if (sym.isMethod) {
- debuglog("specializeMember %s with tps: %s stvars(sym): %s".format(sym, tps, specializedTypeVars(sym)))
+ val stvars = specializedTypeVars(sym)
+ if (stvars.nonEmpty)
+ debuglog("specialized %s on %s".format(sym.fullLocationString, stvars.map(_.name).mkString(", ")))
val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps
- val tps2 = tps1 intersect specializedTypeVars(sym).toList
+ val tps2 = tps1 filter stvars
if (!sym.isDeferred)
addConcreteSpecMethod(sym)
- val ms = specializeOn(tps2)
- ms foreach (m => info(m) = SpecialOverload(sym, typeEnv(m)))
- ms
+ specializeOn(tps2)
}
else Nil
}
@@ -894,7 +908,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*
* this method will return List('apply$mcII$sp')
*/
- private def specialOverrides(clazz: Symbol): List[Symbol] = {
+ private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialOverrides(" + 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.
@@ -917,24 +931,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
if (!overriding.isParamAccessor) {
for (overridden <- overriding.allOverriddenSymbols) {
- debuglog(
- "Overridden: " + overridden.fullName +
- ": " + overridden.info +
- "\n by " + overriding.fullName +
- ": " + overriding.info
- )
val stvars = specializedTypeVars(overridden.info)
if (stvars.nonEmpty) {
- debuglog("\t\tspecializedTVars: " + stvars)
+ debuglog("specialized override of %s by %s%s".format(overridden.fullLocationString, overriding.fullLocationString,
+ if (stvars.isEmpty) "" else stvars.map(_.name).mkString("(", ", ", ")")))
+
if (currentRun compiles overriding)
checkOverriddenTParams(overridden)
val env = unify(overridden.info, overriding.info, emptyEnv, false)
def atNext = afterSpecialize(overridden.owner.info.decl(specializedName(overridden, env)))
- debuglog("\t\tenv: " + env + "isValid: " + TypeEnv.isValid(env, overridden) + "found: " + atNext)
- if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol)
+ if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol) {
+ debuglog(" " + pp(env) + " found " + atNext)
return (overridden, env)
+ }
}
}
}
@@ -945,7 +956,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case (NoSymbol, _) => None
case (overridden, env) =>
val om = specializedOverload(clazz, overridden, env)
- debuglog("Added specialized overload %s for %s in env: %s with type: %s".format(om, overriding.fullName, env, om.info))
+ debuglog("specialized overload %s for %s in %s: %s".format(om, overriding.name.decode, pp(env), om.info))
typeEnv(om) = env
addConcreteSpecMethod(overriding)
info(om) = (
@@ -993,7 +1004,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match {
case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) =>
- debuglog("Unify - basic case: " + tp1 + ", " + tp2)
+ debuglog("Unify " + tp1 + ", " + tp2)
if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1))
env + ((sym1, tp2))
else if (isSpecializedAnyRefSubtype(tp2, sym1))
@@ -1003,19 +1014,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
else
env
case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) =>
- debuglog("Unify TypeRefs: " + tp1 + " and " + tp2 + " with args " + (args1, args2) + " - ")
+ if (args1.nonEmpty || args2.nonEmpty)
+ debuglog("Unify types " + tp1 + " and " + tp2)
+
if (strict && args1.length != args2.length) unifyError(tp1, tp2)
val e = unify(args1, args2, env, strict)
- debuglog("unified to: " + e)
+ if (e.nonEmpty) debuglog("unified to: " + e)
e
case (TypeRef(_, sym1, _), _) if sym1.isTypeParameterOrSkolem =>
env
case (MethodType(params1, res1), MethodType(params2, res2)) =>
if (strict && params1.length != params2.length) unifyError(tp1, tp2)
- debuglog("Unify MethodTypes: " + tp1 + " and " + tp2)
+ debuglog("Unify methods " + tp1 + " and " + tp2)
unify(res1 :: (params1 map (_.tpe)), res2 :: (params2 map (_.tpe)), env, strict)
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
- debuglog("Unify PolyTypes: " + tp1 + " and " + tp2)
+ debuglog("Unify polytypes " + tp1 + " and " + tp2)
if (strict && tparams1.length != tparams2.length)
unifyError(tp1, tp2)
else
@@ -1123,11 +1136,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
if (tparams.isEmpty)
afterSpecialize(parents map (_.typeSymbol.info))
- val parents1 = parents map specializedType
- debuglog("transformInfo %s %s with parents1 %s ph: %s".format(
- if (tparams.nonEmpty) " (poly)" else "",
- clazz, parents1, phase)
- )
+ val parents1 = parents mapConserve specializedType
+ if (parents ne parents1) {
+ debuglog("specialization transforms %s%s parents to %s".format(
+ if (tparams.nonEmpty) "(poly) " else "", clazz, parents1)
+ )
+ }
val newScope = newScopeWith(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz): _*)
// If tparams.isEmpty, this is just the ClassInfoType.
GenPolyType(tparams, ClassInfoType(parents1, newScope, clazz))
@@ -1253,7 +1267,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
override def traverse(tree: Tree) = tree match {
case DefDef(_, _, _, vparams :: Nil, _, rhs) =>
if (concreteSpecMethods(tree.symbol) || tree.symbol.isConstructor) {
- debuglog("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs))
+ // debuglog("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs))
body(tree.symbol) = rhs
// body(tree.symbol) = tree // whole method
parameters(tree.symbol) = vparams.map(_.symbol)
@@ -1559,7 +1573,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
val env = typeEnv(symbol)
val boundTvars = env.keySet
val origtparams = source.typeParams.filter(tparam => !boundTvars(tparam) || !isScalaValueType(env(tparam)))
- debuglog("substituting " + origtparams + " for " + symbol.typeParams)
+ if (origtparams.nonEmpty || symbol.typeParams.nonEmpty)
+ debuglog("substituting " + origtparams + " for " + symbol.typeParams)
// skolemize type parameters
val oldtparams = tparams map (_.symbol)
@@ -1656,7 +1671,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
buf +=
ClassDef(specCls, atPos(impl.pos)(Template(parents, emptyValDef, List()))
.setSymbol(specCls.newLocalDummy(sym1.pos))) setPos tree.pos
- debuglog("created synthetic class: " + specCls + " of " + sym1 + " in env: " + env)
+ debuglog("created synthetic class: " + specCls + " of " + sym1 + " in " + pp(env))
}
case _ =>
}
diff --git a/src/library/scala/concurrent/Awaitable.scala b/src/library/scala/concurrent/Awaitable.scala
index 6c9995eb05..052e6e2366 100644
--- a/src/library/scala/concurrent/Awaitable.scala
+++ b/src/library/scala/concurrent/Awaitable.scala
@@ -16,8 +16,13 @@ import scala.concurrent.util.Duration
trait Awaitable[+T] {
- @implicitNotFound(msg = "Waiting must be done by calling `blocking(timeout) b`, where `b` is the `Awaitable` object or a potentially blocking piece of code.")
- def await(atMost: Duration)(implicit canawait: CanAwait): T
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type
+
+ /**
+ * Throws exceptions if cannot produce a T within the specified time
+ * This method should not be called directly.
+ */
+ def result(atMost: Duration)(implicit permit: CanAwait): T
}
diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala
index 3471095051..ba98757906 100644
--- a/src/library/scala/concurrent/ConcurrentPackageObject.scala
+++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala
@@ -59,14 +59,18 @@ abstract class ConcurrentPackageObject {
/* concurrency constructs */
def future[T](body: =>T)(implicit execCtx: ExecutionContext = executionContext): Future[T] =
- execCtx future body
+ Future[T](body)
def promise[T]()(implicit execCtx: ExecutionContext = executionContext): Promise[T] =
- execCtx promise
+ Promise[T]()
/** Wraps a block of code into an awaitable object. */
def body2awaitable[T](body: =>T) = new Awaitable[T] {
- def await(atMost: Duration)(implicit cb: CanAwait) = body
+ def ready(atMost: Duration)(implicit permit: CanAwait) = {
+ body
+ this
+ }
+ def result(atMost: Duration)(implicit permit: CanAwait) = body
}
/** Used to block on a piece of code which potentially blocks.
@@ -78,8 +82,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](atMost: Duration)(body: =>T)(implicit execCtx: ExecutionContext): T =
- executionContext.blocking(atMost)(body)
+ def blocking[T](body: =>T)(implicit execCtx: ExecutionContext): T =
+ executionContext.blocking(body)
/** Blocks on an awaitable object.
*
diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala
index c4a45f9fb5..a206a2d4ea 100644
--- a/src/library/scala/concurrent/ExecutionContext.scala
+++ b/src/library/scala/concurrent/ExecutionContext.scala
@@ -22,19 +22,11 @@ import collection._
trait ExecutionContext {
- protected implicit object CanAwaitEvidence extends CanAwait
-
def execute(runnable: Runnable): Unit
def execute[U](body: () => U): Unit
- def promise[T]: Promise[T]
-
- def future[T](body: Callable[T]): Future[T] = future(body.call())
-
- def future[T](body: => T): Future[T]
-
- def blocking[T](atMost: Duration)(body: =>T): T
+ def blocking[T](body: =>T): T
def blocking[T](awaitable: Awaitable[T], atMost: Duration): T
@@ -44,89 +36,8 @@ trait ExecutionContext {
private implicit val executionContext = this
- def keptPromise[T](result: T): Promise[T] = {
- val p = promise[T]
- p success result
- }
-
- def brokenPromise[T](t: Throwable): Promise[T] = {
- val p = promise[T]
- p failure t
- }
-
- /** TODO some docs
- *
- */
- def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]])(implicit cbf: CanBuildFrom[Coll[_], T, Coll[T]]): Future[Coll[T]] = {
- import nondeterministic._
- val buffer = new mutable.ArrayBuffer[T]
- val counter = new AtomicInteger(1) // how else could we do this?
- val p: Promise[Coll[T]] = promise[Coll[T]] // we need an implicit execctx in the signature
- var idx = 0
-
- def tryFinish() = if (counter.decrementAndGet() == 0) {
- val builder = cbf(futures)
- builder ++= buffer
- p success builder.result
- }
-
- for (f <- futures) {
- val currentIndex = idx
- buffer += null.asInstanceOf[T]
- counter.incrementAndGet()
- f onComplete {
- case Failure(t) =>
- p tryFailure t
- case Success(v) =>
- buffer(currentIndex) = v
- tryFinish()
- }
- idx += 1
- }
-
- tryFinish()
-
- p.future
- }
-
- /** TODO some docs
- *
- */
- def any[T](futures: Traversable[Future[T]]): Future[T] = {
- val p = promise[T]
- val completeFirst: Try[T] => Unit = elem => p tryComplete elem
-
- futures foreach (_ onComplete completeFirst)
-
- p.future
- }
-
- /** TODO some docs
- *
- */
- def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean): Future[Option[T]] = {
- if (futures.isEmpty) Promise.kept[Option[T]](None).future
- else {
- val result = promise[Option[T]]
- val count = new AtomicInteger(futures.size)
- val search: Try[T] => Unit = {
- v => v match {
- case Success(r) => if (predicate(r)) result trySuccess Some(r)
- case _ =>
- }
- if (count.decrementAndGet() == 0) result trySuccess None
- }
-
- futures.foreach(_ onComplete search)
-
- result.future
- }
- }
-
}
-sealed trait CanAwait
-
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index 1dc8e38355..d73801aa90 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -134,8 +134,26 @@ self =>
/** Creates a new promise.
*/
def newPromise[S]: Promise[S]
-
-
+
+ /** Returns whether the future has already been completed with
+ * a value or an exception.
+ *
+ * $nonDeterministic
+ *
+ * @return `true` if the future is already completed, `false` otherwise
+ */
+ def isCompleted: Boolean
+
+ /** The value of this `Future`.
+ *
+ * If the future is not completed the returned value will be `None`.
+ * If the future is completed the value will be `Some(Success(t))`
+ * if it contains a valid result, or `Some(Failure(error))` if it contains
+ * an exception.
+ */
+ def value: Option[Try[T]]
+
+
/* Projections */
/** Returns a failed projection of this future.
@@ -235,8 +253,8 @@ self =>
* val f = future { 5 }
* val g = f filter { _ % 2 == 1 }
* val h = f filter { _ % 2 == 0 }
- * await(0) g // evaluates to 5
- * await(0) h // throw a NoSuchElementException
+ * await(g, 0) // evaluates to 5
+ * await(h, 0) // throw a NoSuchElementException
* }}}
*/
def filter(pred: T => Boolean): Future[T] = {
@@ -272,8 +290,8 @@ self =>
* val h = f collect {
* case x if x > 0 => x * 2
* }
- * await(0) g // evaluates to 5
- * await(0) h // throw a NoSuchElementException
+ * await(g, 0) // evaluates to 5
+ * await(h, 0) // throw a NoSuchElementException
* }}}
*/
def collect[S](pf: PartialFunction[T, S]): Future[S] = {
@@ -383,7 +401,7 @@ self =>
* val f = future { sys.error("failed") }
* val g = future { 5 }
* val h = f orElse g
- * await(0) h // evaluates to 5
+ * await(h, 0) // evaluates to 5
* }}}
*/
def fallbackTo[U >: T](that: Future[U]): Future[U] = {
@@ -445,7 +463,7 @@ self =>
* val f = future { sys.error("failed") }
* val g = future { 5 }
* val h = f either g
- * await(0) h // evaluates to either 5 or throws a runtime exception
+ * await(h, 0) // evaluates to either 5 or throws a runtime exception
* }}}
*/
def either[U >: T](that: Future[U]): Future[U] = {
@@ -466,26 +484,102 @@ self =>
-/** TODO some docs
+/** Future companion object.
*
* @define nonDeterministic
* Note: using this method yields nondeterministic dataflow programs.
*/
object Future {
+
+ def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = impl.Future(body)
+
+ import scala.collection.mutable.Builder
+ import scala.collection.generic.CanBuildFrom
+
+ /** Simple version of `Futures.traverse`. Transforms a `Traversable[Future[A]]` into a `Future[Traversable[A]]`.
+ * Useful for reducing many `Future`s into a single `Future`.
+ */
+ def sequence[A, M[_] <: Traversable[_]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = {
+ in.foldLeft(Promise.successful(cbf(in)).future) {
+ (fr, fa) => for (r <- fr; a <- fa.asInstanceOf[Future[A]]) yield (r += a)
+ } map (_.result)
+ }
+
+ /** Returns a `Future` to the result of the first future in the list that is completed.
+ */
+ def firstCompletedOf[T](futures: Traversable[Future[T]])(implicit executor: ExecutionContext): Future[T] = {
+ val p = Promise[T]()
+
+ val completeFirst: Try[T] => Unit = p tryComplete _
+ futures.foreach(_ onComplete completeFirst)
- // TODO make more modular by encoding all other helper methods within the execution context
- /** TODO some docs
+ p.future
+ }
+
+ /** Returns a `Future` that will hold the optional result of the first `Future` with a result that matches the predicate.
*/
- def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]])(implicit cbf: CanBuildFrom[Coll[_], T, Coll[T]], ec: ExecutionContext): Future[Coll[T]] =
- ec.all[T, Coll](futures)
+ def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = {
+ if (futures.isEmpty) Promise.successful[Option[T]](None).future
+ else {
+ val result = Promise[Option[T]]()
+ val ref = new AtomicInteger(futures.size)
+ val search: Try[T] => Unit = v => try {
+ v match {
+ case Success(r) => if (predicate(r)) result tryComplete Success(Some(r))
+ case _ =>
+ }
+ } finally {
+ if (ref.decrementAndGet == 0)
+ result tryComplete Success(None)
+ }
- // move this to future companion object
- @inline def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = executor.future(body)
+ futures.foreach(_ onComplete search)
- def any[T](futures: Traversable[Future[T]])(implicit ec: ExecutionContext): Future[T] = ec.any(futures)
+ result.future
+ }
+ }
- def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean)(implicit ec: ExecutionContext): Future[Option[T]] = ec.find(futures)(predicate)
+ /** A non-blocking fold over the specified futures, with the start value of the given zero.
+ * The fold is performed on the thread where the last future is completed,
+ * the result will be the first failure of any of the futures, or any failure in the actual fold,
+ * or the result of the fold.
+ *
+ * Example:
+ * {{{
+ * val result = Await.result(Future.fold(futures)(0)(_ + _), 5 seconds)
+ * }}}
+ */
+ def fold[T, R](futures: Traversable[Future[T]])(zero: R)(foldFun: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = {
+ if (futures.isEmpty) Promise.successful(zero).future
+ else sequence(futures).map(_.foldLeft(zero)(foldFun))
+ }
+ /** Initiates a fold over the supplied futures where the fold-zero is the result value of the `Future` that's completed first.
+ *
+ * Example:
+ * {{{
+ * val result = Await.result(Futures.reduce(futures)(_ + _), 5 seconds)
+ * }}}
+ */
+ def reduce[T, R >: T](futures: Traversable[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = {
+ if (futures.isEmpty) Promise[R].failure(new NoSuchElementException("reduce attempted on empty collection")).future
+ else sequence(futures).map(_ reduceLeft op)
+ }
+
+ /** Transforms a `Traversable[A]` into a `Future[Traversable[B]]` using the provided function `A => Future[B]`.
+ * This is useful for performing a parallel map. For example, to apply a function to all items of a list
+ * in parallel:
+ *
+ * {{{
+ * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x)))
+ * }}}
+ */
+ def traverse[A, B, M[_] <: Traversable[_]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
+ in.foldLeft(Promise.successful(cbf(in)).future) { (fr, a) =>
+ val fb = fn(a.asInstanceOf[A])
+ for (r <- fr; b <- fb) yield (r += b)
+ }.map(_.result)
+
}
diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala
index 4404e90971..61e21606e6 100644
--- a/src/library/scala/concurrent/Promise.scala
+++ b/src/library/scala/concurrent/Promise.scala
@@ -30,8 +30,6 @@ import scala.util.{ Try, Success, Failure }
*/
trait Promise[T] {
- import nondeterministic._
-
/** Future containing the value of this promise.
*/
def future: Future[T]
@@ -114,12 +112,18 @@ trait Promise[T] {
object Promise {
- def kept[T](result: T)(implicit execctx: ExecutionContext): Promise[T] =
- execctx keptPromise result
+ /** Creates a new promise.
+ */
+ def apply[T]()(implicit executor: ExecutionContext): Promise[T] = new impl.Promise.DefaultPromise[T]()
- def broken[T](t: Throwable)(implicit execctx: ExecutionContext): Promise[T] =
- execctx brokenPromise t
+ /** 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))
+ /** 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))
+
}
diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
index 8ac745fd25..5dc440f42b 100644
--- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
+++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala
@@ -15,7 +15,6 @@ import scala.concurrent.forkjoin._
import scala.concurrent.{ExecutionContext, resolver, Awaitable, body2awaitable}
import scala.util.{ Try, Success, Failure }
import scala.concurrent.util.{ Duration }
-import scala.collection.mutable.Stack
@@ -38,32 +37,12 @@ private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends E
def run() = body()
})
- def promise[T]: Promise[T] = new Promise.DefaultPromise[T]()(this)
-
- def future[T](body: =>T): Future[T] = {
- val p = promise[T]
-
- dispatchFuture {
- () =>
- p complete {
- try {
- Success(body)
- } catch {
- case e => resolver(e)
- }
- }
- }
-
- p.future
- }
-
- def blocking[T](atMost: Duration)(body: =>T): T = blocking(body2awaitable(body), atMost)
+ def blocking[T](body: =>T): T = blocking(body2awaitable(body), Duration.fromNanos(0))
def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = {
- currentExecutionContext.get match {
- case null => awaitable.await(atMost)(null) // outside - TODO - fix timeout case
- case x => x.blockingCall(awaitable) // inside an execution context thread
- }
+ Future.releaseStack(this)
+
+ awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence)
}
def reportFailure(t: Throwable) = t match {
@@ -71,61 +50,6 @@ private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends E
case t => t.printStackTrace()
}
- /** Only callable from the tasks running on the same execution context. */
- private def blockingCall[T](body: Awaitable[T]): T = {
- releaseStack()
-
- // TODO see what to do with timeout
- body.await(Duration.fromNanos(0))(CanAwaitEvidence)
- }
-
- // an optimization for batching futures
- // TODO we should replace this with a public queue,
- // so that it can be stolen from
- // OR: a push to the local task queue should be so cheap that this is
- // not even needed, but stealing is still possible
- private val _taskStack = new ThreadLocal[Stack[() => Unit]]()
-
- private def releaseStack(): Unit =
- _taskStack.get match {
- case stack if (stack ne null) && stack.nonEmpty =>
- val tasks = stack.elems
- stack.clear()
- _taskStack.remove()
- dispatchFuture(() => _taskStack.get.elems = tasks, true)
- case null =>
- // do nothing - there is no local batching stack anymore
- case _ =>
- _taskStack.remove()
- }
-
- private[impl] def dispatchFuture(task: () => Unit, force: Boolean = false): Unit =
- _taskStack.get match {
- case stack if (stack ne null) && !force => stack push task
- case _ => this.execute(
- new Runnable {
- def run() {
- try {
- val taskStack = Stack[() => Unit](task)
- _taskStack set taskStack
- while (taskStack.nonEmpty) {
- val next = taskStack.pop()
- try {
- next.apply()
- } catch {
- case e =>
- // TODO catching all and continue isn't good for OOME
- reportFailure(e)
- }
- }
- } finally {
- _taskStack.remove()
- }
- }
- }
- )
- }
-
}
diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala
index b4385ea34a..6833b2467f 100644
--- a/src/library/scala/concurrent/impl/Future.scala
+++ b/src/library/scala/concurrent/impl/Future.scala
@@ -8,13 +8,17 @@
package scala.concurrent.impl
+
+
import scala.concurrent.{Awaitable, ExecutionContext}
import scala.util.{ Try, Success, Failure }
-//import scala.util.continuations._
+import scala.collection.mutable.Stack
+
+
private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] {
- implicit def executor: ExecutionContextImpl
+ implicit def executor: ExecutionContext
/** For use only within a Future.flow block or another compatible Delimited Continuations reset block.
*
@@ -40,7 +44,7 @@ private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awa
* that conforms to A's erased type or a ClassCastException otherwise.
*/
final def mapTo[T](implicit m: Manifest[T]) = {
- val p = executor.promise[T]
+ val p = new Promise.DefaultPromise[T]
onComplete {
case f @ Failure(t) => p complete f.asInstanceOf[Try[T]]
@@ -48,7 +52,7 @@ private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awa
p complete (try {
Success(Future.boxedType(m.erasure).cast(v).asInstanceOf[T])
} catch {
- case e: ClassCastException ⇒ Failure(e)
+ case e: ClassCastException => Failure(e)
})
}
@@ -86,4 +90,66 @@ object Future {
def boxedType(c: Class[_]): Class[_] = {
if (c.isPrimitive) toBoxed(c) else c
}
+
+ def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = {
+ val promise = new Promise.DefaultPromise[T]()
+ executor.execute(new Runnable {
+ def run = {
+ promise complete {
+ try {
+ Success(body)
+ } catch {
+ case e => scala.concurrent.resolver(e)
+ }
+ }
+ }
+ })
+ promise.future
+ }
+
+ // an optimization for batching futures
+ // TODO we should replace this with a public queue,
+ // so that it can be stolen from
+ // OR: a push to the local task queue should be so cheap that this is
+ // not even needed, but stealing is still possible
+ private val _taskStack = new ThreadLocal[Stack[() => Unit]]()
+
+ private[impl] def releaseStack(executor: ExecutionContext): Unit =
+ _taskStack.get match {
+ case stack if (stack ne null) && stack.nonEmpty =>
+ val tasks = stack.elems
+ stack.clear()
+ _taskStack.remove()
+ dispatchFuture(executor, () => _taskStack.get.elems = tasks, true)
+ case null =>
+ // do nothing - there is no local batching stack anymore
+ case _ =>
+ _taskStack.remove()
+ }
+
+ private[impl] def dispatchFuture(executor: ExecutionContext, task: () => Unit, force: Boolean = false): Unit =
+ _taskStack.get match {
+ case stack if (stack ne null) && !force => stack push task
+ case _ => executor.execute(new Runnable {
+ def run() {
+ try {
+ val taskStack = Stack[() => Unit](task)
+ _taskStack set taskStack
+ while (taskStack.nonEmpty) {
+ val next = taskStack.pop()
+ try {
+ next.apply()
+ } catch {
+ case e =>
+ // TODO catching all and continue isn't good for OOME
+ executor.reportFailure(e)
+ }
+ }
+ } finally {
+ _taskStack.remove()
+ }
+ }
+ })
+ }
+
}
diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala
index 4a983b5001..c79b0d02cc 100644
--- a/src/library/scala/concurrent/impl/Promise.scala
+++ b/src/library/scala/concurrent/impl/Promise.scala
@@ -26,7 +26,7 @@ private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with Fu
def future = this
- def newPromise[S]: Promise[S] = executor promise
+ def newPromise[S]: scala.concurrent.Promise[S] = new Promise.DefaultPromise()
// TODO refine answer and return types here from Any to type parameters
// then move this up in the hierarchy
@@ -75,6 +75,7 @@ private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with Fu
object Promise {
+
def dur2long(dur: Duration): Long = if (dur.isFinite) dur.toNanos else Long.MaxValue
def EmptyPending[T](): FState[T] = emptyPendingValue.asInstanceOf[FState[T]]
@@ -101,7 +102,7 @@ object Promise {
/** Default promise implementation.
*/
- class DefaultPromise[T](implicit val executor: ExecutionContextImpl) extends AbstractPromise with Promise[T] {
+ class DefaultPromise[T](implicit val executor: ExecutionContext) extends AbstractPromise with Promise[T] {
self =>
updater.set(this, Promise.EmptyPending())
@@ -126,14 +127,14 @@ object Promise {
value.isDefined
}
- executor.blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), Duration.fromNanos(0))
+ executor.blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), atMost)
}
- private def ready(atMost: Duration)(implicit permit: CanAwait): this.type =
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type =
if (value.isDefined || tryAwait(atMost)) this
else throw new TimeoutException("Futures timed out after [" + atMost.toMillis + "] milliseconds")
- def await(atMost: Duration)(implicit permit: CanAwait): T =
+ def result(atMost: Duration)(implicit permit: CanAwait): T =
ready(atMost).value.get match {
case util.Failure(e) => throw e
case util.Success(r) => r
@@ -176,9 +177,9 @@ object Promise {
case null => false
case cs if cs.isEmpty => true
case cs =>
- executor dispatchFuture {
+ Future.dispatchFuture(executor, {
() => cs.foreach(f => notifyCompleted(f, value))
- }
+ })
true
}
}
@@ -197,9 +198,9 @@ object Promise {
if (tryAddCallback()) {
val result = value.get
- executor dispatchFuture {
+ Future.dispatchFuture(executor, {
() => notifyCompleted(func, result)
- }
+ })
}
this
@@ -218,22 +219,22 @@ object Promise {
*
* Useful in Future-composition when a value to contribute is already available.
*/
- final class KeptPromise[T](suppliedValue: Try[T])(implicit val executor: ExecutionContextImpl) extends Promise[T] {
+ final class KeptPromise[T](suppliedValue: Try[T])(implicit val executor: ExecutionContext) extends Promise[T] {
val value = Some(resolve(suppliedValue))
def tryComplete(value: Try[T]): Boolean = false
def onComplete[U](func: Try[T] => U): this.type = {
val completedAs = value.get
- executor dispatchFuture {
+ Future.dispatchFuture(executor, {
() => func(completedAs)
- }
+ })
this
}
- private def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this
- def await(atMost: Duration)(implicit permit: CanAwait): T = value.get match {
+ def result(atMost: Duration)(implicit permit: CanAwait): T = value.get match {
case util.Failure(e) => throw e
case util.Success(r) => r
}
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index 204b3f2673..e2ae17498f 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -20,27 +20,17 @@ package object concurrent extends scala.concurrent.ConcurrentPackageObject {
}
package concurrent {
- object await {
- def ready[T](atMost: Duration)(awaitable: Awaitable[T])(implicit execCtx: ExecutionContext = executionContext): Awaitable[T] = {
- try blocking(awaitable, atMost)
- catch { case _ => }
- awaitable
- }
-
- def result[T](atMost: Duration)(awaitable: Awaitable[T])(implicit execCtx: ExecutionContext = executionContext): T = {
- blocking(awaitable, atMost)
- }
+
+ sealed trait CanAwait
+
+ object Await {
+ private[concurrent] implicit val canAwaitEvidence = new CanAwait {}
+
+ def ready[T](awaitable: Awaitable[T], atMost: Duration): Awaitable[T] = awaitable.ready(atMost)
+
+ def result[T](awaitable: Awaitable[T], atMost: Duration): T = awaitable.result(atMost)
}
- /** Importing this object allows using some concurrency primitives
- * on futures and promises that can yield nondeterministic programs.
- *
- * While program determinism is broken when using these primitives,
- * some programs cannot be written without them (e.g. multiple client threads
- * cannot send requests to a server thread through regular promises and futures).
- */
- object nondeterministic { }
-
/** A timeout exception.
*
* Futures are failed with a timeout exception when their timeout expires.
diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala
index 70221c0de1..75e2b92ff6 100644
--- a/test/files/jvm/scala-concurrent-tck.scala
+++ b/test/files/jvm/scala-concurrent-tck.scala
@@ -74,7 +74,7 @@ trait FutureCallbacks extends TestBase {
done()
throw new Exception
}
- f onSuccess {
+ f onSuccess {
case _ => assert(false)
}
}
diff --git a/test/pending/pos/t1476.scala b/test/pending/pos/t1476.scala
new file mode 100644
index 0000000000..1f8e95c28f
--- /dev/null
+++ b/test/pending/pos/t1476.scala
@@ -0,0 +1,23 @@
+abstract class Module {
+ def moduleDemands(): List[Module]
+}
+
+object Test {
+ new Module { owner: Module =>
+ def moduleDemands() = Nil
+
+ val a = new Module { def moduleDemands(): List[Module] = Nil }
+ val b = new Module { def moduleDemands(): List[Module] = owner :: c :: Nil }
+ val c = new Module { def moduleDemands(): List[Module] = owner :: a :: Nil }
+ }
+}
+
+object Test2 {
+ new Module { owner =>
+ def moduleDemands() = Nil
+
+ val a = new Module { def moduleDemands(): List[Module] = Nil }
+ val b = new Module { def moduleDemands(): List[Module] = owner :: c :: Nil }
+ val c = new Module { def moduleDemands(): List[Module] = owner :: a :: Nil }
+ }
+}
diff --git a/test/pending/pos/t5626.scala b/test/pending/pos/t5626.scala
new file mode 100644
index 0000000000..7ab3881827
--- /dev/null
+++ b/test/pending/pos/t5626.scala
@@ -0,0 +1,12 @@
+object Test {
+ val blob0 = new {
+ case class Foo(i : Int)
+ }
+ val foo0 = blob0.Foo(22)
+
+ val blob1 = new {
+ class Foo(i: Int)
+ object Foo { def apply(i: Int): Foo = new Foo(i) }
+ }
+ val foo1 = blob1.Foo(22)
+}
diff --git a/test/pending/run/t5629.check b/test/pending/run/t5629.check
new file mode 100644
index 0000000000..6a2d630f4e
--- /dev/null
+++ b/test/pending/run/t5629.check
@@ -0,0 +1,2 @@
+int child got: 33
+any child got: 33
diff --git a/test/pending/run/t5629.scala b/test/pending/run/t5629.scala
new file mode 100644
index 0000000000..28e74a1c94
--- /dev/null
+++ b/test/pending/run/t5629.scala
@@ -0,0 +1,25 @@
+import scala.{specialized => spec}
+
+trait GrandParent[@spec(Int) -A] {
+ def foo(a:A): Unit
+ def bar[B <: A](b:B): Unit = println("grandparent got: %s" format b)
+}
+
+trait Parent[@spec(Int) -A] extends GrandParent[A] {
+ def foo(a:A) = bar(a)
+}
+
+class IntChild extends Parent[Int] {
+ override def bar[B <: Int](b:B): Unit = println("int child got: %s" format b)
+}
+
+class AnyChild extends Parent[Any] {
+ override def bar[B <: Any](b:B): Unit = println("any child got: %s" format b)
+}
+
+object Test {
+ def main(args:Array[String]) {
+ new IntChild().foo(33)
+ new AnyChild().foo(33)
+ }
+}