mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:29:48 +00:00
[dart2wasm] New async* desugaring
See `_lowerAsyncStar` for the desugaring plan. Fixes tests: co19/Language/Expressions/Function_Invocation/async_generator_invokation_t04 co19/Language/Expressions/Function_Invocation/async_generator_invokation_t08 co19/Language/Statements/Yield_and_Yield_Each/Yield/execution_async_A01_t07 co19/Language/Statements/Yield_and_Yield_Each/Yield/execution_async_A03_t04 co19/Language/Statements/Yield_and_Yield_Each/Yield/execution_async_A03_t05 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t03 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t07 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t08 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t09 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t11 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t12 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t14 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t15 co19/Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t16 language/async_star/async_star_await_for_test language/async_star/async_star_cancel_test language/async_star/async_star_test language/async_star/throw_in_catch_test language/async_star/yield_test language/async_star/yieldstar_test lib/async/async_await_zones_test Fixes #55025. Fixes #55018. Fixes #52464. Change-Id: I9d51564698710993cb7d2cc64b3bb8c26d6d4c77 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/355360 Commit-Queue: Ömer Ağacan <omersa@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
88403d9c3e
commit
a2b833ede4
|
@ -30,20 +30,32 @@ class _WasmTransformer extends Transformer {
|
||||||
|
|
||||||
Member? _currentMember;
|
Member? _currentMember;
|
||||||
StaticTypeContext? _cachedTypeContext;
|
StaticTypeContext? _cachedTypeContext;
|
||||||
|
|
||||||
final Library _coreLibrary;
|
final Library _coreLibrary;
|
||||||
final InterfaceType _nonNullableTypeType;
|
final InterfaceType _nonNullableTypeType;
|
||||||
final Class _wasmBaseClass;
|
|
||||||
|
final Class _completerClass;
|
||||||
|
final Class _streamControllerClass;
|
||||||
final Class _wasmArrayClass;
|
final Class _wasmArrayClass;
|
||||||
|
final Class _wasmBaseClass;
|
||||||
|
|
||||||
|
final Procedure _completerComplete;
|
||||||
|
final Procedure _completerConstructor;
|
||||||
|
final Procedure _completerGetFuture;
|
||||||
|
final Procedure _streamControllerAdd;
|
||||||
|
final Procedure _streamControllerAddError;
|
||||||
|
final Procedure _streamControllerAddStream;
|
||||||
|
final Procedure _streamControllerClose;
|
||||||
|
final Procedure _streamControllerConstructor;
|
||||||
|
final Procedure _streamControllerGetHasListener;
|
||||||
|
final Procedure _streamControllerGetIsPaused;
|
||||||
|
final Procedure _streamControllerGetStream;
|
||||||
|
final Procedure _streamControllerSetOnCancel;
|
||||||
|
final Procedure _streamControllerSetOnListen;
|
||||||
|
final Procedure _streamControllerSetOnResume;
|
||||||
|
|
||||||
final List<_AsyncStarFrame> _asyncStarFrames = [];
|
final List<_AsyncStarFrame> _asyncStarFrames = [];
|
||||||
bool _enclosingIsAsyncStar = false;
|
bool _enclosingIsAsyncStar = false;
|
||||||
late final controllerNullableObjectType = InterfaceType(
|
|
||||||
coreTypes.index.getClass('dart:async', 'StreamController'),
|
|
||||||
Nullability.nonNullable,
|
|
||||||
[coreTypes.objectNullableRawType]);
|
|
||||||
late final completerBoolType = InterfaceType(
|
|
||||||
coreTypes.index.getClass('dart:async', 'Completer'),
|
|
||||||
Nullability.nonNullable,
|
|
||||||
[coreTypes.boolNonNullableRawType]);
|
|
||||||
|
|
||||||
final ListFactorySpecializer _listFactorySpecializer;
|
final ListFactorySpecializer _listFactorySpecializer;
|
||||||
|
|
||||||
|
@ -58,9 +70,40 @@ class _WasmTransformer extends Transformer {
|
||||||
_nonNullableTypeType = coreTypes.index
|
_nonNullableTypeType = coreTypes.index
|
||||||
.getClass('dart:core', '_Type')
|
.getClass('dart:core', '_Type')
|
||||||
.getThisType(coreTypes, Nullability.nonNullable),
|
.getThisType(coreTypes, Nullability.nonNullable),
|
||||||
_wasmBaseClass = coreTypes.index.getClass('dart:_wasm', '_WasmBase'),
|
|
||||||
_wasmArrayClass = coreTypes.index.getClass('dart:_wasm', 'WasmArray'),
|
|
||||||
_coreLibrary = coreTypes.index.getLibrary('dart:core'),
|
_coreLibrary = coreTypes.index.getLibrary('dart:core'),
|
||||||
|
_completerClass = coreTypes.index.getClass('dart:async', 'Completer'),
|
||||||
|
_streamControllerClass =
|
||||||
|
coreTypes.index.getClass('dart:async', 'StreamController'),
|
||||||
|
_wasmArrayClass = coreTypes.index.getClass('dart:_wasm', 'WasmArray'),
|
||||||
|
_wasmBaseClass = coreTypes.index.getClass('dart:_wasm', '_WasmBase'),
|
||||||
|
_completerComplete =
|
||||||
|
coreTypes.index.getProcedure('dart:async', 'Completer', 'complete'),
|
||||||
|
_completerConstructor =
|
||||||
|
coreTypes.index.getProcedure('dart:async', 'Completer', ''),
|
||||||
|
_completerGetFuture = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'Completer', 'get:future'),
|
||||||
|
_streamControllerAdd = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'add'),
|
||||||
|
_streamControllerAddError = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'addError'),
|
||||||
|
_streamControllerAddStream = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'addStream'),
|
||||||
|
_streamControllerClose = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'close'),
|
||||||
|
_streamControllerConstructor =
|
||||||
|
coreTypes.index.getProcedure('dart:async', 'StreamController', ''),
|
||||||
|
_streamControllerGetHasListener = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'get:hasListener'),
|
||||||
|
_streamControllerGetIsPaused = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'get:isPaused'),
|
||||||
|
_streamControllerGetStream = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'get:stream'),
|
||||||
|
_streamControllerSetOnCancel = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'set:onCancel'),
|
||||||
|
_streamControllerSetOnListen = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'set:onListen'),
|
||||||
|
_streamControllerSetOnResume = coreTypes.index
|
||||||
|
.getProcedure('dart:async', 'StreamController', 'set:onResume'),
|
||||||
_listFactorySpecializer = ListFactorySpecializer(coreTypes);
|
_listFactorySpecializer = ListFactorySpecializer(coreTypes);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -279,353 +322,257 @@ class _WasmTransformer extends Transformer {
|
||||||
return _lowerForIn(stmt);
|
return _lowerForIn(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticInvocation _completerBoolInitializer() => StaticInvocation(
|
|
||||||
coreTypes.index.getProcedure('dart:async', 'Completer', ''),
|
|
||||||
Arguments([], types: [coreTypes.boolNonNullableRawType]));
|
|
||||||
|
|
||||||
InstanceInvocation _addToController(
|
InstanceInvocation _addToController(
|
||||||
VariableDeclaration controller, Expression expression, int fileOffset) {
|
VariableDeclaration controller, Expression expression, int fileOffset) {
|
||||||
Procedure controllerAdd =
|
final controllerNullableObjectType = InterfaceType(_streamControllerClass,
|
||||||
coreTypes.index.getProcedure('dart:async', 'StreamController', 'add');
|
Nullability.nonNullable, [coreTypes.objectNullableRawType]);
|
||||||
FunctionType controllerAddType =
|
FunctionType controllerAddType =
|
||||||
Substitution.fromInterfaceType(controllerNullableObjectType)
|
Substitution.fromInterfaceType(controllerNullableObjectType)
|
||||||
.substituteType(controllerAdd.function
|
.substituteType(_streamControllerAdd.function
|
||||||
.computeThisFunctionType(Nullability.nonNullable))
|
.computeThisFunctionType(Nullability.nonNullable))
|
||||||
as FunctionType;
|
as FunctionType;
|
||||||
return InstanceInvocation(InstanceAccessKind.Instance,
|
return InstanceInvocation(InstanceAccessKind.Instance,
|
||||||
VariableGet(controller), Name('add'), Arguments([expression]),
|
VariableGet(controller), Name('add'), Arguments([expression]),
|
||||||
interfaceTarget: controllerAdd, functionType: controllerAddType)
|
interfaceTarget: _streamControllerAdd, functionType: controllerAddType)
|
||||||
..fileOffset = fileOffset;
|
..fileOffset = fileOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceInvocation _addCompleterToController(VariableDeclaration controller,
|
|
||||||
VariableDeclaration completer, int fileOffset) =>
|
|
||||||
_addToController(controller, VariableGet(completer), fileOffset);
|
|
||||||
|
|
||||||
AwaitExpression _awaitCompleterFuture(
|
|
||||||
VariableDeclaration completer, int fileOffset) {
|
|
||||||
Procedure completerFuture =
|
|
||||||
coreTypes.index.getProcedure('dart:async', 'Completer', 'get:future');
|
|
||||||
// Future<bool>
|
|
||||||
DartType completerFutureType = InterfaceType(coreTypes.futureClass,
|
|
||||||
Nullability.nonNullable, [coreTypes.boolNonNullableRawType]);
|
|
||||||
return AwaitExpression(InstanceGet(
|
|
||||||
InstanceAccessKind.Instance, VariableGet(completer), Name('future'),
|
|
||||||
interfaceTarget: completerFuture, resultType: completerFutureType)
|
|
||||||
..fileOffset = fileOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeNode _lowerAsyncStar(FunctionNode functionNode) {
|
TreeNode _lowerAsyncStar(FunctionNode functionNode) {
|
||||||
// TODO(joshualitt): This lowering is mostly reasonable, but if possible we
|
// Convert the function into:
|
||||||
// should try and figure out a way to remove the even / odd dance. That
|
|
||||||
// said, this will be replaced by an intrinsic implementation ASAP so it may
|
|
||||||
// not be worth spending anymore time on this(aside from bug fixes).
|
|
||||||
//
|
//
|
||||||
// Transform
|
// Stream<T> name(args) {
|
||||||
|
// var #controller = StreamController<T>(sync: true);
|
||||||
//
|
//
|
||||||
// Stream<T> foo() async* {
|
// void #body() async {
|
||||||
// ...
|
// Completer<void>? #paused;
|
||||||
// yield i;
|
//
|
||||||
// ...
|
// #controller.onResume = #controller.onCancel = () {
|
||||||
// yield* bar;
|
// #paused?.complete(null);
|
||||||
// ...
|
// #paused = null;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// <transformed body>
|
||||||
|
// } catch (e, s) {
|
||||||
|
// #controller.addError(e, s);
|
||||||
|
// } finally {
|
||||||
|
// #controller.close();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #controller.onListen = () {
|
||||||
|
// scheduleMicrotask(#body);
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// return controller.stream;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Where `<transformed body>` is the body of `functionNode` with these
|
||||||
|
// transformations:
|
||||||
|
//
|
||||||
|
// - yield* e
|
||||||
|
//
|
||||||
|
// ==>
|
||||||
|
//
|
||||||
|
// await #controller.addStream(e);
|
||||||
|
// if (!#controller.hasListener) {
|
||||||
|
// return;
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Into
|
// - yield e
|
||||||
//
|
//
|
||||||
// Stream<T> foo() {
|
// ==>
|
||||||
// StreamController<Object?> #controller = StreamController<Object?>();
|
//
|
||||||
// Future<void> Function() #body = () async {
|
// #controller.add(e);
|
||||||
// Completer<bool> #completer = Completer<bool>();
|
// if (#controller.isPaused) {
|
||||||
// #controller.add(#completer);
|
// await (#paused = Completer()).future;
|
||||||
// try {
|
|
||||||
// await #completer.future;
|
|
||||||
// ...
|
|
||||||
// #controller.add(i);
|
|
||||||
// #completer = Completer<bool>();
|
|
||||||
// #controller.add(#completer)
|
|
||||||
// await #completer.future;
|
|
||||||
// ...
|
|
||||||
// await for (var i in bar) {
|
|
||||||
// #controller.add(i);
|
|
||||||
// #completer = Completer<bool>();
|
|
||||||
// #controller.add(#completer)
|
|
||||||
// await #completer.future;
|
|
||||||
// }
|
|
||||||
// ...
|
|
||||||
// } catch (e) {
|
|
||||||
// #controller.addError(e);
|
|
||||||
// } finally {
|
|
||||||
// #controller.close();
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// bool isEven = false;
|
|
||||||
// bool isFirst = true;
|
|
||||||
// #controller.add(null);
|
|
||||||
// return #controller.stream.asyncMap((value) async {
|
|
||||||
// if (isFirst) {
|
|
||||||
// #body();
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// if (value is Completer<Bool>) {
|
|
||||||
// value.complete(true);
|
|
||||||
// }
|
|
||||||
// return value;
|
|
||||||
// }).where((value) {
|
|
||||||
// if (isFirst) {
|
|
||||||
// isFirst = false;
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// bool keep = isEven;
|
|
||||||
// isEven = !isEven;
|
|
||||||
// return keep;
|
|
||||||
// }).cast<T>();
|
|
||||||
// }
|
// }
|
||||||
int fileOffset = functionNode.fileOffset;
|
// if (!#controller.hasListener) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The `yield` and `yield*` transformations are done by [visitYieldStatement].
|
||||||
|
|
||||||
// Initialize `#controller`.
|
final fileOffset = functionNode.fileOffset;
|
||||||
|
final emittedValueType = functionNode.emittedValueType!;
|
||||||
|
|
||||||
|
// var #controller = StreamController<T>(sync: true);
|
||||||
|
final controllerObjectType = InterfaceType(
|
||||||
|
_streamControllerClass, Nullability.nonNullable, [emittedValueType]);
|
||||||
|
|
||||||
|
// StreamController<T>(sync: true)
|
||||||
final controllerInitializer = StaticInvocation(
|
final controllerInitializer = StaticInvocation(
|
||||||
coreTypes.index.getProcedure('dart:async', 'StreamController', ''),
|
_streamControllerConstructor,
|
||||||
Arguments([], types: [coreTypes.objectNullableRawType]));
|
Arguments([], types: [
|
||||||
final controller = VariableDeclaration('#controller',
|
emittedValueType
|
||||||
|
], named: [
|
||||||
|
NamedExpression('sync', ConstantExpression(BoolConstant(true)))
|
||||||
|
]));
|
||||||
|
|
||||||
|
// var #controller = ...
|
||||||
|
final controllerVar = VariableDeclaration('#controller',
|
||||||
initializer: controllerInitializer..fileOffset = fileOffset,
|
initializer: controllerInitializer..fileOffset = fileOffset,
|
||||||
type: controllerNullableObjectType,
|
type: controllerObjectType,
|
||||||
isSynthesized: true)
|
isSynthesized: true)
|
||||||
..fileOffset = fileOffset;
|
..fileOffset = fileOffset;
|
||||||
|
|
||||||
// Initialize `#completer`.
|
// `void #body() async { ... }` statements.
|
||||||
final completer = VariableDeclaration('#completer',
|
final List<Statement> bodyStatements = [];
|
||||||
initializer: _completerBoolInitializer()..fileOffset = fileOffset,
|
|
||||||
type: completerBoolType,
|
|
||||||
isSynthesized: true)
|
|
||||||
..fileOffset = fileOffset;
|
|
||||||
|
|
||||||
// Close `#controller`.
|
// Completer<void>? #paused;
|
||||||
Procedure controllerCloseProc =
|
final pausedVarType = InterfaceType(
|
||||||
coreTypes.index.getProcedure('dart:async', 'StreamController', 'close');
|
_completerClass, Nullability.nullable, [const VoidType()]);
|
||||||
FunctionType controllerCloseType =
|
|
||||||
Substitution.fromInterfaceType(controllerNullableObjectType)
|
|
||||||
.substituteType(controllerCloseProc.function
|
|
||||||
.computeThisFunctionType(Nullability.nonNullable))
|
|
||||||
as FunctionType;
|
|
||||||
final callControllerClose = InstanceInvocation(InstanceAccessKind.Instance,
|
|
||||||
VariableGet(controller), Name('close'), Arguments([]),
|
|
||||||
interfaceTarget: controllerCloseProc,
|
|
||||||
functionType: controllerCloseType);
|
|
||||||
|
|
||||||
// Create a frame so yield statements within the body can access the right
|
final pausedVar = VariableDeclaration('#paused',
|
||||||
// controller / completer.
|
initializer: null, type: pausedVarType, isSynthesized: true);
|
||||||
_asyncStarFrames.add(_AsyncStarFrame(controller, completer));
|
|
||||||
|
|
||||||
// Visit the body to transform any yields. We will re-visit after
|
bodyStatements.add(pausedVar);
|
||||||
// transformation just to ensure everything we've added will also be
|
|
||||||
// lowered.
|
// controller.onResume = controller.onCancel = () {
|
||||||
Statement? transformedBody =
|
// #paused?.complete(null);
|
||||||
functionNode.body?.accept<TreeNode>(this) as Statement?;
|
// #paused = null;
|
||||||
|
// };
|
||||||
|
final List<Statement> onCancelCallbackBodyStatements = [
|
||||||
|
IfStatement(
|
||||||
|
EqualsNull(VariableGet(pausedVar)),
|
||||||
|
Block([]),
|
||||||
|
Block([
|
||||||
|
ExpressionStatement(InstanceInvocation(
|
||||||
|
InstanceAccessKind.Instance,
|
||||||
|
VariableGet(pausedVar),
|
||||||
|
Name('complete'),
|
||||||
|
Arguments([ConstantExpression(NullConstant())]),
|
||||||
|
interfaceTarget: _completerComplete,
|
||||||
|
functionType: substitute(_completerComplete.getterType, {
|
||||||
|
_completerClass.typeParameters.first: const VoidType()
|
||||||
|
}) as FunctionType,
|
||||||
|
)),
|
||||||
|
ExpressionStatement(VariableSet(
|
||||||
|
pausedVar,
|
||||||
|
ConstantExpression(NullConstant()),
|
||||||
|
))
|
||||||
|
])),
|
||||||
|
];
|
||||||
|
|
||||||
|
final onCancelCallback = FunctionExpression(FunctionNode(
|
||||||
|
Block(onCancelCallbackBodyStatements),
|
||||||
|
typeParameters: [],
|
||||||
|
positionalParameters: [],
|
||||||
|
namedParameters: [],
|
||||||
|
requiredParameterCount: 0,
|
||||||
|
returnType: const VoidType(),
|
||||||
|
));
|
||||||
|
|
||||||
|
final onCancelCallbackVar =
|
||||||
|
VariableDeclaration("#onCancelCallback", initializer: onCancelCallback);
|
||||||
|
|
||||||
|
bodyStatements.add(onCancelCallbackVar);
|
||||||
|
|
||||||
|
bodyStatements.add(ExpressionStatement(InstanceSet(
|
||||||
|
InstanceAccessKind.Instance,
|
||||||
|
VariableGet(controllerVar),
|
||||||
|
Name('onResume'),
|
||||||
|
VariableGet(onCancelCallbackVar),
|
||||||
|
interfaceTarget: _streamControllerSetOnResume)));
|
||||||
|
|
||||||
|
bodyStatements.add(ExpressionStatement(InstanceSet(
|
||||||
|
InstanceAccessKind.Instance,
|
||||||
|
VariableGet(controllerVar),
|
||||||
|
Name('onCancel'),
|
||||||
|
VariableGet(onCancelCallbackVar),
|
||||||
|
interfaceTarget: _streamControllerSetOnCancel)));
|
||||||
|
|
||||||
|
_asyncStarFrames
|
||||||
|
.add(_AsyncStarFrame(controllerVar, pausedVar, emittedValueType));
|
||||||
|
final Statement transformedBody =
|
||||||
|
functionNode.body!.accept<TreeNode>(this) as Statement;
|
||||||
_asyncStarFrames.removeLast();
|
_asyncStarFrames.removeLast();
|
||||||
|
|
||||||
// Try-catch-finally around the body to call `controller.addError` and
|
// The body will be wrapped with a `try-catch` to pass the error to the
|
||||||
// `controller.close`.
|
// controller, and `try-finally` to close the controller.
|
||||||
final exceptionVar = VariableDeclaration(null, isSynthesized: true);
|
final exceptionVar = VariableDeclaration(null, isSynthesized: true);
|
||||||
|
|
||||||
final stackTraceVar = VariableDeclaration(null,
|
final stackTraceVar = VariableDeclaration(null,
|
||||||
isSynthesized: true,
|
isSynthesized: true,
|
||||||
type: coreTypes.stackTraceRawType(Nullability.nonNullable));
|
type: coreTypes.stackTraceRawType(Nullability.nonNullable));
|
||||||
final Procedure controllerAddErrorProc = coreTypes.index
|
|
||||||
.getProcedure('dart:async', 'StreamController', 'addError');
|
|
||||||
final FunctionType controllerAddErrorType =
|
|
||||||
Substitution.fromInterfaceType(controllerNullableObjectType)
|
|
||||||
.substituteType(controllerAddErrorProc.function
|
|
||||||
.computeThisFunctionType(Nullability.nonNullable))
|
|
||||||
as FunctionType;
|
|
||||||
final tryCatch = TryCatch(
|
|
||||||
Block([
|
|
||||||
ExpressionStatement(_awaitCompleterFuture(completer, fileOffset)),
|
|
||||||
if (transformedBody != null) transformedBody,
|
|
||||||
]),
|
|
||||||
[
|
|
||||||
Catch(
|
|
||||||
exceptionVar,
|
|
||||||
stackTrace: stackTraceVar,
|
|
||||||
ExpressionStatement(InstanceInvocation(
|
|
||||||
InstanceAccessKind.Instance,
|
|
||||||
VariableGet(controller),
|
|
||||||
Name('addError'),
|
|
||||||
Arguments([VariableGet(exceptionVar), VariableGet(stackTraceVar)]),
|
|
||||||
interfaceTarget: controllerAddErrorProc,
|
|
||||||
functionType: controllerAddErrorType,
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
final tryFinally =
|
|
||||||
TryFinally(tryCatch, ExpressionStatement(callControllerClose));
|
|
||||||
|
|
||||||
// Locally declare body function.
|
final catch_ = Catch(
|
||||||
final bodyFunction = FunctionNode(
|
exceptionVar,
|
||||||
Block([
|
stackTrace: stackTraceVar,
|
||||||
completer,
|
ExpressionStatement(InstanceInvocation(
|
||||||
ExpressionStatement(
|
InstanceAccessKind.Instance,
|
||||||
_addCompleterToController(controller, completer, fileOffset)),
|
VariableGet(controllerVar),
|
||||||
tryFinally,
|
Name("addError"),
|
||||||
]),
|
Arguments([VariableGet(exceptionVar), VariableGet(stackTraceVar)]),
|
||||||
|
interfaceTarget: _streamControllerAddError,
|
||||||
|
functionType: _streamControllerAddError.getterType as FunctionType,
|
||||||
|
)));
|
||||||
|
|
||||||
|
final finalizer = ExpressionStatement(InstanceInvocation(
|
||||||
|
InstanceAccessKind.Instance,
|
||||||
|
VariableGet(controllerVar),
|
||||||
|
Name("close"),
|
||||||
|
Arguments([]),
|
||||||
|
interfaceTarget: _streamControllerClose,
|
||||||
|
functionType: _streamControllerClose.getterType as FunctionType,
|
||||||
|
));
|
||||||
|
|
||||||
|
bodyStatements
|
||||||
|
.add(TryFinally(TryCatch(transformedBody, [catch_]), finalizer));
|
||||||
|
|
||||||
|
final bodyFunction = FunctionNode(Block(bodyStatements),
|
||||||
emittedValueType: const VoidType(),
|
emittedValueType: const VoidType(),
|
||||||
returnType: InterfaceType(
|
returnType: InterfaceType(
|
||||||
coreTypes.futureClass, Nullability.nonNullable, [const VoidType()]),
|
coreTypes.futureClass, Nullability.nonNullable, [const VoidType()]),
|
||||||
asyncMarker: AsyncMarker.Async,
|
asyncMarker: AsyncMarker.Async,
|
||||||
dartAsyncMarker: AsyncMarker.Async);
|
dartAsyncMarker: AsyncMarker.Async);
|
||||||
|
|
||||||
final bodyInitializer = FunctionExpression(bodyFunction);
|
final bodyInitializer = FunctionExpression(bodyFunction);
|
||||||
FunctionType bodyFunctionType =
|
|
||||||
|
final bodyFunctionType =
|
||||||
bodyFunction.computeThisFunctionType(Nullability.nonNullable);
|
bodyFunction.computeThisFunctionType(Nullability.nonNullable);
|
||||||
final body = VariableDeclaration('#body',
|
|
||||||
|
final bodyVar = VariableDeclaration('#body',
|
||||||
initializer: bodyInitializer..fileOffset = fileOffset,
|
initializer: bodyInitializer..fileOffset = fileOffset,
|
||||||
type: bodyFunctionType,
|
type: bodyFunctionType,
|
||||||
isSynthesized: true)
|
isSynthesized: true)
|
||||||
..fileOffset = fileOffset;
|
..fileOffset = fileOffset;
|
||||||
|
|
||||||
// Invoke body.
|
// controller.onListen = () {
|
||||||
final invokeBody = FunctionInvocation(
|
// scheduleMicrotask(_body);
|
||||||
FunctionAccessKind.FunctionType, VariableGet(body), Arguments([]),
|
// };
|
||||||
functionType: bodyFunctionType);
|
final scheduleMicrotaskProcedure =
|
||||||
|
coreTypes.index.getTopLevelProcedure('dart:async', 'scheduleMicrotask');
|
||||||
|
|
||||||
// Create a 'counting' sentinel to let us know which values to filter.
|
final setControllerOnListen = InstanceSet(
|
||||||
final isEven = VariableDeclaration('#isEven',
|
|
||||||
initializer: ConstantExpression(BoolConstant(false))
|
|
||||||
..fileOffset = fileOffset,
|
|
||||||
type: coreTypes.boolNonNullableRawType,
|
|
||||||
isSynthesized: true)
|
|
||||||
..fileOffset = fileOffset;
|
|
||||||
final isFirst = VariableDeclaration('#isFirst',
|
|
||||||
initializer: ConstantExpression(BoolConstant(true))
|
|
||||||
..fileOffset = fileOffset,
|
|
||||||
type: coreTypes.boolNonNullableRawType,
|
|
||||||
isSynthesized: true)
|
|
||||||
..fileOffset = fileOffset;
|
|
||||||
|
|
||||||
// Get `controller.stream`
|
|
||||||
Procedure controllerStream = coreTypes.index
|
|
||||||
.getProcedure('dart:async', 'StreamController', 'get:stream');
|
|
||||||
DartType controllerStreamType =
|
|
||||||
Substitution.fromInterfaceType(controllerNullableObjectType)
|
|
||||||
.substituteType(controllerStream.function.returnType);
|
|
||||||
final getControllerStream = InstanceGet(
|
|
||||||
InstanceAccessKind.Instance, VariableGet(controller), Name('stream'),
|
|
||||||
interfaceTarget: controllerStream, resultType: controllerStreamType);
|
|
||||||
|
|
||||||
// Prepare `completerPrePass` to issue a round of completions to our hidden
|
|
||||||
// completers.
|
|
||||||
Procedure completerComplete =
|
|
||||||
coreTypes.index.getProcedure('dart:async', 'Completer', 'complete');
|
|
||||||
FunctionType completerCompleteType =
|
|
||||||
Substitution.fromInterfaceType(completerBoolType).substituteType(
|
|
||||||
completerComplete.function
|
|
||||||
.computeThisFunctionType(Nullability.nonNullable))
|
|
||||||
as FunctionType;
|
|
||||||
final completerPrePassArg = VariableDeclaration('value',
|
|
||||||
type: coreTypes.objectNullableRawType, isSynthesized: true);
|
|
||||||
final completerPrePass = FunctionExpression(FunctionNode(
|
|
||||||
Block([
|
|
||||||
IfStatement(
|
|
||||||
VariableGet(isFirst),
|
|
||||||
Block([
|
|
||||||
ExpressionStatement(invokeBody),
|
|
||||||
ReturnStatement(ConstantExpression(NullConstant())),
|
|
||||||
]),
|
|
||||||
null),
|
|
||||||
IfStatement(
|
|
||||||
Not(VariableGet(isEven)),
|
|
||||||
ExpressionStatement(InstanceInvocation(
|
|
||||||
InstanceAccessKind.Instance,
|
|
||||||
VariableGet(completerPrePassArg),
|
|
||||||
Name('complete'),
|
|
||||||
Arguments([ConstantExpression(BoolConstant(true))]),
|
|
||||||
interfaceTarget: completerComplete,
|
|
||||||
functionType: completerCompleteType)),
|
|
||||||
null),
|
|
||||||
ReturnStatement(VariableGet(completerPrePassArg)),
|
|
||||||
]),
|
|
||||||
positionalParameters: [completerPrePassArg],
|
|
||||||
returnType: FutureOrType(
|
|
||||||
coreTypes.objectNullableRawType, Nullability.nonNullable),
|
|
||||||
asyncMarker: AsyncMarker.Async,
|
|
||||||
dartAsyncMarker: AsyncMarker.Async,
|
|
||||||
emittedValueType: coreTypes.objectNullableRawType,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Call `asyncMap`.
|
|
||||||
Procedure asyncMap =
|
|
||||||
coreTypes.index.getProcedure('dart:async', 'Stream', 'asyncMap');
|
|
||||||
final streamType = InterfaceType(coreTypes.streamClass,
|
|
||||||
Nullability.nonNullable, [coreTypes.objectNullableRawType]);
|
|
||||||
final asyncMapType = FunctionType([
|
|
||||||
FunctionType([
|
|
||||||
coreTypes.objectNullableRawType
|
|
||||||
], FutureOrType(coreTypes.objectNullableRawType, Nullability.nonNullable),
|
|
||||||
Nullability.nonNullable, requiredParameterCount: 1)
|
|
||||||
], streamType, Nullability.nonNullable, requiredParameterCount: 1);
|
|
||||||
final callAsyncMap = InstanceInvocation(
|
|
||||||
InstanceAccessKind.Instance,
|
InstanceAccessKind.Instance,
|
||||||
getControllerStream,
|
VariableGet(controllerVar),
|
||||||
Name('asyncMap'),
|
Name('onListen'),
|
||||||
Arguments([completerPrePass], types: [coreTypes.objectNullableRawType]),
|
FunctionExpression(FunctionNode(ExpressionStatement(StaticInvocation(
|
||||||
interfaceTarget: asyncMap,
|
scheduleMicrotaskProcedure, Arguments([VariableGet(bodyVar)]))))),
|
||||||
functionType: asyncMapType);
|
interfaceTarget: _streamControllerSetOnListen);
|
||||||
|
|
||||||
// Call `where`.
|
|
||||||
final whereFilterArg = VariableDeclaration('value',
|
|
||||||
type: coreTypes.objectNullableRawType, isSynthesized: true);
|
|
||||||
final whereKeep = VariableDeclaration('keep',
|
|
||||||
initializer: VariableGet(isEven),
|
|
||||||
type: coreTypes.boolNonNullableRawType,
|
|
||||||
isSynthesized: true);
|
|
||||||
|
|
||||||
final whereFilter = FunctionExpression(FunctionNode(
|
|
||||||
Block([
|
|
||||||
IfStatement(
|
|
||||||
VariableGet(isFirst),
|
|
||||||
Block([
|
|
||||||
ExpressionStatement(VariableSet(
|
|
||||||
isFirst, ConstantExpression(BoolConstant(false)))),
|
|
||||||
ReturnStatement(ConstantExpression(BoolConstant(false)))
|
|
||||||
]),
|
|
||||||
null),
|
|
||||||
whereKeep,
|
|
||||||
ExpressionStatement(VariableSet(isEven, Not(VariableGet(isEven)))),
|
|
||||||
ReturnStatement(VariableGet(whereKeep)),
|
|
||||||
]),
|
|
||||||
positionalParameters: [whereFilterArg],
|
|
||||||
returnType: coreTypes.boolNonNullableRawType));
|
|
||||||
|
|
||||||
Procedure whereProc =
|
|
||||||
coreTypes.index.getProcedure('dart:async', 'Stream', 'where');
|
|
||||||
FunctionType whereProcType = Substitution.fromInterfaceType(streamType)
|
|
||||||
.substituteType(whereProc.function
|
|
||||||
.computeThisFunctionType(Nullability.nonNullable)) as FunctionType;
|
|
||||||
final callWhere = InstanceInvocation(InstanceAccessKind.Instance,
|
|
||||||
callAsyncMap, Name('where'), Arguments([whereFilter]),
|
|
||||||
interfaceTarget: whereProc, functionType: whereProcType);
|
|
||||||
|
|
||||||
// Finally call cast.
|
|
||||||
|
|
||||||
final DartType streamTypeArgument = functionNode.emittedValueType!;
|
|
||||||
Procedure castProc =
|
|
||||||
coreTypes.index.getProcedure('dart:async', 'Stream', 'cast');
|
|
||||||
final returnStreamType = InterfaceType(coreTypes.streamClass,
|
|
||||||
streamTypeArgument.nullability, [streamTypeArgument]);
|
|
||||||
final castProcType = FunctionType(
|
|
||||||
[], returnStreamType, Nullability.nonNullable,
|
|
||||||
requiredParameterCount: 1);
|
|
||||||
final castToExpectedType = InstanceInvocation(InstanceAccessKind.Instance,
|
|
||||||
callWhere, Name('cast'), Arguments([], types: [streamTypeArgument]),
|
|
||||||
interfaceTarget: castProc, functionType: castProcType);
|
|
||||||
return FunctionNode(
|
return FunctionNode(
|
||||||
Block([
|
Block([
|
||||||
controller,
|
// var controller = StreamController<T>(sync: true);
|
||||||
body,
|
controllerVar,
|
||||||
isFirst,
|
|
||||||
isEven,
|
// var #body = ...;
|
||||||
ExpressionStatement(_addToController(
|
bodyVar,
|
||||||
controller, ConstantExpression(NullConstant()), fileOffset)),
|
|
||||||
ReturnStatement(castToExpectedType),
|
// controller.onListen = ...;
|
||||||
|
ExpressionStatement(setControllerOnListen),
|
||||||
|
|
||||||
|
// return controller.stream;
|
||||||
|
ReturnStatement(InstanceGet(
|
||||||
|
InstanceAccessKind.Instance,
|
||||||
|
VariableGet(controllerVar),
|
||||||
|
Name("stream"),
|
||||||
|
interfaceTarget: _streamControllerGetStream,
|
||||||
|
resultType: substitute(_streamControllerGetStream.getterType, {
|
||||||
|
_streamControllerClass.typeParameters.first: emittedValueType,
|
||||||
|
}),
|
||||||
|
))
|
||||||
]),
|
]),
|
||||||
typeParameters: functionNode.typeParameters,
|
typeParameters: functionNode.typeParameters,
|
||||||
positionalParameters: functionNode.positionalParameters,
|
positionalParameters: functionNode.positionalParameters,
|
||||||
|
@ -642,48 +589,92 @@ class _WasmTransformer extends Transformer {
|
||||||
if (!_enclosingIsAsyncStar) {
|
if (!_enclosingIsAsyncStar) {
|
||||||
return super.visitYieldStatement(yield);
|
return super.visitYieldStatement(yield);
|
||||||
}
|
}
|
||||||
int fileOffset = yield.fileOffset;
|
|
||||||
_AsyncStarFrame frame = _asyncStarFrames.last;
|
|
||||||
VariableDeclaration controller = frame.controller;
|
|
||||||
VariableDeclaration completer = frame.completer;
|
|
||||||
bool isYieldStar = yield.isYieldStar;
|
|
||||||
|
|
||||||
// If [isYieldStar] then we need to create an `await for` loop to wrap the
|
final fileOffset = yield.fileOffset;
|
||||||
// yields.
|
final frame = _asyncStarFrames.last;
|
||||||
DartType yieldExpressionType = yield.expression.getStaticType(typeContext);
|
final controllerVar = frame.controllerVar;
|
||||||
VariableDeclaration? awaitForVar;
|
final pausedVar = frame.pausedVar;
|
||||||
if (isYieldStar) {
|
final isYieldStar = yield.isYieldStar;
|
||||||
DartType awaitVarType = const DynamicType();
|
|
||||||
if (yieldExpressionType is InterfaceType) {
|
final transformedExpression = yield.expression.accept(this) as Expression;
|
||||||
Class cls = yieldExpressionType.classReference.asClass;
|
|
||||||
if (cls == coreTypes.streamClass) {
|
final List<Statement> statements = [];
|
||||||
awaitVarType = yieldExpressionType.typeArguments.single;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
awaitForVar = VariableDeclaration('#awaitForVar',
|
|
||||||
type: awaitVarType, isSynthesized: true)
|
|
||||||
..fileOffset = fileOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
final yieldBody = Block([
|
|
||||||
ExpressionStatement(_addToController(
|
|
||||||
controller,
|
|
||||||
isYieldStar ? VariableGet(awaitForVar!) : yield.expression,
|
|
||||||
fileOffset)),
|
|
||||||
ExpressionStatement(VariableSet(completer, _completerBoolInitializer())),
|
|
||||||
ExpressionStatement(
|
|
||||||
_addCompleterToController(controller, completer, fileOffset)),
|
|
||||||
ExpressionStatement(_awaitCompleterFuture(completer, fileOffset)),
|
|
||||||
]);
|
|
||||||
if (isYieldStar) {
|
if (isYieldStar) {
|
||||||
// If this is a yield* then wrap the yield in an `await for`.
|
// yield* e
|
||||||
ForInStatement awaitForIn = ForInStatement(
|
//
|
||||||
awaitForVar!, yield.expression, yieldBody,
|
// ==>
|
||||||
isAsync: true);
|
//
|
||||||
return awaitForIn.accept<TreeNode>(this);
|
// await #controller.addStream(e);
|
||||||
|
// if (!#controller.hasListener) return;
|
||||||
|
|
||||||
|
final controllerAddStreamProcedureType =
|
||||||
|
_streamControllerAddStream.getterType as FunctionType;
|
||||||
|
|
||||||
|
statements.add(ExpressionStatement(AwaitExpression(InstanceInvocation(
|
||||||
|
InstanceAccessKind.Instance,
|
||||||
|
VariableGet(controllerVar),
|
||||||
|
Name('addStream'),
|
||||||
|
Arguments([transformedExpression]),
|
||||||
|
interfaceTarget: _streamControllerAddStream,
|
||||||
|
functionType: substitute(controllerAddStreamProcedureType, {
|
||||||
|
_streamControllerClass.typeParameters.first: frame.emittedValueType,
|
||||||
|
}) as FunctionType,
|
||||||
|
))));
|
||||||
|
|
||||||
|
statements.add(IfStatement(
|
||||||
|
InstanceGet(InstanceAccessKind.Instance, VariableGet(controllerVar),
|
||||||
|
Name('hasListener'),
|
||||||
|
interfaceTarget: _streamControllerGetHasListener,
|
||||||
|
resultType: coreTypes.boolNonNullableRawType),
|
||||||
|
Block([]),
|
||||||
|
ReturnStatement()));
|
||||||
} else {
|
} else {
|
||||||
return yieldBody.accept<TreeNode>(this);
|
// yield e
|
||||||
|
//
|
||||||
|
// ==>
|
||||||
|
//
|
||||||
|
// #controller.add(e);
|
||||||
|
// if (#controller.isPaused) {
|
||||||
|
// await (#paused = Completer()).future;
|
||||||
|
// }
|
||||||
|
// if (!#controller.hasListener) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
statements.add(ExpressionStatement(
|
||||||
|
_addToController(controllerVar, yield.expression, fileOffset)));
|
||||||
|
|
||||||
|
// if (controller.isPaused) ...
|
||||||
|
statements.add(IfStatement(
|
||||||
|
InstanceGet(InstanceAccessKind.Instance, VariableGet(controllerVar),
|
||||||
|
Name('isPaused'),
|
||||||
|
interfaceTarget: _streamControllerGetIsPaused,
|
||||||
|
resultType: coreTypes.boolNonNullableRawType),
|
||||||
|
ExpressionStatement(AwaitExpression(InstanceGet(
|
||||||
|
InstanceAccessKind.Instance,
|
||||||
|
VariableSet(
|
||||||
|
pausedVar,
|
||||||
|
StaticInvocation(_completerConstructor,
|
||||||
|
Arguments([], types: [const VoidType()]))),
|
||||||
|
Name('future'),
|
||||||
|
interfaceTarget: _completerGetFuture,
|
||||||
|
resultType: substitute(_completerGetFuture.getterType,
|
||||||
|
{_completerClass.typeParameters.first: const VoidType()})))),
|
||||||
|
null));
|
||||||
|
|
||||||
|
// if (!controller.hasListener) return;
|
||||||
|
statements.add(IfStatement(
|
||||||
|
InstanceGet(InstanceAccessKind.Instance, VariableGet(controllerVar),
|
||||||
|
Name('hasListener'),
|
||||||
|
interfaceTarget: _streamControllerGetHasListener,
|
||||||
|
resultType: coreTypes.boolNonNullableRawType),
|
||||||
|
Block([]),
|
||||||
|
ReturnStatement(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Block(statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -715,8 +706,9 @@ class _WasmTransformer extends Transformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AsyncStarFrame {
|
class _AsyncStarFrame {
|
||||||
final VariableDeclaration controller;
|
final VariableDeclaration controllerVar;
|
||||||
final VariableDeclaration completer;
|
final VariableDeclaration pausedVar;
|
||||||
|
final DartType emittedValueType;
|
||||||
|
|
||||||
_AsyncStarFrame(this.controller, this.completer);
|
_AsyncStarFrame(this.controllerVar, this.pausedVar, this.emittedValueType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,81 +9,63 @@ static method method(core::Iterable<core::int> iterable) → core::Iterable<core
|
||||||
yield* iterable;
|
yield* iterable;
|
||||||
}
|
}
|
||||||
static method asyncMethod(asy::Stream<core::int> stream) → asy::Stream<core::int> {
|
static method asyncMethod(asy::Stream<core::int> stream) → asy::Stream<core::int> {
|
||||||
synthesized asy::StreamController<core::Object?> #controller = asy::StreamController::•<core::Object?>();
|
synthesized asy::StreamController<core::int> #controller = asy::StreamController::•<core::int>(sync: #C1);
|
||||||
synthesized () → asy::Future<void> #body = () → asy::Future<void> async /* emittedValueType= void */ {
|
synthesized () → asy::Future<void> #body = () → asy::Future<void> async /* emittedValueType= void */ {
|
||||||
core::bool :async_temporary_0;
|
void :async_temporary_0;
|
||||||
core::bool :async_temporary_1;
|
void :async_temporary_1;
|
||||||
core::bool :async_temporary_2;
|
dynamic :async_temporary_2;
|
||||||
core::bool :async_temporary_3;
|
synthesized asy::Completer<void>? #paused;
|
||||||
core::bool :async_temporary_4;
|
dynamic #onCancelCallback = () → void {
|
||||||
dynamic :async_temporary_5;
|
if(#paused == null) {
|
||||||
synthesized asy::Completer<core::bool> #completer = asy::Completer::•<core::bool>();
|
}
|
||||||
#controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
|
else {
|
||||||
|
#paused.{asy::Completer::complete}(#C2){([FutureOr<void>?]) → void};
|
||||||
|
#paused = #C2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#controller.{asy::StreamController::onResume} = #onCancelCallback;
|
||||||
|
#controller.{asy::StreamController::onCancel} = #onCancelCallback;
|
||||||
{
|
{
|
||||||
core::int #t1 = 0;
|
core::int #t1 = 0;
|
||||||
core::Object #t2;
|
core::Object #t2;
|
||||||
core::StackTrace #t3;
|
core::StackTrace #t3;
|
||||||
try
|
try
|
||||||
try {
|
try {
|
||||||
:async_temporary_0 = await #completer.{asy::Completer::future}{asy::Future<core::bool>};
|
|
||||||
:async_temporary_0 as{ForLegacy} dynamic;
|
|
||||||
{
|
{
|
||||||
{
|
#controller.{asy::StreamController::add}(1){(core::Object?) → void};
|
||||||
#controller.{asy::StreamController::add}(1){(core::Object?) → void};
|
if(#controller.{asy::StreamController::isPaused}{core::bool}) {
|
||||||
#completer = asy::Completer::•<core::bool>();
|
:async_temporary_0 = await(#paused = asy::Completer::•<void>()).{asy::Completer::future}{asy::Future<void>};
|
||||||
#controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
|
:async_temporary_0 as{ForLegacy} dynamic;
|
||||||
:async_temporary_1 = await #completer.{asy::Completer::future}{asy::Future<core::bool>};
|
}
|
||||||
|
if(#controller.{asy::StreamController::hasListener}{core::bool}) {
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
#controller.{asy::StreamController::add}(2){(core::Object?) → void};
|
||||||
|
if(#controller.{asy::StreamController::isPaused}{core::bool}) {
|
||||||
|
:async_temporary_1 = await(#paused = asy::Completer::•<void>()).{asy::Completer::future}{asy::Future<void>};
|
||||||
:async_temporary_1 as{ForLegacy} dynamic;
|
:async_temporary_1 as{ForLegacy} dynamic;
|
||||||
}
|
}
|
||||||
{
|
if(#controller.{asy::StreamController::hasListener}{core::bool}) {
|
||||||
#controller.{asy::StreamController::add}(2){(core::Object?) → void};
|
|
||||||
#completer = asy::Completer::•<core::bool>();
|
|
||||||
#controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
|
|
||||||
:async_temporary_2 = await #completer.{asy::Completer::future}{asy::Future<core::bool>};
|
|
||||||
:async_temporary_2 as{ForLegacy} dynamic;
|
|
||||||
}
|
}
|
||||||
{
|
else
|
||||||
synthesized asy::_StreamIterator<core::int> #forIterator = new asy::_StreamIterator::•<core::int>(stream);
|
return;
|
||||||
synthesized core::bool #jumpSentinel = #C1;
|
}
|
||||||
{
|
{
|
||||||
core::int #t4 = 0;
|
:async_temporary_2 = await #controller.{asy::StreamController::addStream}(stream){(asy::Stream<core::int>, {cancelOnError: core::bool?}) → asy::Future<dynamic>};
|
||||||
core::Object #t5;
|
:async_temporary_2;
|
||||||
core::StackTrace #t6;
|
if(#controller.{asy::StreamController::hasListener}{core::bool}) {
|
||||||
try {
|
|
||||||
#L1:
|
|
||||||
for (; ; ) {
|
|
||||||
:async_temporary_4 = await #forIterator.{asy::_StreamIterator::moveNext}(){() → asy::Future<core::bool>};
|
|
||||||
if(#jumpSentinel = :async_temporary_4 as{ForLegacy} dynamic) {
|
|
||||||
synthesized core::int #awaitForVar = #forIterator.{asy::_StreamIterator::current}{core::int};
|
|
||||||
{
|
|
||||||
#controller.{asy::StreamController::add}(#awaitForVar){(core::Object?) → void};
|
|
||||||
#completer = asy::Completer::•<core::bool>();
|
|
||||||
#controller.{asy::StreamController::add}(#completer){(core::Object?) → void};
|
|
||||||
:async_temporary_3 = await #completer.{asy::Completer::future}{asy::Future<core::bool>};
|
|
||||||
:async_temporary_3 as{ForLegacy} dynamic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break #L1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if(#jumpSentinel) {
|
|
||||||
:async_temporary_5 = await #forIterator.{asy::_StreamIterator::cancel}(){() → asy::Future<dynamic>};
|
|
||||||
:async_temporary_5;
|
|
||||||
}
|
|
||||||
#t4;
|
|
||||||
#t5;
|
|
||||||
#t6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
on dynamic catch(dynamic #t7, core::StackTrace #t8) {
|
on dynamic catch(dynamic #t4, core::StackTrace #t5) {
|
||||||
#controller.{asy::StreamController::addError}(#t7, #t8){(core::Object, [core::StackTrace?]) → void};
|
#controller.{asy::StreamController::addError}(#t4, #t5){(core::Object, [core::StackTrace?]) → void};
|
||||||
#t7;
|
#t4;
|
||||||
#t8;
|
#t5;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
#controller.{asy::StreamController::close}(){() → asy::Future<dynamic>};
|
#controller.{asy::StreamController::close}(){() → asy::Future<dynamic>};
|
||||||
|
@ -93,30 +75,13 @@ static method asyncMethod(asy::Stream<core::int> stream) → asy::Stream<core::i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
synthesized core::bool #isFirst = #C2;
|
#controller.{asy::StreamController::onListen} = () → dynamic
|
||||||
synthesized core::bool #isEven = #C1;
|
asy::scheduleMicrotask(#body);
|
||||||
#controller.{asy::StreamController::add}(#C3){(core::Object?) → void};
|
;
|
||||||
return #controller.{asy::StreamController::stream}{asy::Stream<core::Object?>}.{asy::Stream::asyncMap}<core::Object?>((synthesized core::Object? value) → FutureOr<core::Object?> async /* emittedValueType= core::Object? */ {
|
return #controller.{asy::StreamController::stream}{asy::Stream<core::int>};
|
||||||
if(#isFirst) {
|
|
||||||
#body(){() → asy::Future<void>};
|
|
||||||
return #C3;
|
|
||||||
}
|
|
||||||
if(!#isEven)
|
|
||||||
value.{asy::Completer::complete}(#C2){([FutureOr<core::bool>?]) → void};
|
|
||||||
return value;
|
|
||||||
}){((core::Object?) → FutureOr<core::Object?>) → asy::Stream<core::Object?>}.{asy::Stream::where}((synthesized core::Object? value) → core::bool {
|
|
||||||
if(#isFirst) {
|
|
||||||
#isFirst = #C1;
|
|
||||||
return #C1;
|
|
||||||
}
|
|
||||||
synthesized core::bool keep = #isEven;
|
|
||||||
#isEven = !#isEven;
|
|
||||||
return keep;
|
|
||||||
}){((core::Object?) → core::bool) → asy::Stream<core::Object?>}.{asy::Stream::cast}<core::int>(){() → asy::Stream<core::int>};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constants {
|
constants {
|
||||||
#C1 = false
|
#C1 = true
|
||||||
#C2 = true
|
#C2 = null
|
||||||
#C3 = null
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,3 @@ LibTest/mirrors/*: SkipByDesign # dart:mirrors is not supported.
|
||||||
|
|
||||||
[ $compiler == dart2wasm && $runtime == chrome ]
|
[ $compiler == dart2wasm && $runtime == chrome ]
|
||||||
Language/Expressions/Function_Invocation/async_generator_invokation_t10: SkipSlow # Issue(http://dartbug.com/55025)
|
Language/Expressions/Function_Invocation/async_generator_invokation_t10: SkipSlow # Issue(http://dartbug.com/55025)
|
||||||
Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t03: SkipSlow # Issue(http://dartbug.com/55025)
|
|
||||||
Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t07: SkipSlow # Issue(http://dartbug.com/55025)
|
|
||||||
Language/Statements/Yield_and_Yield_Each/Yield_Each/execution_async_A03_t11: SkipSlow # Issue(http://dartbug.com/55025)
|
|
||||||
|
|
|
@ -8,9 +8,5 @@ inference_update_2/why_not_promoted_external_error_test: SkipByDesign # Non-JS-i
|
||||||
number/web_int_literals_test: SkipByDesign # WASM has real integers.
|
number/web_int_literals_test: SkipByDesign # WASM has real integers.
|
||||||
vm/*: SkipByDesign # Tests for the VM.
|
vm/*: SkipByDesign # Tests for the VM.
|
||||||
|
|
||||||
[ $compiler == dart2wasm && $runtime == chrome ]
|
|
||||||
async_star/yield_test: SkipSlow # Issue(http://dartbug.com/55025)
|
|
||||||
async_star/yieldstar_test: SkipSlow # Issue(http://dartbug.com/55025)
|
|
||||||
|
|
||||||
[ $compiler == dart2wasm && $runtime == d8 ]
|
[ $compiler == dart2wasm && $runtime == d8 ]
|
||||||
import/conditional_string_test: SkipByDesign # No XHR in d8
|
import/conditional_string_test: SkipByDesign # No XHR in d8
|
||||||
|
|
Loading…
Reference in a new issue