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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/parser.h" 5 #include "vm/parser.h"
6 #include "vm/flags.h" 6 #include "vm/flags.h"
7 7
8 #ifndef DART_PRECOMPILED_RUNTIME 8 #ifndef DART_PRECOMPILED_RUNTIME
9 9
10 #include "lib/invocation_mirror.h" 10 #include "lib/invocation_mirror.h"
(...skipping 3678 matching lines...) Expand 10 before | Expand all | Expand 10 after
3689 ConsumeToken(); 3689 ConsumeToken();
3690 if (String::Handle(Z, func.name()).Equals(Symbols::EqualOperator())) { 3690 if (String::Handle(Z, func.name()).Equals(Symbols::EqualOperator())) {
3691 const Class& owner = Class::Handle(Z, func.Owner()); 3691 const Class& owner = Class::Handle(Z, func.Owner());
3692 if (!owner.IsObjectClass()) { 3692 if (!owner.IsObjectClass()) {
3693 AddEqualityNullCheck(); 3693 AddEqualityNullCheck();
3694 } 3694 }
3695 } 3695 }
3696 const TokenPosition expr_pos = TokenPos(); 3696 const TokenPosition expr_pos = TokenPos();
3697 AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); 3697 AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
3698 ASSERT(expr != NULL); 3698 ASSERT(expr != NULL);
3699 current_block_->statements->Add(new ReturnNode(expr_pos, expr)); 3699 expr = AddAsyncResultTypeCheck(expr_pos, expr);
3700 current_block_->statements->Add(new (Z) ReturnNode(expr_pos, expr));
3700 end_token_pos = TokenPos(); 3701 end_token_pos = TokenPos();
3701 if (check_semicolon) { 3702 if (check_semicolon) {
3702 ExpectSemicolon(); 3703 ExpectSemicolon();
3703 } 3704 }
3704 } else if (IsSymbol(Symbols::Native())) { 3705 } else if (IsSymbol(Symbols::Native())) {
3705 if (String::Handle(Z, func.name()).Equals(Symbols::EqualOperator())) { 3706 if (String::Handle(Z, func.name()).Equals(Symbols::EqualOperator())) {
3706 const Class& owner = Class::Handle(Z, func.Owner()); 3707 const Class& owner = Class::Handle(Z, func.Owner());
3707 if (!owner.IsObjectClass()) { 3708 if (!owner.IsObjectClass()) {
3708 AddEqualityNullCheck(); 3709 AddEqualityNullCheck();
3709 } 3710 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
3764 new ComparisonNode(TokenPosition::kNoSource, Token::kEQ_STRICT, 3765 new ComparisonNode(TokenPosition::kNoSource, Token::kEQ_STRICT,
3765 LoadReceiver(TokenPosition::kNoSource), null_operand); 3766 LoadReceiver(TokenPosition::kNoSource), null_operand);
3766 SequenceNode* arg_is_null = 3767 SequenceNode* arg_is_null =
3767 new SequenceNode(TokenPosition::kNoSource, current_block_->scope); 3768 new SequenceNode(TokenPosition::kNoSource, current_block_->scope);
3768 arg_is_null->Add(new ReturnNode(TokenPosition::kNoSource, result)); 3769 arg_is_null->Add(new ReturnNode(TokenPosition::kNoSource, result));
3769 IfNode* if_arg_null = 3770 IfNode* if_arg_null =
3770 new IfNode(TokenPosition::kNoSource, check_arg, arg_is_null, NULL); 3771 new IfNode(TokenPosition::kNoSource, check_arg, arg_is_null, NULL);
3771 current_block_->statements->Add(if_arg_null); 3772 current_block_->statements->Add(if_arg_null);
3772 } 3773 }
3773 3774
3775 AstNode* Parser::AddAsyncResultTypeCheck(TokenPosition expr_pos,
3776 AstNode* expr) {
3777 if (I->type_checks() &&
3778 (((FunctionLevel() == 0) && current_function().IsAsyncClosure()))) {
3779 // In checked mode, when the declared result type is Future<T>, verify
3780 // that the returned expression is of type T or Future<T> as follows:
3781 // return temp = expr, temp is Future ? temp as Future<T> : temp as T;
3782 // In case of a mismatch, we need a TypeError and not a CastError, so
3783 // we do not actually implement an "as" test, but an "assignable" test.
3784 Function& async_func =
3785 Function::Handle(Z, current_function().parent_function());
3786 const AbstractType& result_type =
3787 AbstractType::ZoneHandle(Z, async_func.result_type());
3788 const Class& future_class =
3789 Class::ZoneHandle(Z, I->object_store()->future_class());
3790 ASSERT(!future_class.IsNull());
3791 if (result_type.type_class() == future_class.raw()) {
3792 const TypeArguments& result_type_args =
3793 TypeArguments::ZoneHandle(Z, result_type.arguments());
3794 if (!result_type_args.IsNull() && (result_type_args.Length() == 1)) {
3795 const AbstractType& result_type_arg =
3796 AbstractType::ZoneHandle(Z, result_type_args.TypeAt(0));
3797 LetNode* checked_expr = new (Z) LetNode(expr_pos);
3798 LocalVariable* temp = checked_expr->AddInitializer(expr);
3799 temp->set_is_final();
3800 const AbstractType& future_type =
3801 AbstractType::ZoneHandle(Z, future_class.RareType());
3802 AstNode* is_future = new (Z) LoadLocalNode(expr_pos, temp);
3803 is_future =
3804 new (Z) ComparisonNode(expr_pos, Token::kIS, is_future,
3805 new (Z) TypeNode(expr_pos, future_type));
3806 AstNode* as_future_t = new (Z) LoadLocalNode(expr_pos, temp);
3807 as_future_t = new (Z) AssignableNode(expr_pos, as_future_t, result_type,
3808 Symbols::FunctionResult());
3809 AstNode* as_t = new (Z) LoadLocalNode(expr_pos, temp);
3810 as_t = new (Z) AssignableNode(expr_pos, as_t, result_type_arg,
3811 Symbols::FunctionResult());
3812 checked_expr->AddNode(new (Z) ConditionalExprNode(expr_pos, is_future,
3813 as_future_t, as_t));
3814 expr = checked_expr;
3815 }
3816 }
3817 }
3818 return expr;
3819 }
3820
3774 void Parser::SkipIf(Token::Kind token) { 3821 void Parser::SkipIf(Token::Kind token) {
3775 if (CurrentToken() == token) { 3822 if (CurrentToken() == token) {
3776 ConsumeToken(); 3823 ConsumeToken();
3777 } 3824 }
3778 } 3825 }
3779 3826
3780 void Parser::SkipInitializers() { 3827 void Parser::SkipInitializers() {
3781 ASSERT(CurrentToken() == Token::kCOLON); 3828 ASSERT(CurrentToken() == Token::kCOLON);
3782 do { 3829 do {
3783 ConsumeToken(); // Colon or comma. 3830 ConsumeToken(); // Colon or comma.
(...skipping 6746 matching lines...) Expand 10 before | Expand all | Expand 10 after
10530 const int function_level = FunctionLevel(); 10577 const int function_level = FunctionLevel();
10531 if (current_function().IsGenerativeConstructor() && 10578 if (current_function().IsGenerativeConstructor() &&
10532 (function_level == 0)) { 10579 (function_level == 0)) {
10533 ReportError(expr_pos, 10580 ReportError(expr_pos,
10534 "return of a value is not allowed in constructors"); 10581 "return of a value is not allowed in constructors");
10535 } else if (current_function().IsGeneratorClosure() && 10582 } else if (current_function().IsGeneratorClosure() &&
10536 (function_level == 0)) { 10583 (function_level == 0)) {
10537 ReportError(expr_pos, "generator functions may not return a value"); 10584 ReportError(expr_pos, "generator functions may not return a value");
10538 } 10585 }
10539 AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL); 10586 AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
10540 if (I->type_checks() && 10587 expr = AddAsyncResultTypeCheck(expr_pos, expr);
10541 (((function_level == 0) && current_function().IsAsyncClosure()))) {
10542 // In checked mode, when the declared result type is Future<T>, verify
10543 // that the returned expression is of type T or Future<T> as follows:
10544 // return temp = expr, temp is Future ? temp as Future<T> : temp as T;
10545 // In case of a mismatch, we need a TypeError and not a CastError, so
10546 // we do not actually implement an "as" test, but an "assignable" test.
10547 Function& async_func =
10548 Function::Handle(Z, current_function().parent_function());
10549 const AbstractType& result_type =
10550 AbstractType::ZoneHandle(Z, async_func.result_type());
10551 const Class& future_class =
10552 Class::ZoneHandle(Z, I->object_store()->future_class());
10553 ASSERT(!future_class.IsNull());
10554 if (result_type.type_class() == future_class.raw()) {
10555 const TypeArguments& result_type_args =
10556 TypeArguments::ZoneHandle(Z, result_type.arguments());
10557 if (!result_type_args.IsNull() && (result_type_args.Length() == 1)) {
10558 const AbstractType& result_type_arg =
10559 AbstractType::ZoneHandle(Z, result_type_args.TypeAt(0));
10560 LetNode* checked_expr = new (Z) LetNode(expr_pos);
10561 LocalVariable* temp = checked_expr->AddInitializer(expr);
10562 temp->set_is_final();
10563 const AbstractType& future_type =
10564 AbstractType::ZoneHandle(Z, future_class.RareType());
10565 AstNode* is_future = new (Z) LoadLocalNode(expr_pos, temp);
10566 is_future =
10567 new (Z) ComparisonNode(expr_pos, Token::kIS, is_future,
10568 new (Z) TypeNode(expr_pos, future_type));
10569 AstNode* as_future_t = new (Z) LoadLocalNode(expr_pos, temp);
10570 as_future_t = new (Z) AssignableNode(
10571 expr_pos, as_future_t, result_type, Symbols::FunctionResult());
10572 AstNode* as_t = new (Z) LoadLocalNode(expr_pos, temp);
10573 as_t = new (Z) AssignableNode(expr_pos, as_t, result_type_arg,
10574 Symbols::FunctionResult());
10575 checked_expr->AddNode(new (Z) ConditionalExprNode(
10576 expr_pos, is_future, as_future_t, as_t));
10577 expr = checked_expr;
10578 }
10579 }
10580 }
10581 statement = new (Z) ReturnNode(statement_pos, expr); 10588 statement = new (Z) ReturnNode(statement_pos, expr);
10582 } else { 10589 } else {
10583 if (current_function().IsSyncGenClosure() && (FunctionLevel() == 0)) { 10590 if (current_function().IsSyncGenClosure() && (FunctionLevel() == 0)) {
10584 // In a synchronous generator, return without an expression 10591 // In a synchronous generator, return without an expression
10585 // returns false, signaling that the iterator terminates and 10592 // returns false, signaling that the iterator terminates and
10586 // did not yield a value. 10593 // did not yield a value.
10587 statement = new (Z) ReturnNode( 10594 statement = new (Z) ReturnNode(
10588 statement_pos, new (Z) LiteralNode(return_pos, Bool::False())); 10595 statement_pos, new (Z) LiteralNode(return_pos, Bool::False()));
10589 } else { 10596 } else {
10590 statement = new (Z) ReturnNode(statement_pos); 10597 statement = new (Z) ReturnNode(statement_pos);
(...skipping 4509 matching lines...) Expand 10 before | Expand all | Expand 10 after
15100 bool Parser::FieldHasFunctionLiteralInitializer(const Field& field, 15107 bool Parser::FieldHasFunctionLiteralInitializer(const Field& field,
15101 TokenPosition* start, 15108 TokenPosition* start,
15102 TokenPosition* end) { 15109 TokenPosition* end) {
15103 UNREACHABLE(); 15110 UNREACHABLE();
15104 return false; 15111 return false;
15105 } 15112 }
15106 15113
15107 } // namespace dart 15114 } // namespace dart
15108 15115
15109 #endif // DART_PRECOMPILED_RUNTIME 15116 #endif // DART_PRECOMPILED_RUNTIME
OLDNEW
« 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