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

Side by Side Diff: runtime/vm/parser.cc

Issue 23542051: Fix redirecting constructors (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/language/language.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 6
7 #include "lib/invocation_mirror.h" 7 #include "lib/invocation_mirror.h"
8 #include "vm/bigint_operations.h" 8 #include "vm/bigint_operations.h"
9 #include "vm/bootstrap.h" 9 #include "vm/bootstrap.h"
10 #include "vm/class_finalizer.h" 10 #include "vm/class_finalizer.h"
(...skipping 2331 matching lines...) Expand 10 before | Expand all | Expand 10 after
2342 initialized_fields->Add(field); 2342 initialized_fields->Add(field);
2343 } 2343 }
2344 2344
2345 2345
2346 void Parser::ParseInitializers(const Class& cls, 2346 void Parser::ParseInitializers(const Class& cls,
2347 LocalVariable* receiver, 2347 LocalVariable* receiver,
2348 GrowableArray<Field*>* initialized_fields) { 2348 GrowableArray<Field*>* initialized_fields) {
2349 TRACE_PARSER("ParseInitializers"); 2349 TRACE_PARSER("ParseInitializers");
2350 bool super_init_seen = false; 2350 bool super_init_seen = false;
2351 if (CurrentToken() == Token::kCOLON) { 2351 if (CurrentToken() == Token::kCOLON) {
2352 if ((LookaheadToken(1) == Token::kTHIS) &&
2353 ((LookaheadToken(2) == Token::kLPAREN) ||
2354 ((LookaheadToken(2) == Token::kPERIOD) &&
2355 (LookaheadToken(4) == Token::kLPAREN)))) {
2356 // Either we see this(...) or this.xxx(...) which is a
2357 // redirected constructor. We don't need to check whether
2358 // const fields are initialized. The other constructor will
2359 // guarantee that.
2360 ConsumeToken(); // Colon.
2361 ParseConstructorRedirection(cls, receiver);
2362 return;
2363 }
2364 do { 2352 do {
2365 ConsumeToken(); // Colon or comma. 2353 ConsumeToken(); // Colon or comma.
2366 AstNode* init_statement; 2354 AstNode* init_statement;
2367 if (CurrentToken() == Token::kSUPER) { 2355 if (CurrentToken() == Token::kSUPER) {
2368 if (super_init_seen) { 2356 if (super_init_seen) {
2369 ErrorMsg("duplicate call to super constructor"); 2357 ErrorMsg("duplicate call to super constructor");
2370 } 2358 }
2371 init_statement = ParseSuperInitializer(cls, receiver); 2359 init_statement = ParseSuperInitializer(cls, receiver);
2372 super_init_seen = true; 2360 super_init_seen = true;
2373 } else { 2361 } else {
2374 init_statement = ParseInitializer(cls, receiver, initialized_fields); 2362 init_statement = ParseInitializer(cls, receiver, initialized_fields);
2375 } 2363 }
2376 current_block_->statements->Add(init_statement); 2364 current_block_->statements->Add(init_statement);
2377 } while (CurrentToken() == Token::kCOMMA); 2365 } while (CurrentToken() == Token::kCOMMA);
2378 } 2366 }
2379 if (!super_init_seen) { 2367 if (!super_init_seen) {
2380 // Generate implicit super() if we haven't seen an explicit super call 2368 // Generate implicit super() if we haven't seen an explicit super call
2381 // or constructor redirection. 2369 // or constructor redirection.
2382 GenerateSuperConstructorCall(cls, receiver, NULL); 2370 GenerateSuperConstructorCall(cls, receiver, NULL);
2383 } 2371 }
2384 CheckConstFieldsInitialized(cls); 2372 CheckConstFieldsInitialized(cls);
2385 } 2373 }
2386 2374
2387 2375
2388 void Parser::ParseConstructorRedirection(const Class& cls, 2376 void Parser::ParseConstructorRedirection(const Class& cls,
2389 LocalVariable* receiver) { 2377 LocalVariable* receiver) {
2390 TRACE_PARSER("ParseConstructorRedirection"); 2378 TRACE_PARSER("ParseConstructorRedirection");
2379 ExpectToken(Token::kCOLON);
2391 ASSERT(CurrentToken() == Token::kTHIS); 2380 ASSERT(CurrentToken() == Token::kTHIS);
2392 const intptr_t call_pos = TokenPos(); 2381 const intptr_t call_pos = TokenPos();
2393 ConsumeToken(); 2382 ConsumeToken();
2394 String& ctor_name = String::Handle(cls.Name()); 2383 String& ctor_name = String::Handle(cls.Name());
2395 2384
2396 ctor_name = String::Concat(ctor_name, Symbols::Dot()); 2385 ctor_name = String::Concat(ctor_name, Symbols::Dot());
2397 if (CurrentToken() == Token::kPERIOD) { 2386 if (CurrentToken() == Token::kPERIOD) {
2398 ConsumeToken(); 2387 ConsumeToken();
2399 ctor_name = String::Concat(ctor_name, 2388 ctor_name = String::Concat(ctor_name,
2400 *ExpectIdentifier("constructor name expected")); 2389 *ExpectIdentifier("constructor name expected"));
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
2561 } 2550 }
2562 ParseFormalParameterList(allow_explicit_default_values, false, &params); 2551 ParseFormalParameterList(allow_explicit_default_values, false, &params);
2563 2552
2564 SetupDefaultsForOptionalParams(&params, default_parameter_values); 2553 SetupDefaultsForOptionalParams(&params, default_parameter_values);
2565 ASSERT(AbstractType::Handle(func.result_type()).IsResolved()); 2554 ASSERT(AbstractType::Handle(func.result_type()).IsResolved());
2566 ASSERT(func.NumParameters() == params.parameters->length()); 2555 ASSERT(func.NumParameters() == params.parameters->length());
2567 2556
2568 // Now populate function scope with the formal parameters. 2557 // Now populate function scope with the formal parameters.
2569 AddFormalParamsToScope(&params, current_block_->scope); 2558 AddFormalParamsToScope(&params, current_block_->scope);
2570 2559
2571 // Initialize instance fields that have an explicit initializer expression. 2560 const bool is_redirecting_constructor =
2572 // The formal parameter names must not be visible to the instance 2561 (CurrentToken() == Token::kCOLON) &&
2573 // field initializer expressions, yet the parameters must be added to 2562 ((LookaheadToken(1) == Token::kTHIS) &&
2574 // the scope so the expressions use the correct offsets for 'this' when 2563 ((LookaheadToken(2) == Token::kLPAREN) ||
2575 // storing values. We make the formal parameters temporarily invisible 2564 ((LookaheadToken(2) == Token::kPERIOD) &&
2576 // while parsing the instance field initializer expressions. 2565 (LookaheadToken(4) == Token::kLPAREN))));
2577 params.SetInvisible(true); 2566
2578 GrowableArray<Field*> initialized_fields; 2567 GrowableArray<Field*> initialized_fields;
2579 LocalVariable* receiver = current_block_->scope->VariableAt(0); 2568 LocalVariable* receiver = (*params.parameters)[0].var;
2580 OpenBlock(); 2569 OpenBlock();
2581 ParseInitializedInstanceFields(cls, receiver, &initialized_fields);
2582 // Make the parameters (which are in the outer scope) visible again.
2583 params.SetInvisible(false);
2584 2570
2585 // Turn formal field parameters into field initializers or report error 2571 // If this is not a redirecting constructor, initialize
2586 // if the function is not a constructor. 2572 // instance fields that have an explicit initializer expression.
2573 if (!is_redirecting_constructor) {
2574 // The formal parameter names must not be visible to the instance
2575 // field initializer expressions, yet the parameters must be added to
2576 // the scope so the expressions use the correct offsets for 'this' when
2577 // storing values. We make the formal parameters temporarily invisible
2578 // while parsing the instance field initializer expressions.
2579 params.SetInvisible(true);
2580 ParseInitializedInstanceFields(cls, receiver, &initialized_fields);
2581 // Make the parameters (which are in the outer scope) visible again.
2582 params.SetInvisible(false);
2583 }
2584
2585 // Turn formal field parameters into field initializers.
2587 if (params.has_field_initializer) { 2586 if (params.has_field_initializer) {
2588 for (int i = 0; i < params.parameters->length(); i++) { 2587 // First two parameters are implicit receiver and phase.
2588 ASSERT(params.parameters->length() >= 2);
2589 for (int i = 2; i < params.parameters->length(); i++) {
2589 ParamDesc& param = (*params.parameters)[i]; 2590 ParamDesc& param = (*params.parameters)[i];
2590 if (param.is_field_initializer) { 2591 if (param.is_field_initializer) {
2591 const String& field_name = *param.name; 2592 const String& field_name = *param.name;
2592 Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name)); 2593 Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name));
2593 if (field.IsNull()) { 2594 if (field.IsNull()) {
2594 ErrorMsg(param.name_pos, 2595 ErrorMsg(param.name_pos,
2595 "unresolved reference to instance field '%s'", 2596 "unresolved reference to instance field '%s'",
2596 field_name.ToCString()); 2597 field_name.ToCString());
2597 } 2598 }
2599 if (is_redirecting_constructor) {
2600 ErrorMsg(param.name_pos,
2601 "redirecting constructors may not have "
2602 "initializing formal parameters");
2603 }
2598 CheckDuplicateFieldInit(param.name_pos, &initialized_fields, &field); 2604 CheckDuplicateFieldInit(param.name_pos, &initialized_fields, &field);
2599 AstNode* instance = new LoadLocalNode(param.name_pos, receiver); 2605 AstNode* instance = new LoadLocalNode(param.name_pos, receiver);
2600 // Initializing formals cannot be used in the explicit initializer 2606 // Initializing formals cannot be used in the explicit initializer
2601 // list, nor can they be used in the constructor body. 2607 // list, nor can they be used in the constructor body.
2602 // Thus, they are set to be invisible when added to the scope. 2608 // Thus, they are set to be invisible when added to the scope.
2603 LocalVariable* p = param.var; 2609 LocalVariable* p = param.var;
2604 ASSERT(p != NULL); 2610 ASSERT(p != NULL);
2605 ASSERT(p->is_invisible()); 2611 ASSERT(p->is_invisible());
2606 AstNode* value = new LoadLocalNode(param.name_pos, p); 2612 AstNode* value = new LoadLocalNode(param.name_pos, p);
2607 EnsureExpressionTemp(); 2613 EnsureExpressionTemp();
2608 AstNode* initializer = new StoreInstanceFieldNode( 2614 AstNode* initializer = new StoreInstanceFieldNode(
2609 param.name_pos, instance, field, value); 2615 param.name_pos, instance, field, value);
2610 current_block_->statements->Add(initializer); 2616 current_block_->statements->Add(initializer);
2611 } 2617 }
2612 } 2618 }
2613 } 2619 }
2614 2620
2615 // Now parse the explicit initializer list or constructor redirection. 2621 if (is_redirecting_constructor) {
2616 ParseInitializers(cls, receiver, &initialized_fields); 2622 ParseConstructorRedirection(cls, receiver);
2623 } else {
2624 ParseInitializers(cls, receiver, &initialized_fields);
2625 }
2617 2626
2618 SequenceNode* init_statements = CloseBlock(); 2627 SequenceNode* init_statements = CloseBlock();
2619 if (init_statements->length() > 0) { 2628 if (init_statements->length() > 0) {
2620 // Generate guard around the initializer code. 2629 // Generate guard around the initializer code.
2621 LocalVariable* phase_param = LookupPhaseParameter(); 2630 LocalVariable* phase_param = LookupPhaseParameter();
2622 AstNode* phase_value = new LoadLocalNode(TokenPos(), phase_param); 2631 AstNode* phase_value = new LoadLocalNode(TokenPos(), phase_param);
2623 AstNode* phase_check = new BinaryOpNode( 2632 AstNode* phase_check = new BinaryOpNode(
2624 TokenPos(), Token::kBIT_AND, phase_value, 2633 TokenPos(), Token::kBIT_AND, phase_value,
2625 new LiteralNode(TokenPos(), 2634 new LiteralNode(TokenPos(),
2626 Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit)))); 2635 Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit))));
(...skipping 26 matching lines...) Expand all
2653 break; 2662 break;
2654 } 2663 }
2655 } 2664 }
2656 } 2665 }
2657 if (super_call != NULL) { 2666 if (super_call != NULL) {
2658 // Generate an implicit call to the super constructor's body. 2667 // Generate an implicit call to the super constructor's body.
2659 // We need to patch the super _initializer_ call so that it 2668 // We need to patch the super _initializer_ call so that it
2660 // saves the evaluated actual arguments in temporary variables. 2669 // saves the evaluated actual arguments in temporary variables.
2661 // The temporary variables are necessary so that the argument 2670 // The temporary variables are necessary so that the argument
2662 // expressions are not evaluated twice. 2671 // expressions are not evaluated twice.
2672 // Note: we should never get here in the case of a redirecting
2673 // constructor. In that case, the call to the target constructor
2674 // is the "super call" and is implicitly at the end of the
2675 // initializer list.
2676 ASSERT(!is_redirecting_constructor);
2663 ArgumentListNode* ctor_args = super_call->arguments(); 2677 ArgumentListNode* ctor_args = super_call->arguments();
2664 // The super initializer call has at least 2 arguments: the 2678 // The super initializer call has at least 2 arguments: the
2665 // implicit receiver, and the hidden construction phase. 2679 // implicit receiver, and the hidden construction phase.
2666 ASSERT(ctor_args->length() >= 2); 2680 ASSERT(ctor_args->length() >= 2);
2667 for (int i = 2; i < ctor_args->length(); i++) { 2681 for (int i = 2; i < ctor_args->length(); i++) {
2668 AstNode* arg = ctor_args->NodeAt(i); 2682 AstNode* arg = ctor_args->NodeAt(i);
2669 if (!IsSimpleLocalOrLiteralNode(arg)) { 2683 if (!IsSimpleLocalOrLiteralNode(arg)) {
2670 LocalVariable* temp = 2684 LocalVariable* temp =
2671 CreateTempConstVariable(arg->token_pos(), "sca"); 2685 CreateTempConstVariable(arg->token_pos(), "sca");
2672 AstNode* save_temp = new StoreLocalNode(arg->token_pos(), temp, arg); 2686 AstNode* save_temp = new StoreLocalNode(arg->token_pos(), temp, arg);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
2712 } 2726 }
2713 } 2727 }
2714 ASSERT(super_ctor.AreValidArguments(super_call_args->length(), 2728 ASSERT(super_ctor.AreValidArguments(super_call_args->length(),
2715 super_call_args->names(), 2729 super_call_args->names(),
2716 NULL)); 2730 NULL));
2717 current_block_->statements->Add( 2731 current_block_->statements->Add(
2718 new StaticCallNode(body_pos, super_ctor, super_call_args)); 2732 new StaticCallNode(body_pos, super_ctor, super_call_args));
2719 } 2733 }
2720 2734
2721 if (CurrentToken() == Token::kLBRACE) { 2735 if (CurrentToken() == Token::kLBRACE) {
2736 // We checked in the top-level parse phase that a redirecting
2737 // constructor does not have a body.
2738 ASSERT(!is_redirecting_constructor);
2722 ConsumeToken(); 2739 ConsumeToken();
2723 ParseStatementSequence(); 2740 ParseStatementSequence();
2724 ExpectToken(Token::kRBRACE); 2741 ExpectToken(Token::kRBRACE);
2725 } else if (CurrentToken() == Token::kARROW) { 2742 } else if (CurrentToken() == Token::kARROW) {
2726 ErrorMsg("constructors may not return a value"); 2743 ErrorMsg("constructors may not return a value");
2727 } else if (IsLiteral("native")) { 2744 } else if (IsLiteral("native")) {
2728 ErrorMsg("native constructors not supported"); 2745 ErrorMsg("native constructors not supported");
2729 } else if (CurrentToken() == Token::kSEMICOLON) { 2746 } else if (CurrentToken() == Token::kSEMICOLON) {
2730 // Some constructors have no function body. 2747 // Some constructors have no function body.
2731 ConsumeToken(); 2748 ConsumeToken();
(...skipping 7693 matching lines...) Expand 10 before | Expand all | Expand 10 after
10425 void Parser::SkipQualIdent() { 10442 void Parser::SkipQualIdent() {
10426 ASSERT(IsIdentifier()); 10443 ASSERT(IsIdentifier());
10427 ConsumeToken(); 10444 ConsumeToken();
10428 if (CurrentToken() == Token::kPERIOD) { 10445 if (CurrentToken() == Token::kPERIOD) {
10429 ConsumeToken(); // Consume the kPERIOD token. 10446 ConsumeToken(); // Consume the kPERIOD token.
10430 ExpectIdentifier("identifier expected after '.'"); 10447 ExpectIdentifier("identifier expected after '.'");
10431 } 10448 }
10432 } 10449 }
10433 10450
10434 } // namespace dart 10451 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698