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

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

Issue 505033002: Initializing a final instance is a runtime error (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 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 | « runtime/vm/parser.h ('k') | tests/co19/co19-co19.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 "platform/utils.h" 8 #include "platform/utils.h"
9 #include "vm/ast_transformer.h" 9 #include "vm/ast_transformer.h"
10 #include "vm/bootstrap.h" 10 #include "vm/bootstrap.h"
(...skipping 2175 matching lines...) Expand 10 before | Expand all | Expand 10 after
2186 SetAllowFunctionLiterals(saved_mode); 2186 SetAllowFunctionLiterals(saved_mode);
2187 if (current_function().is_const() && !init_expr->IsPotentiallyConst()) { 2187 if (current_function().is_const() && !init_expr->IsPotentiallyConst()) {
2188 ReportError(field_pos, 2188 ReportError(field_pos,
2189 "initializer expression must be compile time constant."); 2189 "initializer expression must be compile time constant.");
2190 } 2190 }
2191 Field& field = Field::ZoneHandle(I, cls.LookupInstanceField(field_name)); 2191 Field& field = Field::ZoneHandle(I, cls.LookupInstanceField(field_name));
2192 if (field.IsNull()) { 2192 if (field.IsNull()) {
2193 ReportError(field_pos, "unresolved reference to instance field '%s'", 2193 ReportError(field_pos, "unresolved reference to instance field '%s'",
2194 field_name.ToCString()); 2194 field_name.ToCString());
2195 } 2195 }
2196 CheckDuplicateFieldInit(field_pos, initialized_fields, &field);
2197 AstNode* instance = new LoadLocalNode(field_pos, receiver);
2198 EnsureExpressionTemp(); 2196 EnsureExpressionTemp();
2199 return new StoreInstanceFieldNode(field_pos, instance, field, init_expr); 2197 AstNode* instance = new(I) LoadLocalNode(field_pos, receiver);
2198 AstNode* initializer = CheckDuplicateFieldInit(field_pos,
2199 initialized_fields, instance, &field, init_expr);
2200 if (initializer == NULL) {
2201 initializer =
2202 new(I) StoreInstanceFieldNode(field_pos, instance, field, init_expr);
2203 }
2204 return initializer;
2200 } 2205 }
2201 2206
2202 2207
2203 void Parser::CheckFieldsInitialized(const Class& cls) { 2208 void Parser::CheckFieldsInitialized(const Class& cls) {
2204 const Array& fields = Array::Handle(I, cls.fields()); 2209 const Array& fields = Array::Handle(I, cls.fields());
2205 Field& field = Field::Handle(I); 2210 Field& field = Field::Handle(I);
2206 SequenceNode* initializers = current_block_->statements; 2211 SequenceNode* initializers = current_block_->statements;
2207 for (int field_num = 0; field_num < fields.Length(); field_num++) { 2212 for (int field_num = 0; field_num < fields.Length(); field_num++) {
2208 field ^= fields.At(field_num); 2213 field ^= fields.At(field_num);
2209 if (field.is_static()) { 2214 if (field.is_static()) {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
2310 AstNode* instance = new LoadLocalNode(field.token_pos(), receiver); 2315 AstNode* instance = new LoadLocalNode(field.token_pos(), receiver);
2311 EnsureExpressionTemp(); 2316 EnsureExpressionTemp();
2312 AstNode* field_init = 2317 AstNode* field_init =
2313 new StoreInstanceFieldNode(field.token_pos(), 2318 new StoreInstanceFieldNode(field.token_pos(),
2314 instance, 2319 instance,
2315 field, 2320 field,
2316 init_expr); 2321 init_expr);
2317 current_block_->statements->Add(field_init); 2322 current_block_->statements->Add(field_init);
2318 } 2323 }
2319 } 2324 }
2325 initialized_fields->Add(NULL); // End of inline initializers.
2320 SetPosition(saved_pos); 2326 SetPosition(saved_pos);
2321 } 2327 }
2322 2328
2323 2329
2324 void Parser::CheckDuplicateFieldInit(intptr_t init_pos, 2330 AstNode* Parser::CheckDuplicateFieldInit(
2325 GrowableArray<Field*>* initialized_fields, 2331 intptr_t init_pos,
2326 Field* field) { 2332 GrowableArray<Field*>* initialized_fields,
2333 AstNode* instance,
2334 Field* field,
2335 AstNode* init_value) {
2327 ASSERT(!field->is_static()); 2336 ASSERT(!field->is_static());
2328 for (int i = 0; i < initialized_fields->length(); i++) { 2337 AstNode* result = NULL;
2329 Field* initialized_field = (*initialized_fields)[i]; 2338
2339 // The initializer_list is divided into two sections. The sections
2340 // are separated by a NULL entry: [f0, ... fn, NULL, fn+1, ...]
2341 // The first fields f0 .. fn are final fields of the class that
2342 // have an initializer expression inlined in the class declaration.
2343 // The remaining fields are those initialized by the constructor's
2344 // initializing formals and initializer list
2345 int initializer_idx = 0;
2346 while (initializer_idx < initialized_fields->length()) {
2347 Field* initialized_field = (*initialized_fields)[initializer_idx];
2348 initializer_idx++;
2349 if (initialized_field == NULL) {
2350 break;
2351 }
2352 if (initialized_field->raw() == field->raw()) {
2353 // This final field has been initialized by an inlined
2354 // initializer expression. This is a runtime error.
2355 // Throw a NoSuchMethodError for the missing setter.
2356 ASSERT(field->is_final());
2357
2358 // Build a call to NoSuchMethodError::_throwNew(
2359 // Object receiver,
2360 // String memberName,
2361 // int invocation_type,
2362 // List arguments,
2363 // List argumentNames,
2364 // List existingArgumentNames);
2365
2366 ArgumentListNode* nsm_args = new(I) ArgumentListNode(init_pos);
2367 // Object receiver.
2368 nsm_args->Add(instance);
2369
2370 // String memberName.
2371 String& setter_name = String::ZoneHandle(field->name());
2372 setter_name = Field::SetterSymbol(setter_name);
2373 nsm_args->Add(new(I) LiteralNode(init_pos, setter_name));
2374
2375 // Smi invocation_type.
2376 const int invocation_type =
2377 InvocationMirror::EncodeType(InvocationMirror::kDynamic,
2378 InvocationMirror::kSetter);
2379 nsm_args->Add(new(I) LiteralNode(
2380 init_pos, Smi::ZoneHandle(I, Smi::New(invocation_type))));
2381
2382 // List arguments.
2383 GrowableArray<AstNode*> setter_args;
2384 setter_args.Add(init_value);
2385 ArrayNode* setter_args_array = new(I) ArrayNode(
2386 init_pos,
2387 Type::ZoneHandle(I, Type::ArrayType()),
2388 setter_args);
2389 nsm_args->Add(setter_args_array);
2390
2391 // List argumentNames.
2392 // The missing implicit setter of the field has no argument names.
2393 nsm_args->Add(new(I) LiteralNode(init_pos, Array::ZoneHandle(I)));
2394
2395 // List existingArgumentNames.
2396 // There is no setter for the final field, thus there are
2397 // no existing names.
2398 nsm_args->Add(new(I) LiteralNode(init_pos, Array::ZoneHandle(I)));
2399
2400 AstNode* nsm_call =
2401 MakeStaticCall(Symbols::NoSuchMethodError(),
2402 Library::PrivateCoreLibName(Symbols::ThrowNew()),
2403 nsm_args);
2404
2405 LetNode* let = new(I) LetNode(init_pos);
2406 let->AddNode(init_value);
2407 let->AddNode(nsm_call);
2408 result = let;
2409 }
2410 }
2411 // The remaining elements in initialized_fields are fields that
2412 // are initialized through initializing formal parameters, or
2413 // in the constructor's initializer list. If there is a duplicate,
2414 // it is a compile time error.
2415 while (initializer_idx < initialized_fields->length()) {
2416 Field* initialized_field = (*initialized_fields)[initializer_idx];
2417 initializer_idx++;
2330 if (initialized_field->raw() == field->raw()) { 2418 if (initialized_field->raw() == field->raw()) {
2331 ReportError(init_pos, 2419 ReportError(init_pos,
2332 "duplicate initialization for field %s", 2420 "duplicate initializer for field %s",
2333 String::Handle(I, field->name()).ToCString()); 2421 String::Handle(I, field->name()).ToCString());
2334 } 2422 }
2335 } 2423 }
2336 initialized_fields->Add(field); 2424 initialized_fields->Add(field);
2425 return result;
2337 } 2426 }
2338 2427
2339 2428
2340 void Parser::ParseInitializers(const Class& cls, 2429 void Parser::ParseInitializers(const Class& cls,
2341 LocalVariable* receiver, 2430 LocalVariable* receiver,
2342 GrowableArray<Field*>* initialized_fields) { 2431 GrowableArray<Field*>* initialized_fields) {
2343 TRACE_PARSER("ParseInitializers"); 2432 TRACE_PARSER("ParseInitializers");
2344 bool super_init_seen = false; 2433 bool super_init_seen = false;
2345 if (CurrentToken() == Token::kCOLON) { 2434 if (CurrentToken() == Token::kCOLON) {
2346 do { 2435 do {
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
2603 if (field.IsNull()) { 2692 if (field.IsNull()) {
2604 ReportError(param.name_pos, 2693 ReportError(param.name_pos,
2605 "unresolved reference to instance field '%s'", 2694 "unresolved reference to instance field '%s'",
2606 field_name.ToCString()); 2695 field_name.ToCString());
2607 } 2696 }
2608 if (is_redirecting_constructor) { 2697 if (is_redirecting_constructor) {
2609 ReportError(param.name_pos, 2698 ReportError(param.name_pos,
2610 "redirecting constructors may not have " 2699 "redirecting constructors may not have "
2611 "initializing formal parameters"); 2700 "initializing formal parameters");
2612 } 2701 }
2613 CheckDuplicateFieldInit(param.name_pos, &initialized_fields, &field);
2614 2702
2615 if (!param.has_explicit_type) { 2703 if (!param.has_explicit_type) {
2616 const AbstractType& field_type = 2704 const AbstractType& field_type =
2617 AbstractType::ZoneHandle(I, field.type()); 2705 AbstractType::ZoneHandle(I, field.type());
2618 param.type = &field_type; 2706 param.type = &field_type;
2619 // Parameter type was already set to dynamic when parsing the class 2707 // Parameter type was already set to dynamic when parsing the class
2620 // declaration: fix it. 2708 // declaration: fix it.
2621 func.SetParameterTypeAt(i, field_type); 2709 func.SetParameterTypeAt(i, field_type);
2622 } 2710 }
2623 2711
2624 AstNode* instance = new LoadLocalNode(param.name_pos, receiver); 2712 AstNode* instance = new LoadLocalNode(param.name_pos, receiver);
2625 // Initializing formals cannot be used in the explicit initializer 2713 // Initializing formals cannot be used in the explicit initializer
2626 // list, nor can they be used in the constructor body. 2714 // list, nor can they be used in the constructor body.
2627 // Thus, they are set to be invisible when added to the scope. 2715 // Thus, they are set to be invisible when added to the scope.
2628 LocalVariable* p = param.var; 2716 LocalVariable* p = param.var;
2629 ASSERT(p != NULL); 2717 ASSERT(p != NULL);
2630 ASSERT(p->is_invisible()); 2718 ASSERT(p->is_invisible());
2631 AstNode* value = new LoadLocalNode(param.name_pos, p); 2719 AstNode* value = new LoadLocalNode(param.name_pos, p);
2632 EnsureExpressionTemp(); 2720 EnsureExpressionTemp();
2633 AstNode* initializer = new StoreInstanceFieldNode( 2721 AstNode* initializer =
2634 param.name_pos, instance, field, value); 2722 CheckDuplicateFieldInit(param.name_pos,
2723 &initialized_fields,
2724 instance,
2725 &field,
2726 value);
2727 if (initializer == NULL) {
2728 initializer = new(I) StoreInstanceFieldNode(
2729 param.name_pos, instance, field, value);
2730 }
2635 current_block_->statements->Add(initializer); 2731 current_block_->statements->Add(initializer);
2636 } 2732 }
2637 } 2733 }
2638 } 2734 }
2639 2735
2640 if (is_redirecting_constructor) { 2736 if (is_redirecting_constructor) {
2641 ParseConstructorRedirection(cls, receiver); 2737 ParseConstructorRedirection(cls, receiver);
2642 } else { 2738 } else {
2643 ParseInitializers(cls, receiver, &initialized_fields); 2739 ParseInitializers(cls, receiver, &initialized_fields);
2644 } 2740 }
(...skipping 8742 matching lines...) Expand 10 before | Expand all | Expand 10 after
11387 void Parser::SkipQualIdent() { 11483 void Parser::SkipQualIdent() {
11388 ASSERT(IsIdentifier()); 11484 ASSERT(IsIdentifier());
11389 ConsumeToken(); 11485 ConsumeToken();
11390 if (CurrentToken() == Token::kPERIOD) { 11486 if (CurrentToken() == Token::kPERIOD) {
11391 ConsumeToken(); // Consume the kPERIOD token. 11487 ConsumeToken(); // Consume the kPERIOD token.
11392 ExpectIdentifier("identifier expected after '.'"); 11488 ExpectIdentifier("identifier expected after '.'");
11393 } 11489 }
11394 } 11490 }
11395 11491
11396 } // namespace dart 11492 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/co19/co19-co19.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698