Support for AwaitExpression in unlinked expressions.

This code was failing when analyzing dev_compiler with the new driver.
var instanceVarArrowExpression = (f) async => await f;

The reason was that we:
1. Don't understand AwaitExpression in AbstractConstExprSerializer.
2. So, we throw StateError.
3. So, AbstractConstExprSerializer.serialize() marks isValidConst.
4. But we don't check 'isValidConst' in linker.
5. The list of operations is empty, so we don't have anything in stack.
6. So, we throw an exception in linker.

R=paulberry@google.com
BUG=

Review URL: https://codereview.chromium.org/2541603002 .
This commit is contained in:
Konstantin Shcheglov 2016-11-29 13:22:31 -08:00
parent 4cdb5534bf
commit 38635ec91e
8 changed files with 80 additions and 5 deletions

View file

@ -71,7 +71,7 @@ class AnalysisDriver {
/**
* The version of data format, should be incremented on every format change.
*/
static const int DATA_VERSION = 8;
static const int DATA_VERSION = 9;
/**
* The name of the driver, e.g. the name of the folder.

View file

@ -765,7 +765,13 @@ enum UnlinkedExprOperation : byte {
* keep it and discard the second. Otherwise, keep the second and discard the
* first.
*/
ifNull
ifNull,
/**
* Pop the top value from the stack. Treat it as a Future and await its
* completion. Then push the awaited value onto the stack.
*/
await
}
/**

View file

@ -2341,6 +2341,12 @@ enum UnlinkedExprOperation {
* first.
*/
ifNull,
/**
* Pop the top value from the stack. Treat it as a Future and await its
* completion. Then push the awaited value onto the stack.
*/
await,
}
/**

View file

@ -2228,6 +2228,9 @@ class ExprTypeComputer {
case UnlinkedExprOperation.assignToIndex:
_doAssignToIndex();
break;
case UnlinkedExprOperation.await:
_doAwait();
break;
case UnlinkedExprOperation.extractIndex:
_doExtractIndex();
break;
@ -2363,6 +2366,13 @@ class ExprTypeComputer {
}
}
void _doAwait() {
DartType type = stack.removeLast();
DartType typeArgument = type?.flattenFutures(linker.typeSystem);
typeArgument = _dynamicIfNull(typeArgument);
stack.add(typeArgument);
}
void _doConditional() {
DartType elseType = stack.removeLast();
DartType thenType = stack.removeLast();
@ -3413,10 +3423,10 @@ abstract class LibraryElementForLink<
_linkedLibrary.importDependencies.map(_getDependency).toList();
@override
bool get isDartAsync => _absoluteUri == 'dart:async';
bool get isDartAsync => _absoluteUri.toString() == 'dart:async';
@override
bool get isDartCore => _absoluteUri == 'dart:core';
bool get isDartCore => _absoluteUri.toString() == 'dart:core';
/**
* If this library is part of the build unit being linked, return the library

View file

@ -500,6 +500,10 @@ class _ConstExprBuilder {
case UnlinkedExprOperation.ifNull:
_pushBinary(TokenType.QUESTION_QUESTION);
break;
case UnlinkedExprOperation.await:
Expression expression = _pop();
_push(AstTestFactory.awaitExpression(expression));
break;
case UnlinkedExprOperation.assignToRef:
case UnlinkedExprOperation.assignToProperty:
case UnlinkedExprOperation.assignToIndex:

View file

@ -66,7 +66,7 @@ abstract class AbstractConstExprSerializer {
bool isValidConst = true;
/**
* See [UnlinkedExprBuilder.nmae].
* See [UnlinkedExprBuilder.name].
*/
String name = null;
@ -380,6 +380,10 @@ abstract class AbstractConstExprSerializer {
isValidConst = false;
_serialize(expr.expression);
operations.add(UnlinkedExprOperation.throwException);
} else if (expr is AwaitExpression) {
isValidConst = false;
_serialize(expr.expression);
operations.add(UnlinkedExprOperation.await);
} else {
throw new StateError('Unknown expression type: $expr');
}

View file

@ -3673,6 +3673,31 @@ abstract class D extends C {
checkLibrary('var v = () => 0;');
}
test_initializer_executable_with_return_type_from_closure_await_dynamic() {
checkLibrary('var v = (f) async => await f;');
}
test_initializer_executable_with_return_type_from_closure_await_future3_int() {
checkLibrary(r'''
import 'dart:async';
var v = (Future<Future<Future<int>>> f) async => await f;
''');
}
test_initializer_executable_with_return_type_from_closure_await_future_int() {
checkLibrary(r'''
import 'dart:async';
var v = (Future<int> f) async => await f;
''');
}
test_initializer_executable_with_return_type_from_closure_await_future_noArg() {
checkLibrary(r'''
import 'dart:async';
var v = (Future f) async => await f;
''');
}
test_initializer_executable_with_return_type_from_closure_field() {
checkLibrary('''
class C {

View file

@ -1843,6 +1843,26 @@ class C<T> {
operators: [UnlinkedExprOperation.pushParameter], strings: ['T']);
}
test_constExpr_functionExpression() {
if (skipNonConstInitializers) {
return;
}
UnlinkedVariable variable = serializeVariableText('''
import 'dart:async';
const v = (f) async => await f;
''');
_assertUnlinkedConst(variable.initializer.localFunctions[0].bodyExpr,
isValidConst: false,
operators: [
UnlinkedExprOperation.pushParameter,
UnlinkedExprOperation.await
],
strings: [
'f'
],
ints: []);
}
test_constExpr_functionExpression_asArgument() {
// Even though function expressions are not allowed in constant
// declarations, they might occur due to erroneous code, so make sure they