Transform functions marked as async

In a nutshell:

  foo(params) async { <body> return result; }

transforms to

  foo(params) async {
    var c = new Completer();
    var async_body = () { <body> completer.complete(result); }
    new Future(async_body);
    return c.future;
  }

BUG=
R=hausner@google.com

Review URL: https://codereview.chromium.org//362153002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@38681 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
mlippautz@google.com 2014-07-29 17:16:00 +00:00
parent 30366cf249
commit dfc33496a4
10 changed files with 429 additions and 7 deletions

View file

@ -165,6 +165,7 @@ class SequenceNode : public AstNode {
void Add(AstNode* node) { nodes_.Add(node); }
intptr_t length() const { return nodes_.length(); }
AstNode* NodeAt(intptr_t index) const { return nodes_[index]; }
void ReplaceNodeAt(intptr_t index, AstNode* value) { nodes_[index] = value; }
DECLARE_COMMON_NODE_FUNCTIONS(SequenceNode);

View file

@ -5425,6 +5425,11 @@ void Function::set_kind(RawFunction::Kind value) const {
}
void Function::set_modifier(RawFunction::AsyncModifier value) const {
set_kind_tag(ModifierBits::update(value, raw_ptr()->kind_tag_));
}
void Function::set_is_intrinsic(bool value) const {
set_kind_tag(IntrinsicBit::update(value, raw_ptr()->kind_tag_));
}
@ -5455,6 +5460,11 @@ void Function::set_is_external(bool value) const {
}
void Function::set_is_async_closure(bool value) const {
set_kind_tag(AsyncClosureBit::update(value, raw_ptr()->kind_tag_));
}
void Function::set_token_pos(intptr_t value) const {
ASSERT(value >= 0);
raw_ptr()->token_pos_ = value;
@ -5462,7 +5472,7 @@ void Function::set_token_pos(intptr_t value) const {
void Function::set_kind_tag(intptr_t value) const {
raw_ptr()->kind_tag_ = static_cast<uint16_t>(value);
raw_ptr()->kind_tag_ = static_cast<uint32_t>(value);
}
@ -6052,6 +6062,7 @@ RawFunction* Function::New(const String& name,
result.set_parameter_names(Object::empty_array());
result.set_name(name);
result.set_kind(kind);
result.set_modifier(RawFunction::kNoModifier);
result.set_is_static(is_static);
result.set_is_const(is_const);
result.set_is_abstract(is_abstract);
@ -6061,6 +6072,7 @@ RawFunction* Function::New(const String& name,
result.set_is_intrinsic(false);
result.set_is_recognized(false);
result.set_is_redirecting(false);
result.set_is_async_closure(false);
result.set_owner(owner);
result.set_token_pos(token_pos);
result.set_end_token_pos(token_pos);

View file

@ -1665,6 +1665,10 @@ class Function : public Object {
return KindBits::decode(raw_ptr()->kind_tag_);
}
RawFunction::AsyncModifier modifier() const {
return ModifierBits::decode(raw_ptr()->kind_tag_);
}
static const char* KindToCString(RawFunction::Kind kind);
bool is_static() const { return StaticBit::decode(raw_ptr()->kind_tag_); }
@ -1811,6 +1815,11 @@ class Function : public Object {
void SetIsOptimizable(bool value) const;
void SetIsNativeAutoSetupScope(bool value) const;
bool is_async_closure() const {
return AsyncClosureBit::decode(raw_ptr()->kind_tag_);
}
void set_is_async_closure(bool value) const;
bool is_native() const { return NativeBit::decode(raw_ptr()->kind_tag_); }
void set_is_native(bool value) const;
@ -1961,6 +1970,10 @@ class Function : public Object {
return kind() == RawFunction::kSignatureFunction;
}
bool IsAsyncFunction() const {
return modifier() == RawFunction::kAsync;
}
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawFunction));
}
@ -2015,6 +2028,8 @@ class Function : public Object {
static const int kCtorPhaseBody = 1 << 1;
static const int kCtorPhaseAll = (kCtorPhaseInit | kCtorPhaseBody);
void set_modifier(RawFunction::AsyncModifier value) const;
private:
void set_ic_data_array(const Array& value) const;
@ -2033,6 +2048,8 @@ class Function : public Object {
kRedirectingBit = 13,
kExternalBit = 14,
kAllowsHoistingCheckClassBit = 15,
kModifierPos = 16,
kAsyncClosureBit = 18,
};
class KindBits :
public BitField<RawFunction::Kind, kKindTagPos, kKindTagSize> {}; // NOLINT
@ -2049,6 +2066,9 @@ class Function : public Object {
class RedirectingBit : public BitField<bool, kRedirectingBit, 1> {};
class AllowsHoistingCheckClassBit :
public BitField<bool, kAllowsHoistingCheckClassBit, 1> {}; // NOLINT
class ModifierBits :
public BitField<RawFunction::AsyncModifier, kModifierPos, 2> {}; // NOLINT
class AsyncClosureBit : public BitField<bool, kAsyncClosureBit, 1> {};
void set_name(const String& value) const;
void set_kind(RawFunction::Kind value) const;

View file

@ -39,6 +39,7 @@ DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef.");
DEFINE_FLAG(bool, enable_async, false, "Enable async operations.");
DECLARE_FLAG(bool, error_on_bad_type);
DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
@ -2898,6 +2899,17 @@ SequenceNode* Parser::ParseConstructor(const Function& func,
}
// TODO(mlippautz): Once we know where these classes should come from, adjust
// how we get their definition.
RawClass* Parser::GetClassForAsync(const String& class_name) {
const Class& cls = Class::Handle(library_.LookupClass(class_name));
if (cls.IsNull()) {
ReportError("async modifier requires dart:async to be imported");
}
return cls.raw();
}
// Parser is at the opening parenthesis of the formal parameter
// declaration of the function or constructor.
// Parse the formal parameters and code.
@ -2912,6 +2924,7 @@ SequenceNode* Parser::ParseFunc(const Function& func,
intptr_t saved_try_index = last_used_try_index_;
last_used_try_index_ = 0;
intptr_t formal_params_pos = TokenPos();
// TODO(12455) : Need better validation mechanism.
if (func.IsConstructor()) {
@ -2946,12 +2959,23 @@ SequenceNode* Parser::ParseFunc(const Function& func,
&Symbols::TypeArgumentsParameter(),
&Type::ZoneHandle(I, Type::DynamicType()));
}
ASSERT((CurrentToken() == Token::kLPAREN) || func.IsGetterFunction());
ASSERT((CurrentToken() == Token::kLPAREN) ||
func.IsGetterFunction() ||
func.is_async_closure());
const bool allow_explicit_default_values = true;
if (func.IsGetterFunction()) {
// Populate function scope with the formal parameters. Since in this case
// we are compiling a getter this will at most populate the receiver.
AddFormalParamsToScope(&params, current_block_->scope);
} else if (func.is_async_closure()) {
AddFormalParamsToScope(&params, current_block_->scope);
ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved());
ASSERT(func.NumParameters() == params.parameters->length());
if (!Function::Handle(func.parent_function()).IsGetterFunction()) {
// Parse away any formal parameters, as they are accessed as as context
// variables.
ParseFormalParameterList(allow_explicit_default_values, false, &params);
}
} else {
ParseFormalParameterList(allow_explicit_default_values, false, &params);
@ -2992,7 +3016,16 @@ SequenceNode* Parser::ParseFunc(const Function& func,
}
}
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
func.set_modifier(func_modifier);
OpenBlock(); // Open a nested scope for the outermost function block.
Function& async_closure = Function::ZoneHandle(I);
if (func.IsAsyncFunction() && !func.is_async_closure()) {
async_closure = OpenAsyncFunction(formal_params_pos);
}
intptr_t end_token_pos = 0;
if (CurrentToken() == Token::kLBRACE) {
ConsumeToken();
@ -3053,6 +3086,11 @@ SequenceNode* Parser::ParseFunc(const Function& func,
func.end_token_pos() == end_token_pos);
func.set_end_token_pos(end_token_pos);
SequenceNode* body = CloseBlock();
if (func.IsAsyncFunction() && !func.is_async_closure()) {
body = CloseAsyncFunction(async_closure, body);
} else if (func.is_async_closure()) {
CloseAsyncClosure(body);
}
current_block_->statements->Add(body);
innermost_function_ = saved_innermost_function.raw();
last_used_try_index_ = saved_try_index;
@ -3366,6 +3404,15 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) {
method->name->ToCString());
}
RawFunction::AsyncModifier async_modifier = ParseFunctionModifier();
if ((method->IsFactoryOrConstructor() || method->IsSetter()) &&
async_modifier != RawFunction::kNoModifier) {
ReportError(method->name_pos,
"%s '%s' may not be async",
(method->IsSetter()) ? "setter" : "constructor",
method->name->ToCString());
}
intptr_t method_end_pos = TokenPos();
if ((CurrentToken() == Token::kLBRACE) ||
(CurrentToken() == Token::kARROW)) {
@ -3480,6 +3527,7 @@ void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) {
func.set_result_type(*method->type);
func.set_end_token_pos(method_end_pos);
func.set_is_redirecting(is_redirecting);
func.set_modifier(async_modifier);
if (method->has_native && library_.is_dart_scheme() &&
library_.IsPrivate(*method->name)) {
func.set_is_visible(false);
@ -4800,6 +4848,17 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level,
}
RawFunction::AsyncModifier Parser::ParseFunctionModifier() {
if (FLAG_enable_async) {
if (CurrentLiteral()->raw() == Symbols::Async().raw()) {
ConsumeToken();
return RawFunction::kAsync;
}
}
return RawFunction::kNoModifier;
}
void Parser::ParseTopLevelFunction(TopLevel* top_level,
intptr_t metadata_pos) {
TRACE_PARSER("ParseTopLevelFunction");
@ -4853,6 +4912,8 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level,
const bool allow_explicit_default_values = true;
ParseFormalParameterList(allow_explicit_default_values, false, &params);
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
intptr_t function_end_pos = function_pos;
bool is_native = false;
if (is_external) {
@ -4887,6 +4948,7 @@ void Parser::ParseTopLevelFunction(TopLevel* top_level,
decl_begin_pos));
func.set_result_type(result_type);
func.set_end_token_pos(function_end_pos);
func.set_modifier(func_modifier);
if (is_native && library_.is_dart_scheme() && library_.IsPrivate(func_name)) {
func.set_is_visible(false);
}
@ -4989,6 +5051,8 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level,
field_name->ToCString());
}
RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
intptr_t accessor_end_pos = accessor_pos;
bool is_native = false;
if (is_external) {
@ -5024,6 +5088,7 @@ void Parser::ParseTopLevelAccessor(TopLevel* top_level,
decl_begin_pos));
func.set_result_type(result_type);
func.set_end_token_pos(accessor_end_pos);
func.set_modifier(func_modifier);
if (is_native && library_.is_dart_scheme() &&
library_.IsPrivate(accessor_name)) {
func.set_is_visible(false);
@ -5440,6 +5505,45 @@ void Parser::OpenFunctionBlock(const Function& func) {
}
RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) {
// Create the closure containing the old body of this function.
Class& sig_cls = Class::ZoneHandle(I);
Type& sig_type = Type::ZoneHandle(I);
Function& closure = Function::ZoneHandle(I);
String& sig = String::ZoneHandle(I);
ParamList closure_params;
closure_params.AddFinalParameter(
formal_param_pos,
&Symbols::ClosureParameter(),
&Type::ZoneHandle(I, Type::DynamicType()));
closure = Function::NewClosureFunction(
Symbols::AnonymousClosure(),
innermost_function(),
formal_param_pos);
AddFormalParamsToFunction(&closure_params, closure);
closure.set_is_async_closure(true);
closure.set_result_type(AbstractType::Handle(Type::DynamicType()));
sig = closure.Signature();
sig_cls = library_.LookupLocalClass(sig);
if (sig_cls.IsNull()) {
sig_cls = Class::NewSignatureClass(sig, closure, script_, formal_param_pos);
library_.AddClass(sig_cls);
}
closure.set_signature_class(sig_cls);
sig_type = sig_cls.SignatureType();
if (!sig_type.IsFinalized()) {
ClassFinalizer::FinalizeType(
sig_cls, sig_type, ClassFinalizer::kCanonicalize);
}
ASSERT(AbstractType::Handle(I, closure.result_type()).IsResolved());
ASSERT(closure.NumParameters() == closure_params.parameters->length());
OpenFunctionBlock(closure);
AddFormalParamsToScope(&closure_params, current_block_->scope);
OpenBlock();
return closure.raw();
}
SequenceNode* Parser::CloseBlock() {
SequenceNode* statements = current_block_->statements;
if (current_block_->scope != NULL) {
@ -5453,6 +5557,141 @@ SequenceNode* Parser::CloseBlock() {
}
SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
SequenceNode* closure_body) {
ASSERT(!closure.IsNull());
ASSERT(closure_body != NULL);
// The block for the async closure body has already been closed. Close the
// corresponding function block.
CloseBlock();
// Create and return a new future that executes a closure with the current
// body.
bool found = false;
// No need to capture parameters or other variables, since they have already
// been captured in the corresponding scope as the body has been parsed within
// a nested block (contained in the async funtion's block).
const Class& future = Class::ZoneHandle(I,
GetClassForAsync(Symbols::Future()));
ASSERT(!future.IsNull());
const Function& constructor = Function::ZoneHandle(I,
future.LookupFunction(Symbols::FutureConstructor()));
ASSERT(!constructor.IsNull());
const Class& completer = Class::ZoneHandle(I,
GetClassForAsync(Symbols::Completer()));
ASSERT(!completer.IsNull());
const Function& completer_constructor = Function::ZoneHandle(I,
completer.LookupFunction(Symbols::CompleterConstructor()));
ASSERT(!completer_constructor.IsNull());
// Add to AST:
// var :async_op;
// var :async_completer;
LocalVariable* async_op_var = new (I) LocalVariable(
Scanner::kNoSourcePos,
Symbols::AsyncOperation(),
Type::ZoneHandle(I, Type::DynamicType()));
current_block_->scope->AddVariable(async_op_var);
found = closure_body->scope()->CaptureVariable(Symbols::AsyncOperation());
ASSERT(found);
LocalVariable* async_completer = new (I) LocalVariable(
Scanner::kNoSourcePos,
Symbols::AsyncCompleter(),
Type::ZoneHandle(I, Type::DynamicType()));
current_block_->scope->AddVariable(async_completer);
found = closure_body->scope()->CaptureVariable(Symbols::AsyncCompleter());
ASSERT(found);
// Add to AST:
// :async_completer = new Completer();
ArgumentListNode* empty_args = new (I) ArgumentListNode(
Scanner::kNoSourcePos);
ConstructorCallNode* completer_constructor_node = new (I) ConstructorCallNode(
Scanner::kNoSourcePos,
TypeArguments::ZoneHandle(I),
completer_constructor,
empty_args);
StoreLocalNode* store_completer = new (I) StoreLocalNode(
Scanner::kNoSourcePos,
async_completer,
completer_constructor_node);
current_block_->statements->Add(store_completer);
// Add to AST:
// :async_op = <closure>; (containing the original body)
ClosureNode* cn = new(I) ClosureNode(
Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
StoreLocalNode* store_async_op = new (I) StoreLocalNode(
Scanner::kNoSourcePos,
async_op_var,
cn);
current_block_->statements->Add(store_async_op);
// Add to AST:
// new Future(:async_op);
ArgumentListNode* arguments = new (I) ArgumentListNode(Scanner::kNoSourcePos);
arguments->Add(new (I) LoadLocalNode(
Scanner::kNoSourcePos, async_op_var));
ConstructorCallNode* future_node = new (I) ConstructorCallNode(
Scanner::kNoSourcePos, TypeArguments::ZoneHandle(I), constructor,
arguments);
current_block_->statements->Add(future_node);
// Add to AST:
// return :async_completer.future;
ReturnNode* return_node = new (I) ReturnNode(
Scanner::kNoSourcePos,
new (I) InstanceGetterNode(
Scanner::kNoSourcePos,
new (I) LoadLocalNode(
Scanner::kNoSourcePos,
async_completer),
Symbols::CompleterFuture()));
current_block_->statements->Add(return_node);
return CloseBlock();
}
void Parser::CloseAsyncClosure(SequenceNode* body) {
ASSERT(body != NULL);
// Replace an optional ReturnNode with the appropriate completer calls.
intptr_t last_index = body->length() - 1;
AstNode* last = NULL;
if (last_index >= 0) {
// Non-empty async closure.
last = body->NodeAt(last_index);
}
ArgumentListNode* args = new (I) ArgumentListNode(Scanner::kNoSourcePos);
LocalVariable* completer = body->scope()->LookupVariable(
Symbols::AsyncCompleter(), false);
ASSERT(completer != NULL);
if (last != NULL && last->IsReturnNode()) {
// Replace
// return <expr>;
// with
// completer.complete(<expr>);
args->Add(body->NodeAt(last_index)->AsReturnNode()->value());
body->ReplaceNodeAt(last_index,
new (I) InstanceCallNode(
Scanner::kNoSourcePos,
new (I) LoadLocalNode(Scanner::kNoSourcePos, completer),
Symbols::CompleterComplete(),
args));
} else {
// Add to AST:
// completer.complete();
body->Add(
new (I) InstanceCallNode(
Scanner::kNoSourcePos,
new (I) LoadLocalNode(Scanner::kNoSourcePos, completer),
Symbols::CompleterComplete(),
args));
}
}
// Set up default values for all optional parameters to the function.
void Parser::SetupDefaultsForOptionalParams(const ParamList* params,
Array* default_values) {
@ -6228,7 +6467,9 @@ bool Parser::IsFunctionDeclaration() {
if ((CurrentToken() == Token::kLBRACE) ||
(CurrentToken() == Token::kARROW) ||
(is_top_level_ && IsLiteral("native")) ||
is_external) {
is_external ||
(FLAG_enable_async &&
CurrentLiteral()->raw() == Symbols::Async().raw())) {
SetPosition(saved_pos);
return true;
}
@ -10767,6 +11008,7 @@ void Parser::SkipFunctionLiteral() {
params.skipped = true;
ParseFormalParameterList(allow_explicit_default_values, false, &params);
}
ParseFunctionModifier();
if (CurrentToken() == Token::kLBRACE) {
SkipBlock();
ExpectToken(Token::kRBRACE);
@ -10792,7 +11034,8 @@ void Parser::SkipFunctionPreamble() {
// Case handles "native" keyword, but also return types of form
// native.SomeType where native is the name of a library.
if (token == Token::kIDENT && LookaheadToken(1) != Token::kPERIOD) {
if (CurrentLiteral()->raw() == Symbols::Native().raw()) {
if (CurrentLiteral()->raw() == Symbols::Native().raw() ||
CurrentLiteral()->raw() == Symbols::Async().raw()) {
return;
}
}

View file

@ -363,6 +363,8 @@ class Parser : public ValueObject {
void ParseTopLevelAccessor(TopLevel* top_level, intptr_t metadata_pos);
RawArray* EvaluateMetadata();
RawFunction::AsyncModifier ParseFunctionModifier();
// Support for parsing libraries.
RawObject* CallLibraryTagHandler(Dart_LibraryTag tag,
intptr_t token_pos,
@ -463,6 +465,7 @@ class Parser : public ValueObject {
Array* default_parameter_values);
SequenceNode* ParseFunc(const Function& func,
Array* default_parameter_values);
RawClass* GetClassForAsync(const String& class_name);
void ParseNativeFunctionBlock(const ParamList* params, const Function& func);
@ -483,7 +486,12 @@ class Parser : public ValueObject {
void OpenBlock();
void OpenLoopBlock();
void OpenFunctionBlock(const Function& func);
RawFunction* OpenAsyncFunction(intptr_t formal_param_pos);
SequenceNode* CloseBlock();
SequenceNode* CloseAsyncFunction(const Function& closure,
SequenceNode* closure_node);
void CloseAsyncClosure(SequenceNode* body);
LocalVariable* LookupPhaseParameter();
LocalVariable* LookupReceiver(LocalScope* from_scope, bool test_only);

View file

@ -615,6 +615,11 @@ class RawFunction : public RawObject {
kInvokeFieldDispatcher, // invokes a field as a closure.
};
enum AsyncModifier {
kNoModifier,
kAsync,
};
private:
// So that the MarkingVisitor::DetachCode can null out the code fields.
friend class MarkingVisitor;
@ -650,7 +655,7 @@ class RawFunction : public RawObject {
int16_t num_fixed_parameters_;
int16_t num_optional_parameters_; // > 0: positional; < 0: named.
int16_t deoptimization_counter_;
uint16_t kind_tag_; // See Function::KindTagBits.
uint32_t kind_tag_; // See Function::KindTagBits.
uint16_t optimized_instruction_count_;
uint16_t optimized_call_site_count_;
};

View file

@ -698,7 +698,7 @@ RawFunction* Function::ReadFrom(SnapshotReader* reader,
func.set_num_fixed_parameters(reader->Read<int16_t>());
func.set_num_optional_parameters(reader->Read<int16_t>());
func.set_deoptimization_counter(reader->Read<int16_t>());
func.set_kind_tag(reader->Read<uint16_t>());
func.set_kind_tag(reader->Read<uint32_t>());
func.set_optimized_instruction_count(reader->Read<uint16_t>());
func.set_optimized_call_site_count(reader->Read<uint16_t>());
@ -739,7 +739,7 @@ void RawFunction::WriteTo(SnapshotWriter* writer,
writer->Write<int16_t>(ptr()->num_fixed_parameters_);
writer->Write<int16_t>(ptr()->num_optional_parameters_);
writer->Write<int16_t>(ptr()->deoptimization_counter_);
writer->Write<uint16_t>(ptr()->kind_tag_);
writer->Write<uint32_t>(ptr()->kind_tag_);
writer->Write<uint16_t>(ptr()->optimized_instruction_count_);
writer->Write<uint16_t>(ptr()->optimized_call_site_count_);

View file

@ -68,6 +68,15 @@ class ObjectPointerVisitor;
V(Library, "library") \
V(LoadLibrary, "loadLibrary") \
V(_LibraryPrefix, "_LibraryPrefix") \
V(Async, "async") \
V(AsyncCompleter, ":async_completer") \
V(AsyncOperation, ":async_op") \
V(Future, "Future") \
V(FutureConstructor, "Future.") \
V(Completer, "Completer") \
V(CompleterComplete, "complete") \
V(CompleterConstructor, "Completer.") \
V(CompleterFuture, "future") \
V(Native, "native") \
V(Import, "import") \
V(Source, "source") \

View file

@ -0,0 +1,121 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--enable_async
import 'package:expect/expect.dart';
import 'dart:async';
topLevelFunction() async { }
Future<int> topLevelWithParameter(int a) async {
return 7 + a;
}
int topLevelWithParameterWrongType(int a) async {
return 7 + a;
}
var what = 'async getter';
Future<String> get topLevelGetter async {
return 'I want to be an ${what}';
}
class A {
static int staticVar = 1;
static staticMethod(int param) async => staticVar + param;
static get staticGetter async => staticVar + 3;
int _x;
A(this._x);
A.fail() async; /// constructor2: compile-time error
factory A.create() async {return null; } /// constructor3: compile-time error
int someMethod(int param1, int param2, int param3) async => _x + param2;
int get getter async { return 5 + _x; }
operator+(A other) async {
return new A(_x + other._x);
}
get value => _x;
}
class B {
final _y;
const B._internal(this._y);
const factory B.createConst(int y) async = A._internal; /// constructor4: compile-time error
B();
set dontDoThat(value) async {} /// setter1: compile-time error
}
main() {
var asyncReturn;
asyncReturn = topLevelFunction();
Expect.isTrue(asyncReturn is Future);
int a1 = topLevelWithParameter(2); /// type-mismatch1: static type warning, dynamic type error
int a2 = topLevelWithParameterWrongType(2); /// type-mismatch2: static type warning, dynamic type error
asyncReturn = topLevelWithParameter(4);
Expect.isTrue(asyncReturn is Future);
asyncReturn.then((int result) => Expect.equals(result, 11));
asyncReturn = topLevelGetter;
Expect.isTrue(asyncReturn is Future);
asyncReturn.then((String result) =>
Expect.stringEquals(result, 'I want to be an async getter'));
asyncReturn = A.staticMethod(2);
Expect.isTrue(asyncReturn is Future);
asyncReturn.then((int result) => Expect.equals(result, 3));
asyncReturn = A.staticGetter;
Expect.isTrue(asyncReturn is Future);
asyncReturn.then((int result) => Expect.equals(result, 4));
A a = new A(13);
asyncReturn = a.someMethod(1,2,3); /// type-mismatch3: static type warning, dynamic type error
Expect.isTrue(asyncReturn is Future); /// type-mismatch3: continued
asyncReturn.then((int result) => Expect.equals(result, 15)); /// type-mismatch3: continued
asyncReturn = a.getter; /// type-mismatch4: static type warning, dynamic type error
Expect.isTrue(asyncReturn is Future); /// type-mismatch4: continued
asyncReturn.then((int result) => Expect.equals(result, 18)); /// type-mismatch4: continued
var b = new A(9);
asyncReturn = a + b;
Expect.isTrue(asyncReturn is Future);
asyncReturn.then((A result) => Expect.equals(result.value, 22));
var foo = 17;
bar(int p1, p2) async {
var z = 8;
return p2 + z + foo;
}
asyncReturn = bar(1,2);
Expect.isTrue(asyncReturn is Future);
asyncReturn.then((int result) => Expect.equals(result, 27));
var moreNesting = (int shadowP1, String p2, num p3) {
var z = 3;
aa(int shadowP1) async {
return foo + z + p3 + shadowP1;
}
return aa(6);
};
asyncReturn = moreNesting(1, "ignore", 2);
Expect.isTrue(asyncReturn is Future);
asyncReturn.then((int result) => Expect.equals(result, 28));
var b1 = const B.createConst(4); /// constructor4: compile-time error
var b2 = new B();
b2.dontDoThat = 4; /// setter1: compile-time error
}

View file

@ -31,6 +31,9 @@ deferred_constraints_constants_old_syntax_test/default_argument2: Fail, Ok
deferred_constraints_constants_old_syntax_test/constructor1: Fail, Ok
deferred_constraints_constants_old_syntax_test/constructor2: Fail, Ok
[ $runtime != vm ]
# Async tests are currently only supported by the vm.
async_test/*: Skip
[ $compiler == dart2dart]
deferred_load_library_wrong_args_test/none: Fail # Issue 17523