@@ -101,7 +101,7 @@ private[concurrent] object Promise {
101
101
}
102
102
103
103
// Left non-final to enable addition of extra fields by Java/Scala converters in scala-java8-compat.
104
- class DefaultPromise [T ] private [this ] (initial : AnyRef ) extends AtomicReference [AnyRef ](initial) with scala.concurrent.Promise [T ] with scala.concurrent.Future [T ] {
104
+ class DefaultPromise [T ] private [this ] (initial : AnyRef ) extends AtomicReference [AnyRef ](initial) with scala.concurrent.Promise [T ] with scala.concurrent.Future [T ] with ( Try [ T ] => Unit ) {
105
105
/**
106
106
* Constructs a new, completed, Promise.
107
107
*/
@@ -112,6 +112,13 @@ private[concurrent] object Promise {
112
112
*/
113
113
final def this () = this (Noop : AnyRef )
114
114
115
+ /**
116
+ * WARNING: the `resolved` value needs to have been pre-resolved using `resolve()`
117
+ * INTERNAL API
118
+ */
119
+ override final def apply (resolved : Try [T ]): Unit =
120
+ tryComplete0(get(), resolved)
121
+
115
122
/**
116
123
* Returns the associated `Future` with this `Promise`
117
124
*/
@@ -248,11 +255,13 @@ private[concurrent] object Promise {
248
255
} else /* if(state.isInstanceOf[Try[T]]) */ false
249
256
250
257
override final def completeWith (other : Future [T ]): this .type = {
251
- val state = get()
252
- if ((other ne this ) && ! state.isInstanceOf [Try [T ]]) {
253
- val resolved = if (other.isInstanceOf [DefaultPromise [T ]]) other.asInstanceOf [DefaultPromise [T ]].value0 else null
254
- if (resolved ne null ) tryComplete0(state, resolved)
255
- else super .completeWith(other)
258
+ if (other ne this ) {
259
+ val state = get()
260
+ if (! state.isInstanceOf [Try [T ]]) {
261
+ val resolved = if (other.isInstanceOf [DefaultPromise [T ]]) other.asInstanceOf [DefaultPromise [T ]].value0 else other.value.orNull
262
+ if (resolved ne null ) tryComplete0(state, resolved)
263
+ else other.onComplete(this )(InternalCallbackExecutor )
264
+ }
256
265
}
257
266
258
267
this
@@ -362,10 +371,11 @@ private[concurrent] object Promise {
362
371
**/
363
372
final class Transformation [- F , T ] private [this ] (
364
373
private [this ] final var _fun : Any => Any ,
365
- private [this ] final var _arg : AnyRef ,
374
+ private [this ] final var _ec : ExecutionContext ,
375
+ private [this ] final var _arg : Try [F ],
366
376
private [this ] final val _xform : Byte
367
377
) extends DefaultPromise [T ]() with Callbacks [F ] with Runnable with Batchable with OnCompleteRunnable {
368
- final def this (xform : Int , f : _ => _, ec : ExecutionContext ) = this (f.asInstanceOf [Any => Any ], ec.prepare(): AnyRef , xform.toByte)
378
+ final def this (xform : Int , f : _ => _, ec : ExecutionContext ) = this (f.asInstanceOf [Any => Any ], ec.prepare(), null , xform.toByte)
369
379
370
380
final def benefitsFromBatching : Boolean = _xform != Xform_onComplete && _xform != Xform_foreach
371
381
@@ -374,9 +384,9 @@ private[concurrent] object Promise {
374
384
// Invariant: _arg is `ExecutionContext`, and non-null. `this` ne Noop.
375
385
// requireNonNull(resolved) will hold as guarded by `resolve`
376
386
final def submitWithValue (resolved : Try [F ]): this .type = {
377
- val e = _arg.asInstanceOf [ExecutionContext ]
378
387
_arg = resolved
379
- try e.execute(this ) /* Safe publication of _arg and _fun */
388
+ val e = _ec
389
+ try e.execute(this ) /* Safe publication of _arg, _fun, _ec */
380
390
catch {
381
391
case t : Throwable => handleFailure(t, e)
382
392
}
@@ -387,81 +397,77 @@ private[concurrent] object Promise {
387
397
private [this ] final def handleFailure (t : Throwable , e : ExecutionContext ): Unit = {
388
398
_fun = null // allow to GC
389
399
_arg = null // see above
400
+ _ec = null // see above again
390
401
val wasInterrupted = t.isInstanceOf [InterruptedException ]
391
402
if (wasInterrupted || NonFatal (t)) {
392
403
val completed = tryComplete0(get(), resolve(Failure (t)))
393
404
if (completed && wasInterrupted) Thread .currentThread.interrupt()
394
- if (! completed && (e ne null )) e.reportFailure(t)
405
+
406
+ // Report or rethrow failures which are unlikely to otherwise be noticed
407
+ if (_xform == Xform_foreach || _xform == Xform_onComplete || ! completed)
408
+ e.reportFailure(t)
395
409
} else throw t
396
410
}
397
411
412
+ @ inline private [this ] final def completeWithLink (f : Future [T ]): Try [T ] = {
413
+ if (f.isInstanceOf [DefaultPromise [T ]])
414
+ f.asInstanceOf [DefaultPromise [T ]].linkRootOf(this , null )
415
+ else
416
+ completeWith(f)
417
+
418
+ null
419
+ }
420
+
398
421
// Gets invoked by the ExecutionContext, when we have a value to transform.
399
- // Invariant: if (_arg.isInstanceOf[Try[F]] && (_fun ne null))
400
- override final def run (): Unit =
422
+ override final def run (): Unit = {
423
+ val v = _arg
424
+ val fun = _fun
425
+ val ec = _ec
401
426
try {
402
- val v = _arg.asInstanceOf [Try [F ]]
403
- (_xform.toInt: @ switch) match {
404
- case Xform_noop => doAbort(v)
405
- case Xform_map => doMap(v)
406
- case Xform_flatMap => doFlatMap(v)
407
- case Xform_transform => doTransform(v)
408
- case Xform_transformWith => doTransformWith(v)
409
- case Xform_foreach => v.foreach(_fun)
410
- case Xform_onComplete => _fun(v)
411
- case Xform_recover => doRecover(v)
412
- case Xform_recoverWith => doRecoverWith(v)
413
- case Xform_filter => doFilter(v)
414
- case Xform_collect => doCollect(v)
415
- case _ => doAbort(v)
416
- }
427
+ val resolvedResult : Try [T ] =
428
+ (_xform.toInt: @ switch) match {
429
+ case Xform_noop =>
430
+ null
431
+ case Xform_map =>
432
+ if (v.isInstanceOf [Success [F ]]) Success (fun(v.asInstanceOf [Success [F ]].value).asInstanceOf [T ]) else v.asInstanceOf [Failure [T ]]
433
+ case Xform_flatMap =>
434
+ if (v.isInstanceOf [Success [F ]]) completeWithLink(fun(v.asInstanceOf [Success [F ]].value).asInstanceOf [Future [T ]])
435
+ else v.asInstanceOf [Failure [T ]] // Already resolved
436
+ case Xform_transform =>
437
+ resolve(fun(v).asInstanceOf [Try [T ]])
438
+ case Xform_transformWith =>
439
+ completeWithLink(fun(v).asInstanceOf [Future [T ]])
440
+ case Xform_foreach =>
441
+ if (v.isInstanceOf [Success [F ]]) fun(v.asInstanceOf [Success [F ]].value)
442
+ null
443
+ case Xform_onComplete =>
444
+ fun(v)
445
+ null
446
+ case Xform_recover =>
447
+ resolve(v.recover(fun.asInstanceOf [PartialFunction [Throwable , F ]]).asInstanceOf [Try [T ]]) // recover F=:=T
448
+ case Xform_recoverWith =>
449
+ if (v.isInstanceOf [Failure [F ]]) {
450
+ val f = fun.asInstanceOf [PartialFunction [Throwable , Future [T ]]].applyOrElse(v.asInstanceOf [Failure [F ]].exception, Future .recoverWithFailed)
451
+ if (f ne Future .recoverWithFailedMarker) completeWithLink(f)
452
+ else v.asInstanceOf [Failure [T ]]
453
+ } else v.asInstanceOf [Success [T ]]
454
+ case Xform_filter =>
455
+ if (v.isInstanceOf [Failure [F ]] || fun.asInstanceOf [F => Boolean ](v.asInstanceOf [Success [F ]].value)) v.asInstanceOf [Try [T ]]
456
+ else Future .filterFailure // Safe for unresolved completes
457
+ case Xform_collect =>
458
+ if (v.isInstanceOf [Success [F ]]) Success (fun.asInstanceOf [PartialFunction [F , T ]].applyOrElse(v.asInstanceOf [Success [F ]].value, Future .collectFailed))
459
+ else v.asInstanceOf [Failure [T ]] // Already resolved
460
+ case _ =>
461
+ Failure (new IllegalStateException (" BUG: encountered transformation promise with illegal type: " + _xform))
462
+ }
463
+ if (resolvedResult ne null )
464
+ tryComplete0(get(), resolvedResult)
417
465
_fun = null // allow to GC
418
466
_arg = null // see above
467
+ _ec = null // see above
419
468
} catch {
420
- case t : Throwable => handleFailure(t, null )
469
+ case t : Throwable => handleFailure(t, ec )
421
470
}
422
-
423
- private [this ] final def doMap (v : Try [F ]): Unit = { tryComplete0(get(), resolve(v.map(_fun.asInstanceOf [F => T ]))) }
424
-
425
- private [this ] final def doFlatMap (v : Try [F ]): Unit =
426
- if (v.isInstanceOf [Success [F ]]) {
427
- val f = _fun(v.asInstanceOf [Success [F ]].value)
428
- if (f.isInstanceOf [DefaultPromise [T ]]) f.asInstanceOf [DefaultPromise [T ]].linkRootOf(this , null )
429
- else completeWith(f.asInstanceOf [Future [T ]])
430
- } else tryComplete0(get(), v.asInstanceOf [Try [T ]]) // Already resolved
431
-
432
- private [this ] final def doTransform (v : Try [F ]): Unit = tryComplete0(get(), resolve(_fun(v).asInstanceOf [Try [T ]]))
433
-
434
- private [this ] final def doTransformWith (v : Try [F ]): Unit = {
435
- val f = _fun(v)
436
- if (f.isInstanceOf [DefaultPromise [T ]]) f.asInstanceOf [DefaultPromise [T ]].linkRootOf(this , null )
437
- else completeWith(f.asInstanceOf [Future [T ]])
438
471
}
439
-
440
- private [this ] final def doRecover (v : Try [F ]): Unit =
441
- tryComplete0(get(), resolve(v.recover(_fun.asInstanceOf [PartialFunction [Throwable , F ]]).asInstanceOf [Try [T ]])) // recover F=:=T
442
-
443
- private [this ] final def doRecoverWith (v : Try [F ]): Unit = // recoverWith F=:=T
444
- if (v.isInstanceOf [Failure [F ]]) {
445
- val f = _fun.asInstanceOf [PartialFunction [Throwable , Future [T ]]].applyOrElse(v.asInstanceOf [Failure [F ]].exception, Future .recoverWithFailed)
446
- if (f ne Future .recoverWithFailedMarker) {
447
- if (f.isInstanceOf [DefaultPromise [T ]]) f.asInstanceOf [DefaultPromise [T ]].linkRootOf(this , null )
448
- else completeWith(f)
449
- } else tryComplete0(get(), v.asInstanceOf [Failure [T ]])
450
- } else tryComplete0(get(), v.asInstanceOf [Try [T ]])
451
-
452
- private [this ] final def doFilter (v : Try [F ]): Unit =
453
- tryComplete0(get(),
454
- if (v.isInstanceOf [Failure [F ]] || _fun.asInstanceOf [F => Boolean ](v.asInstanceOf [Success [F ]].value)) v.asInstanceOf [Try [T ]]
455
- else Future .filterFailure // Safe for unresolved completes
456
- )
457
-
458
- private [this ] final def doCollect (v : Try [F ]): Unit =
459
- tryComplete0(get(),
460
- if (v.isInstanceOf [Success [F ]]) Success (_fun.asInstanceOf [PartialFunction [F , T ]].applyOrElse(v.asInstanceOf [Success [F ]].value, Future .collectFailed))
461
- else v.asInstanceOf [Try [T ]] // Already resolved
462
- )
463
-
464
- private [this ] final def doAbort (v : Try [F ]): Unit =
465
- tryComplete0(get(), Failure (new IllegalStateException (" BUG: encountered transformation promise with illegal type: " + _xform)))
466
472
}
467
473
}
0 commit comments