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

Side by Side Diff: src/scopes.cc

Issue 943543002: [strong] Declaration-after-use errors. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: minimizing diff Created 5 years, 10 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
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/scopes.h" 7 #include "src/scopes.h"
8 8
9 #include "src/accessors.h" 9 #include "src/accessors.h"
10 #include "src/bootstrapper.h" 10 #include "src/bootstrapper.h"
(...skipping 16 matching lines...) Expand all
27 VariableMap::VariableMap(Zone* zone) 27 VariableMap::VariableMap(Zone* zone)
28 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), 28 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)),
29 zone_(zone) {} 29 zone_(zone) {}
30 VariableMap::~VariableMap() {} 30 VariableMap::~VariableMap() {}
31 31
32 32
33 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, 33 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name,
34 VariableMode mode, bool is_valid_lhs, 34 VariableMode mode, bool is_valid_lhs,
35 Variable::Kind kind, 35 Variable::Kind kind,
36 InitializationFlag initialization_flag, 36 InitializationFlag initialization_flag,
37 int position,
37 MaybeAssignedFlag maybe_assigned_flag) { 38 MaybeAssignedFlag maybe_assigned_flag) {
38 // AstRawStrings are unambiguous, i.e., the same string is always represented 39 // AstRawStrings are unambiguous, i.e., the same string is always represented
39 // by the same AstRawString*. 40 // by the same AstRawString*.
40 // FIXME(marja): fix the type of Lookup. 41 // FIXME(marja): fix the type of Lookup.
41 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), 42 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(),
42 true, ZoneAllocationPolicy(zone())); 43 true, ZoneAllocationPolicy(zone()));
43 if (p->value == NULL) { 44 if (p->value == NULL) {
44 // The variable has not been declared yet -> insert it. 45 // The variable has not been declared yet -> insert it.
45 DCHECK(p->key == name); 46 DCHECK(p->key == name);
46 p->value = new (zone()) Variable(scope, name, mode, is_valid_lhs, kind, 47 Variable* variable =
47 initialization_flag, maybe_assigned_flag); 48 new (zone()) Variable(scope, name, mode, is_valid_lhs, kind,
49 initialization_flag, maybe_assigned_flag);
50 variable->set_initializer_position(position);
51 p->value = variable;
48 } 52 }
49 return reinterpret_cast<Variable*>(p->value); 53 return reinterpret_cast<Variable*>(p->value);
50 } 54 }
51 55
52 56
53 Variable* VariableMap::Lookup(const AstRawString* name) { 57 Variable* VariableMap::Lookup(const AstRawString* name) {
54 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), 58 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(),
55 false, ZoneAllocationPolicy(NULL)); 59 false, ZoneAllocationPolicy(NULL));
56 if (p != NULL) { 60 if (p != NULL) {
57 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); 61 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name);
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 // Traverse the scope tree up to the first unresolved scope or the global 260 // Traverse the scope tree up to the first unresolved scope or the global
257 // scope and start scope resolution and variable allocation from that scope. 261 // scope and start scope resolution and variable allocation from that scope.
258 while (!top->is_script_scope() && 262 while (!top->is_script_scope() &&
259 !top->outer_scope()->already_resolved()) { 263 !top->outer_scope()->already_resolved()) {
260 top = top->outer_scope(); 264 top = top->outer_scope();
261 } 265 }
262 266
263 // Allocate the variables. 267 // Allocate the variables.
264 { 268 {
265 AstNodeFactory ast_node_factory(info->ast_value_factory()); 269 AstNodeFactory ast_node_factory(info->ast_value_factory());
266 if (!top->AllocateVariables(info, &ast_node_factory)) return false; 270 if (!top->AllocateVariables(info, &ast_node_factory)) {
271 DCHECK(top->pending_error_handler_.has_pending_error());
272 top->pending_error_handler_.ThrowPendingError(info->isolate(),
273 info->script());
274 return false;
275 }
267 } 276 }
268 277
269 #ifdef DEBUG 278 #ifdef DEBUG
270 if (info->isolate()->bootstrapper()->IsActive() 279 if (info->isolate()->bootstrapper()->IsActive()
271 ? FLAG_print_builtin_scopes 280 ? FLAG_print_builtin_scopes
272 : FLAG_print_scopes) { 281 : FLAG_print_scopes) {
273 scope->Print(); 282 scope->Print();
274 } 283 }
275 #endif 284 #endif
276 285
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 404
396 mode = DYNAMIC; 405 mode = DYNAMIC;
397 location = Variable::LOOKUP; 406 location = Variable::LOOKUP;
398 init_flag = kCreatedInitialized; 407 init_flag = kCreatedInitialized;
399 // Be conservative and flag parameters as maybe assigned. Better information 408 // Be conservative and flag parameters as maybe assigned. Better information
400 // would require ScopeInfo to serialize the maybe_assigned bit also for 409 // would require ScopeInfo to serialize the maybe_assigned bit also for
401 // parameters. 410 // parameters.
402 maybe_assigned_flag = kMaybeAssigned; 411 maybe_assigned_flag = kMaybeAssigned;
403 } 412 }
404 413
405 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, 414 Variable* var =
406 init_flag, maybe_assigned_flag); 415 variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag,
416 RelocInfo::kNoPosition, maybe_assigned_flag);
407 var->AllocateTo(location, index); 417 var->AllocateTo(location, index);
408 return var; 418 return var;
409 } 419 }
410 420
411 421
412 Variable* Scope::LookupFunctionVar(const AstRawString* name, 422 Variable* Scope::LookupFunctionVar(const AstRawString* name,
413 AstNodeFactory* factory) { 423 AstNodeFactory* factory) {
414 if (function_ != NULL && function_->proxy()->raw_name() == name) { 424 if (function_ != NULL && function_->proxy()->raw_name() == name) {
415 return function_->proxy()->var(); 425 return function_->proxy()->var();
416 } else if (!scope_info_.is_null()) { 426 } else if (!scope_info_.is_null()) {
417 // If we are backed by a scope info, try to lookup the variable there. 427 // If we are backed by a scope info, try to lookup the variable there.
418 VariableMode mode; 428 VariableMode mode;
419 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); 429 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
420 if (index < 0) return NULL; 430 if (index < 0) return NULL;
421 Variable* var = new(zone()) Variable( 431 Variable* var =
422 this, name, mode, true /* is valid LHS */, 432 new (zone()) Variable(this, name, mode, true /* is valid LHS */,
423 Variable::NORMAL, kCreatedInitialized); 433 Variable::NORMAL, kCreatedInitialized);
424 VariableProxy* proxy = factory->NewVariableProxy(var); 434 VariableProxy* proxy = factory->NewVariableProxy(var);
425 VariableDeclaration* declaration = factory->NewVariableDeclaration( 435 VariableDeclaration* declaration = factory->NewVariableDeclaration(
426 proxy, mode, this, RelocInfo::kNoPosition); 436 proxy, mode, this, RelocInfo::kNoPosition);
427 DeclareFunctionVar(declaration); 437 DeclareFunctionVar(declaration);
428 var->AllocateTo(Variable::CONTEXT, index); 438 var->AllocateTo(Variable::CONTEXT, index);
429 return var; 439 return var;
430 } else { 440 } else {
431 return NULL; 441 return NULL;
432 } 442 }
433 } 443 }
(...skipping 20 matching lines...) Expand all
454 DCHECK_NULL(rest_parameter_); 464 DCHECK_NULL(rest_parameter_);
455 rest_parameter_ = var; 465 rest_parameter_ = var;
456 rest_index_ = num_parameters(); 466 rest_index_ = num_parameters();
457 } 467 }
458 params_.Add(var, zone()); 468 params_.Add(var, zone());
459 return var; 469 return var;
460 } 470 }
461 471
462 472
463 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, 473 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
464 InitializationFlag init_flag, 474 InitializationFlag init_flag, int position,
475 bool is_function,
465 MaybeAssignedFlag maybe_assigned_flag) { 476 MaybeAssignedFlag maybe_assigned_flag) {
466 DCHECK(!already_resolved()); 477 DCHECK(!already_resolved());
467 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are 478 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are
468 // introduces during variable allocation, INTERNAL variables are allocated 479 // introduces during variable allocation, INTERNAL variables are allocated
469 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). 480 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
470 DCHECK(IsDeclaredVariableMode(mode)); 481 DCHECK(IsDeclaredVariableMode(mode));
471 ++num_var_or_const_; 482 ++num_var_or_const_;
472 return variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, 483 return variables_.Declare(this, name, mode, true,
473 maybe_assigned_flag); 484 is_function ? Variable::FUNCTION : Variable::NORMAL,
485 init_flag, position, maybe_assigned_flag);
474 } 486 }
475 487
476 488
477 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { 489 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
478 DCHECK(is_script_scope()); 490 DCHECK(is_script_scope());
479 return variables_.Declare(this, 491 return variables_.Declare(this,
480 name, 492 name,
481 DYNAMIC_GLOBAL, 493 DYNAMIC_GLOBAL,
482 true, 494 true,
483 Variable::NORMAL, 495 Variable::NORMAL,
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 int end_pos = scope->end_position(); 773 int end_pos = scope->end_position();
762 DCHECK(beg_pos >= 0 && end_pos >= 0); 774 DCHECK(beg_pos >= 0 && end_pos >= 0);
763 if (beg_pos <= position && position < end_pos) { 775 if (beg_pos <= position && position < end_pos) {
764 scope->GetNestedScopeChain(isolate, chain, position); 776 scope->GetNestedScopeChain(isolate, chain, position);
765 return; 777 return;
766 } 778 }
767 } 779 }
768 } 780 }
769 781
770 782
783 void Scope::ReportMessage(int start_position, int end_position,
784 const char* message, const AstRawString* arg) {
785 // Propagate the error to the topmost scope targeted by this scope analysis
786 // phase.
787 Scope* top = this;
788 while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) {
789 top = top->outer_scope();
790 }
791
792 top->pending_error_handler_.ReportMessageAt(start_position, end_position,
793 message, arg, kReferenceError);
794 }
795
796
771 #ifdef DEBUG 797 #ifdef DEBUG
772 static const char* Header(ScopeType scope_type) { 798 static const char* Header(ScopeType scope_type) {
773 switch (scope_type) { 799 switch (scope_type) {
774 case EVAL_SCOPE: return "eval"; 800 case EVAL_SCOPE: return "eval";
775 case FUNCTION_SCOPE: return "function"; 801 case FUNCTION_SCOPE: return "function";
776 case MODULE_SCOPE: return "module"; 802 case MODULE_SCOPE: return "module";
777 case SCRIPT_SCOPE: return "global"; 803 case SCRIPT_SCOPE: return "global";
778 case CATCH_SCOPE: return "catch"; 804 case CATCH_SCOPE: return "catch";
779 case BLOCK_SCOPE: return "block"; 805 case BLOCK_SCOPE: return "block";
780 case WITH_SCOPE: return "with"; 806 case WITH_SCOPE: return "with";
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
1043 // If the proxy is already resolved there's nothing to do 1069 // If the proxy is already resolved there's nothing to do
1044 // (functions and consts may be resolved by the parser). 1070 // (functions and consts may be resolved by the parser).
1045 if (proxy->is_resolved()) return true; 1071 if (proxy->is_resolved()) return true;
1046 1072
1047 // Otherwise, try to resolve the variable. 1073 // Otherwise, try to resolve the variable.
1048 BindingKind binding_kind; 1074 BindingKind binding_kind;
1049 Variable* var = LookupRecursive(proxy, &binding_kind, factory); 1075 Variable* var = LookupRecursive(proxy, &binding_kind, factory);
1050 switch (binding_kind) { 1076 switch (binding_kind) {
1051 case BOUND: 1077 case BOUND:
1052 // We found a variable binding. 1078 // We found a variable binding.
1079 if (is_strong(language_mode())) {
1080 // Check for declaration-after use (for variables) in strong mode. Note
1081 // that we can only do this in the case where we have seen the
1082 // declaration. And we always allow referencing functions (for now).
1083
1084 // If both the use and the declaration are inside an eval scope
1085 // (possibly indirectly), or one of them is, we need to check whether
1086 // they are inside the same eval scope or different
1087 // ones. TODO(marja,rossberg): Detect errors across different evals
1088 // (depends on the future of eval in strong mode).
1089 const Scope* eval_for_use = NearestOuterEvalScope();
1090 const Scope* eval_for_declaration =
1091 var->scope()->NearestOuterEvalScope();
1092
1093 if (proxy->position() != RelocInfo::kNoPosition &&
1094 proxy->position() < var->initializer_position() &&
1095 !var->is_function() && eval_for_use == eval_for_declaration) {
1096 DCHECK(proxy->end_position() != RelocInfo::kNoPosition);
1097 ReportMessage(proxy->position(), proxy->end_position(),
1098 "strong_use_before_declaration", proxy->raw_name());
1099 return false;
1100 }
1101 }
1053 break; 1102 break;
1054 1103
1055 case BOUND_EVAL_SHADOWED: 1104 case BOUND_EVAL_SHADOWED:
1056 // We either found a variable binding that might be shadowed by eval or 1105 // We either found a variable binding that might be shadowed by eval or
1057 // gave up on it (e.g. by encountering a local with the same in the outer 1106 // gave up on it (e.g. by encountering a local with the same in the outer
1058 // scope which was not promoted to a context, this can happen if we use 1107 // scope which was not promoted to a context, this can happen if we use
1059 // debugger to evaluate arbitrary expressions at a break point). 1108 // debugger to evaluate arbitrary expressions at a break point).
1060 if (var->IsGlobalObjectProperty()) { 1109 if (var->IsGlobalObjectProperty()) {
1061 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); 1110 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
1062 } else if (var->is_dynamic()) { 1111 } else if (var->is_dynamic()) {
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after
1381 } 1430 }
1382 1431
1383 1432
1384 int Scope::ContextLocalCount() const { 1433 int Scope::ContextLocalCount() const {
1385 if (num_heap_slots() == 0) return 0; 1434 if (num_heap_slots() == 0) return 0;
1386 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - 1435 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
1387 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); 1436 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
1388 } 1437 }
1389 1438
1390 } } // namespace v8::internal 1439 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698