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

Unified Diff: runtime/vm/parser.cc

Issue 2993223002: [VM parser] Insert missing result type check in async functions using arrow (Closed)
Patch Set: update status file Created 3 years, 4 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 | « runtime/vm/parser.h ('k') | tests/language_2/language_2_analyzer.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/parser.cc
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 004956688b7c8463f5bd63582f8fb6af59a1202f..557e69d5b588f7a53e136658456b4cc75a5471d0 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3696,7 +3696,8 @@ SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) {
const TokenPosition expr_pos = TokenPos();
AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
ASSERT(expr != NULL);
- current_block_->statements->Add(new ReturnNode(expr_pos, expr));
+ expr = AddAsyncResultTypeCheck(expr_pos, expr);
+ current_block_->statements->Add(new (Z) ReturnNode(expr_pos, expr));
end_token_pos = TokenPos();
if (check_semicolon) {
ExpectSemicolon();
@@ -3771,6 +3772,52 @@ void Parser::AddEqualityNullCheck() {
current_block_->statements->Add(if_arg_null);
}
+AstNode* Parser::AddAsyncResultTypeCheck(TokenPosition expr_pos,
+ AstNode* expr) {
+ if (I->type_checks() &&
+ (((FunctionLevel() == 0) && current_function().IsAsyncClosure()))) {
+ // In checked mode, when the declared result type is Future<T>, verify
+ // that the returned expression is of type T or Future<T> as follows:
+ // return temp = expr, temp is Future ? temp as Future<T> : temp as T;
+ // In case of a mismatch, we need a TypeError and not a CastError, so
+ // we do not actually implement an "as" test, but an "assignable" test.
+ Function& async_func =
+ Function::Handle(Z, current_function().parent_function());
+ const AbstractType& result_type =
+ AbstractType::ZoneHandle(Z, async_func.result_type());
+ const Class& future_class =
+ Class::ZoneHandle(Z, I->object_store()->future_class());
+ ASSERT(!future_class.IsNull());
+ if (result_type.type_class() == future_class.raw()) {
+ const TypeArguments& result_type_args =
+ TypeArguments::ZoneHandle(Z, result_type.arguments());
+ if (!result_type_args.IsNull() && (result_type_args.Length() == 1)) {
+ const AbstractType& result_type_arg =
+ AbstractType::ZoneHandle(Z, result_type_args.TypeAt(0));
+ LetNode* checked_expr = new (Z) LetNode(expr_pos);
+ LocalVariable* temp = checked_expr->AddInitializer(expr);
+ temp->set_is_final();
+ const AbstractType& future_type =
+ AbstractType::ZoneHandle(Z, future_class.RareType());
+ AstNode* is_future = new (Z) LoadLocalNode(expr_pos, temp);
+ is_future =
+ new (Z) ComparisonNode(expr_pos, Token::kIS, is_future,
+ new (Z) TypeNode(expr_pos, future_type));
+ AstNode* as_future_t = new (Z) LoadLocalNode(expr_pos, temp);
+ as_future_t = new (Z) AssignableNode(expr_pos, as_future_t, result_type,
+ Symbols::FunctionResult());
+ AstNode* as_t = new (Z) LoadLocalNode(expr_pos, temp);
+ as_t = new (Z) AssignableNode(expr_pos, as_t, result_type_arg,
+ Symbols::FunctionResult());
+ checked_expr->AddNode(new (Z) ConditionalExprNode(expr_pos, is_future,
+ as_future_t, as_t));
+ expr = checked_expr;
+ }
+ }
+ }
+ return expr;
+}
+
void Parser::SkipIf(Token::Kind token) {
if (CurrentToken() == token) {
ConsumeToken();
@@ -10537,47 +10584,7 @@ AstNode* Parser::ParseStatement() {
ReportError(expr_pos, "generator functions may not return a value");
}
AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
- if (I->type_checks() &&
- (((function_level == 0) && current_function().IsAsyncClosure()))) {
- // In checked mode, when the declared result type is Future<T>, verify
- // that the returned expression is of type T or Future<T> as follows:
- // return temp = expr, temp is Future ? temp as Future<T> : temp as T;
- // In case of a mismatch, we need a TypeError and not a CastError, so
- // we do not actually implement an "as" test, but an "assignable" test.
- Function& async_func =
- Function::Handle(Z, current_function().parent_function());
- const AbstractType& result_type =
- AbstractType::ZoneHandle(Z, async_func.result_type());
- const Class& future_class =
- Class::ZoneHandle(Z, I->object_store()->future_class());
- ASSERT(!future_class.IsNull());
- if (result_type.type_class() == future_class.raw()) {
- const TypeArguments& result_type_args =
- TypeArguments::ZoneHandle(Z, result_type.arguments());
- if (!result_type_args.IsNull() && (result_type_args.Length() == 1)) {
- const AbstractType& result_type_arg =
- AbstractType::ZoneHandle(Z, result_type_args.TypeAt(0));
- LetNode* checked_expr = new (Z) LetNode(expr_pos);
- LocalVariable* temp = checked_expr->AddInitializer(expr);
- temp->set_is_final();
- const AbstractType& future_type =
- AbstractType::ZoneHandle(Z, future_class.RareType());
- AstNode* is_future = new (Z) LoadLocalNode(expr_pos, temp);
- is_future =
- new (Z) ComparisonNode(expr_pos, Token::kIS, is_future,
- new (Z) TypeNode(expr_pos, future_type));
- AstNode* as_future_t = new (Z) LoadLocalNode(expr_pos, temp);
- as_future_t = new (Z) AssignableNode(
- expr_pos, as_future_t, result_type, Symbols::FunctionResult());
- AstNode* as_t = new (Z) LoadLocalNode(expr_pos, temp);
- as_t = new (Z) AssignableNode(expr_pos, as_t, result_type_arg,
- Symbols::FunctionResult());
- checked_expr->AddNode(new (Z) ConditionalExprNode(
- expr_pos, is_future, as_future_t, as_t));
- expr = checked_expr;
- }
- }
- }
+ expr = AddAsyncResultTypeCheck(expr_pos, expr);
statement = new (Z) ReturnNode(statement_pos, expr);
} else {
if (current_function().IsSyncGenClosure() && (FunctionLevel() == 0)) {
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/language_2/language_2_analyzer.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698