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

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: more fixes + tests 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 p->value = new (zone())
47 initialization_flag, maybe_assigned_flag); 48 Variable(scope, name, mode, is_valid_lhs, kind, initialization_flag,
49 position, maybe_assigned_flag);
48 } 50 }
49 return reinterpret_cast<Variable*>(p->value); 51 return reinterpret_cast<Variable*>(p->value);
50 } 52 }
51 53
52 54
53 Variable* VariableMap::Lookup(const AstRawString* name) { 55 Variable* VariableMap::Lookup(const AstRawString* name) {
54 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), 56 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(),
55 false, ZoneAllocationPolicy(NULL)); 57 false, ZoneAllocationPolicy(NULL));
56 if (p != NULL) { 58 if (p != NULL) {
57 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); 59 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 258 // 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. 259 // scope and start scope resolution and variable allocation from that scope.
258 while (!top->is_script_scope() && 260 while (!top->is_script_scope() &&
259 !top->outer_scope()->already_resolved()) { 261 !top->outer_scope()->already_resolved()) {
260 top = top->outer_scope(); 262 top = top->outer_scope();
261 } 263 }
262 264
263 // Allocate the variables. 265 // Allocate the variables.
264 { 266 {
265 AstNodeFactory ast_node_factory(info->ast_value_factory()); 267 AstNodeFactory ast_node_factory(info->ast_value_factory());
266 if (!top->AllocateVariables(info, &ast_node_factory)) return false; 268 if (!top->AllocateVariables(info, &ast_node_factory)) {
269 DCHECK(top->pending_error_handler_.has_pending_error());
270 top->pending_error_handler_.ThrowPendingError(info->isolate(),
271 info->script());
272 return false;
273 }
267 } 274 }
268 275
269 #ifdef DEBUG 276 #ifdef DEBUG
270 if (info->isolate()->bootstrapper()->IsActive() 277 if (info->isolate()->bootstrapper()->IsActive()
271 ? FLAG_print_builtin_scopes 278 ? FLAG_print_builtin_scopes
272 : FLAG_print_scopes) { 279 : FLAG_print_scopes) {
273 scope->Print(); 280 scope->Print();
274 } 281 }
275 #endif 282 #endif
276 283
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 402
396 mode = DYNAMIC; 403 mode = DYNAMIC;
397 location = Variable::LOOKUP; 404 location = Variable::LOOKUP;
398 init_flag = kCreatedInitialized; 405 init_flag = kCreatedInitialized;
399 // Be conservative and flag parameters as maybe assigned. Better information 406 // Be conservative and flag parameters as maybe assigned. Better information
400 // would require ScopeInfo to serialize the maybe_assigned bit also for 407 // would require ScopeInfo to serialize the maybe_assigned bit also for
401 // parameters. 408 // parameters.
402 maybe_assigned_flag = kMaybeAssigned; 409 maybe_assigned_flag = kMaybeAssigned;
403 } 410 }
404 411
405 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, 412 Variable* var =
406 init_flag, maybe_assigned_flag); 413 variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag,
414 RelocInfo::kNoPosition, maybe_assigned_flag);
407 var->AllocateTo(location, index); 415 var->AllocateTo(location, index);
408 return var; 416 return var;
409 } 417 }
410 418
411 419
412 Variable* Scope::LookupFunctionVar(const AstRawString* name, 420 Variable* Scope::LookupFunctionVar(const AstRawString* name,
413 AstNodeFactory* factory) { 421 AstNodeFactory* factory) {
414 if (function_ != NULL && function_->proxy()->raw_name() == name) { 422 if (function_ != NULL && function_->proxy()->raw_name() == name) {
415 return function_->proxy()->var(); 423 return function_->proxy()->var();
416 } else if (!scope_info_.is_null()) { 424 } else if (!scope_info_.is_null()) {
417 // If we are backed by a scope info, try to lookup the variable there. 425 // If we are backed by a scope info, try to lookup the variable there.
418 VariableMode mode; 426 VariableMode mode;
419 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); 427 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode);
420 if (index < 0) return NULL; 428 if (index < 0) return NULL;
421 Variable* var = new(zone()) Variable( 429 Variable* var = new (zone())
422 this, name, mode, true /* is valid LHS */, 430 Variable(this, name, mode, true /* is valid LHS */, Variable::FUNCTION,
423 Variable::NORMAL, kCreatedInitialized); 431 kCreatedInitialized, RelocInfo::kNoPosition);
424 VariableProxy* proxy = factory->NewVariableProxy(var); 432 VariableProxy* proxy = factory->NewVariableProxy(var);
425 VariableDeclaration* declaration = factory->NewVariableDeclaration( 433 VariableDeclaration* declaration = factory->NewVariableDeclaration(
426 proxy, mode, this, RelocInfo::kNoPosition); 434 proxy, mode, this, RelocInfo::kNoPosition);
427 DeclareFunctionVar(declaration); 435 DeclareFunctionVar(declaration);
428 var->AllocateTo(Variable::CONTEXT, index); 436 var->AllocateTo(Variable::CONTEXT, index);
429 return var; 437 return var;
430 } else { 438 } else {
431 return NULL; 439 return NULL;
432 } 440 }
433 } 441 }
(...skipping 20 matching lines...) Expand all
454 DCHECK_NULL(rest_parameter_); 462 DCHECK_NULL(rest_parameter_);
455 rest_parameter_ = var; 463 rest_parameter_ = var;
456 rest_index_ = num_parameters(); 464 rest_index_ = num_parameters();
457 } 465 }
458 params_.Add(var, zone()); 466 params_.Add(var, zone());
459 return var; 467 return var;
460 } 468 }
461 469
462 470
463 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, 471 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
464 InitializationFlag init_flag, 472 InitializationFlag init_flag, int position,
473 bool is_function,
465 MaybeAssignedFlag maybe_assigned_flag) { 474 MaybeAssignedFlag maybe_assigned_flag) {
466 DCHECK(!already_resolved()); 475 DCHECK(!already_resolved());
467 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are 476 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are
468 // introduces during variable allocation, INTERNAL variables are allocated 477 // introduces during variable allocation, INTERNAL variables are allocated
469 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). 478 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
470 DCHECK(IsDeclaredVariableMode(mode)); 479 DCHECK(IsDeclaredVariableMode(mode));
471 ++num_var_or_const_; 480 ++num_var_or_const_;
472 return variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, 481 return variables_.Declare(this, name, mode, true,
473 maybe_assigned_flag); 482 is_function ? Variable::FUNCTION : Variable::NORMAL,
483 init_flag, position, maybe_assigned_flag);
474 } 484 }
475 485
476 486
477 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { 487 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) {
478 DCHECK(is_script_scope()); 488 DCHECK(is_script_scope());
479 return variables_.Declare(this, 489 return variables_.Declare(this,
480 name, 490 name,
481 DYNAMIC_GLOBAL, 491 DYNAMIC_GLOBAL,
482 true, 492 true,
483 Variable::NORMAL, 493 Variable::NORMAL,
484 kCreatedInitialized); 494 kCreatedInitialized);
485 } 495 }
486 496
487 497
488 void Scope::RemoveUnresolved(VariableProxy* var) { 498 void Scope::RemoveUnresolved(VariableProxy* var) {
489 // Most likely (always?) any variable we want to remove 499 // Most likely (always?) any variable we want to remove
490 // was just added before, so we search backwards. 500 // was just added before, so we search backwards.
491 for (int i = unresolved_.length(); i-- > 0;) { 501 for (int i = unresolved_.length(); i-- > 0;) {
492 if (unresolved_[i] == var) { 502 if (unresolved_[i] == var) {
493 unresolved_.Remove(i); 503 unresolved_.Remove(i);
494 return; 504 return;
495 } 505 }
496 } 506 }
497 } 507 }
498 508
499 509
500 Variable* Scope::NewInternal(const AstRawString* name) { 510 Variable* Scope::NewInternal(const AstRawString* name) {
501 DCHECK(!already_resolved()); 511 DCHECK(!already_resolved());
502 Variable* var = new(zone()) Variable(this, 512 Variable* var =
503 name, 513 new (zone()) Variable(this, name, INTERNAL, false, Variable::NORMAL,
504 INTERNAL, 514 kCreatedInitialized, RelocInfo::kNoPosition);
505 false,
506 Variable::NORMAL,
507 kCreatedInitialized);
508 internals_.Add(var, zone()); 515 internals_.Add(var, zone());
509 return var; 516 return var;
510 } 517 }
511 518
512 519
513 Variable* Scope::NewTemporary(const AstRawString* name) { 520 Variable* Scope::NewTemporary(const AstRawString* name) {
514 DCHECK(!already_resolved()); 521 DCHECK(!already_resolved());
515 Variable* var = new(zone()) Variable(this, 522 Variable* var =
516 name, 523 new (zone()) Variable(this, name, TEMPORARY, true, Variable::NORMAL,
517 TEMPORARY, 524 kCreatedInitialized, RelocInfo::kNoPosition);
518 true,
519 Variable::NORMAL,
520 kCreatedInitialized);
521 temps_.Add(var, zone()); 525 temps_.Add(var, zone());
522 return var; 526 return var;
523 } 527 }
524 528
525 529
526 void Scope::AddDeclaration(Declaration* declaration) { 530 void Scope::AddDeclaration(Declaration* declaration) {
527 decls_.Add(declaration, zone()); 531 decls_.Add(declaration, zone());
528 } 532 }
529 533
530 534
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 int end_pos = scope->end_position(); 765 int end_pos = scope->end_position();
762 DCHECK(beg_pos >= 0 && end_pos >= 0); 766 DCHECK(beg_pos >= 0 && end_pos >= 0);
763 if (beg_pos <= position && position < end_pos) { 767 if (beg_pos <= position && position < end_pos) {
764 scope->GetNestedScopeChain(isolate, chain, position); 768 scope->GetNestedScopeChain(isolate, chain, position);
765 return; 769 return;
766 } 770 }
767 } 771 }
768 } 772 }
769 773
770 774
775 void Scope::ReportMessage(int start_position, int end_position,
776 const char* message, const AstRawString* arg) {
777 // Propagate the error to the topmost scope targeted by this scope analysis
778 // phase.
779 Scope* top = this;
780 while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) {
781 top = top->outer_scope();
782 }
783
784 top->pending_error_handler_.ReportMessageAt(start_position, end_position,
785 message, arg, kReferenceError);
786 }
787
788
771 #ifdef DEBUG 789 #ifdef DEBUG
772 static const char* Header(ScopeType scope_type) { 790 static const char* Header(ScopeType scope_type) {
773 switch (scope_type) { 791 switch (scope_type) {
774 case EVAL_SCOPE: return "eval"; 792 case EVAL_SCOPE: return "eval";
775 case FUNCTION_SCOPE: return "function"; 793 case FUNCTION_SCOPE: return "function";
776 case MODULE_SCOPE: return "module"; 794 case MODULE_SCOPE: return "module";
777 case SCRIPT_SCOPE: return "global"; 795 case SCRIPT_SCOPE: return "global";
778 case CATCH_SCOPE: return "catch"; 796 case CATCH_SCOPE: return "catch";
779 case BLOCK_SCOPE: return "block"; 797 case BLOCK_SCOPE: return "block";
780 case WITH_SCOPE: return "with"; 798 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 1061 // If the proxy is already resolved there's nothing to do
1044 // (functions and consts may be resolved by the parser). 1062 // (functions and consts may be resolved by the parser).
1045 if (proxy->is_resolved()) return true; 1063 if (proxy->is_resolved()) return true;
1046 1064
1047 // Otherwise, try to resolve the variable. 1065 // Otherwise, try to resolve the variable.
1048 BindingKind binding_kind; 1066 BindingKind binding_kind;
1049 Variable* var = LookupRecursive(proxy, &binding_kind, factory); 1067 Variable* var = LookupRecursive(proxy, &binding_kind, factory);
1050 switch (binding_kind) { 1068 switch (binding_kind) {
1051 case BOUND: 1069 case BOUND:
1052 // We found a variable binding. 1070 // We found a variable binding.
1071 if (is_strong(language_mode())) {
1072 // Check for declaration-after use (for variables) in strong mode. Note
1073 // that we can only do this in the case where we have seen the
1074 // declaration. And we always allow referencing functions (for now).
1075
1076 // If both the use and the declaration are inside an eval scope
1077 // (possibly indirectly), or one of them is, we need to check whether
1078 // they are inside the same eval scope or different ones.
rossberg 2015/02/23 13:45:26 Can you add a TODO regarding different evals? I su
marja 2015/02/24 13:29:34 Added a todo. So one error case is: This throws:
1079 const Scope* eval_for_use = NearestOuterEvalScope();
1080 const Scope* eval_for_declaration =
1081 var->scope()->NearestOuterEvalScope();
1082
1083 if (proxy->position() != RelocInfo::kNoPosition &&
1084 proxy->position() < var->position() && !var->is_function() &&
rossberg 2015/02/23 13:45:26 I don't believe this is good enough. Consider:
marja 2015/02/24 13:29:35 Fixed this to use initializer_position(), undid th
1085 eval_for_use == eval_for_declaration) {
1086 DCHECK(proxy->end_position() != RelocInfo::kNoPosition);
1087 ReportMessage(proxy->position(), proxy->end_position(),
1088 "strong_use_before_declaration", proxy->raw_name());
1089 return false;
1090 }
1091 }
1053 break; 1092 break;
1054 1093
1055 case BOUND_EVAL_SHADOWED: 1094 case BOUND_EVAL_SHADOWED:
1056 // We either found a variable binding that might be shadowed by eval or 1095 // 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 1096 // 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 1097 // scope which was not promoted to a context, this can happen if we use
1059 // debugger to evaluate arbitrary expressions at a break point). 1098 // debugger to evaluate arbitrary expressions at a break point).
1060 if (var->IsGlobalObjectProperty()) { 1099 if (var->IsGlobalObjectProperty()) {
1061 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); 1100 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL);
1062 } else if (var->is_dynamic()) { 1101 } else if (var->is_dynamic()) {
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after
1381 } 1420 }
1382 1421
1383 1422
1384 int Scope::ContextLocalCount() const { 1423 int Scope::ContextLocalCount() const {
1385 if (num_heap_slots() == 0) return 0; 1424 if (num_heap_slots() == 0) return 0;
1386 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - 1425 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
1387 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); 1426 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
1388 } 1427 }
1389 1428
1390 } } // namespace v8::internal 1429 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698