Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Unified Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2610903004: Implement async/await/yield and async for-in (Closed)
Patch Set: dartfmt Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/graph_builder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/ssa/builder_kernel.dart
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 2143a52da0beb781bbdfed381011121a42333100..262459068b13a735965342b9466a82863657c34f 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -565,6 +565,26 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
}
}
+ /// Returns true if the [type] is a valid return type for an asynchronous
+ /// function.
+ ///
+ /// Asynchronous functions return a `Future`, and a valid return is thus
+ /// either dynamic, Object, or Future.
+ ///
+ /// We do not accept the internal Future implementation class.
+ bool isValidAsyncReturnType(ir.DartType type) {
+ // TODO(sigurdm): In an internal library a function could be declared:
+ //
+ // _FutureImpl foo async => 1;
+ //
+ // This should be valid (because the actual value returned from an async
+ // function is a `_FutureImpl`), but currently false is returned in this
+ // case.
+ return type is ir.DynamicType ||
+ type == astAdapter.objectClass.thisType ||
+ (type is ir.InterfaceType && type == astAdapter.futureClass.thisType);
+ }
+
@override
void visitReturnStatement(ir.ReturnStatement returnStatement) {
HInstruction value;
@@ -573,8 +593,22 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
} else {
assert(_targetFunction != null && _targetFunction is ir.FunctionNode);
returnStatement.expression.accept(this);
- value = typeBuilder.potentiallyCheckOrTrustType(
- pop(), astAdapter.getFunctionReturnType(_targetFunction));
+ value = pop();
+ if (_targetFunction.asyncMarker == ir.AsyncMarker.Async) {
+ var returnType = astAdapter.getDartType(_targetFunction.returnType);
+ if (compiler.options.enableTypeAssertions &&
+ !isValidAsyncReturnType(_targetFunction.returnType)) {
+ generateTypeError(
+ returnStatement,
+ "Async function returned a Future,"
+ " was declared to return a ${_targetFunction.returnType}.");
+ pop();
+ return;
+ }
+ } else {
+ value = typeBuilder.potentiallyCheckOrTrustType(
+ value, astAdapter.getFunctionReturnType(_targetFunction));
+ }
}
// TODO(het): Add source information
// TODO(het): Set a return value instead of closing the function when we
@@ -621,8 +655,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
@override
void visitForInStatement(ir.ForInStatement forInStatement) {
if (forInStatement.isAsync) {
- compiler.reporter.internalError(astAdapter.getNode(forInStatement),
- "Cannot compile async for-in using kernel.");
+ _buildAsyncForIn(forInStatement);
}
// If the expression being iterated over is a JS indexable type, we can
// generate an optimized version of for-in that uses indexing.
@@ -777,6 +810,57 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
forInStatement, buildInitializer, buildCondition, () {}, buildBody);
}
+ void _buildAsyncForIn(ir.ForInStatement forInStatement) {
+ // The async-for is implemented with a StreamIterator.
+ HInstruction streamIterator;
+
+ forInStatement.iterable.accept(this);
+ _pushStaticInvocation(
+ astAdapter.streamIteratorConstructor,
+ [pop(), graph.addConstantNull(closedWorld)],
+ astAdapter.streamIteratorConstructorType);
+ streamIterator = pop();
+
+ void buildInitializer() {}
+
+ HInstruction buildCondition() {
+ TypeMask mask = astAdapter.typeOfIteratorMoveNext(forInStatement);
+ _pushDynamicInvocation(forInStatement, mask, [streamIterator],
+ selector: Selectors.moveNext);
+ HInstruction future = pop();
+ push(new HAwait(future, astAdapter.makeSubtypeOfObject(closedWorld)));
+ return popBoolified();
+ }
+
+ void buildBody() {
+ TypeMask mask = astAdapter.typeOfIteratorCurrent(forInStatement);
+ _pushDynamicInvocation(forInStatement, mask, [streamIterator],
+ selector: Selectors.current);
+ localsHandler.updateLocal(
+ astAdapter.getLocal(forInStatement.variable), pop());
+ forInStatement.body.accept(this);
+ }
+
+ void buildUpdate() {}
+
+ // Creates a synthetic try/finally block in case anything async goes amiss.
+ TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this);
+ // Build fake try body:
+ loopHandler.handleLoop(forInStatement, buildInitializer, buildCondition,
+ buildUpdate, buildBody);
+
+ void finalizerFunction() {
+ _pushDynamicInvocation(forInStatement, null, [streamIterator],
+ selector: Selectors.cancel);
+ add(new HAwait(pop(), astAdapter.makeSubtypeOfObject(closedWorld)));
+ }
+
+ tryBuilder
+ ..closeTryBody()
+ ..buildFinallyBlock(finalizerFunction)
+ ..cleanUp();
+ }
+
HInstruction callSetRuntimeTypeInfo(
HInstruction typeInfo, HInstruction newObject) {
// Set the runtime type information on the object.
@@ -2235,6 +2319,19 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
}
}
+ void visitYieldStatement(ir.YieldStatement yieldStatement) {
+ yieldStatement.expression.accept(this);
+ add(new HYield(pop(), yieldStatement.isYieldStar));
+ }
+
+ @override
+ void visitAwaitExpression(ir.AwaitExpression await) {
+ await.operand.accept(this);
+ HInstruction awaited = pop();
+ // TODO(herhut): Improve this type.
+ push(new HAwait(awaited, astAdapter.makeSubtypeOfObject(closedWorld)));
+ }
+
@override
void visitRethrow(ir.Rethrow rethrowNode) {
HInstruction exception = rethrowableException;
@@ -2304,7 +2401,9 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
}
tryBuilder
- ..buildFinallyBlock(tryFinally)
+ ..buildFinallyBlock(() {
+ tryFinally.finalizer.accept(this);
+ })
..cleanUp();
}
}
@@ -2401,11 +2500,11 @@ class TryCatchFinallyBuilder {
/// Build the finally{} clause of a try/{catch}/finally statement. Note this
/// does not examine the body of the try clause, only the finally portion.
- void buildFinallyBlock(ir.TryFinally tryFinally) {
+ void buildFinallyBlock(void buildFinalizer()) {
kernelBuilder.localsHandler = new LocalsHandler.from(originalSavedLocals);
startFinallyBlock = kernelBuilder.graph.addNewBlock();
kernelBuilder.open(startFinallyBlock);
- tryFinally.finalizer.accept(kernelBuilder);
+ buildFinalizer();
if (!kernelBuilder.isAborted()) {
endFinallyBlock = kernelBuilder.close(new HGoto());
}
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/graph_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698