Chromium Code Reviews| Index: src/ast/scopes.cc |
| diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc |
| index 129cbceaf5bef5c1104efa1332481c23582f7ce3..7faa0183db8fb3fd99cd2eae78de0013b596f871 100644 |
| --- a/src/ast/scopes.cc |
| +++ b/src/ast/scopes.cc |
| @@ -696,6 +696,110 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
| maybe_assigned_flag); |
| } |
| +Variable* Scope::DeclareVariable( |
| + Declaration* declaration, VariableMode mode, InitializationFlag init, |
| + bool allow_harmony_restrictive_generators, |
| + bool* sloppy_mode_block_scope_function_redefinition, bool* ok) { |
| + DCHECK(IsDeclaredVariableMode(mode) && mode != CONST_LEGACY); |
| + DCHECK(!already_resolved_); |
| + |
| + if (mode == VAR && !is_declaration_scope()) { |
| + return GetDeclarationScope()->DeclareVariable( |
| + declaration, mode, init, allow_harmony_restrictive_generators, |
| + sloppy_mode_block_scope_function_redefinition, ok); |
| + } |
| + DCHECK(!is_catch_scope()); |
| + DCHECK(!is_with_scope()); |
| + DCHECK(is_declaration_scope() || |
| + (IsLexicalVariableMode(mode) && is_block_scope())); |
| + |
| + VariableProxy* proxy = declaration->proxy(); |
| + DCHECK(proxy->raw_name() != NULL); |
| + const AstRawString* name = proxy->raw_name(); |
| + bool is_function_declaration = declaration->IsFunctionDeclaration(); |
| + |
| + Variable* var = nullptr; |
| + if (is_eval_scope() && is_sloppy(language_mode()) && mode == VAR) { |
| + // In a var binding in a sloppy direct eval, pollute the enclosing scope |
| + // with this new binding by doing the following: |
| + // The proxy is bound to a lookup variable to force a dynamic declaration |
| + // using the DeclareEvalVar or DeclareEvalFunction runtime functions. |
| + Variable::Kind kind = Variable::NORMAL; |
| + // TODO(sigurds) figure out if kNotAssigned is OK here |
| + var = new (zone()) Variable(this, name, mode, kind, init, kNotAssigned); |
| + var->AllocateTo(VariableLocation::LOOKUP, -1); |
| + } else { |
| + // Declare the variable in the declaration scope. |
| + var = LookupLocal(name); |
| + if (var == NULL) { |
| + // Declare the name. |
| + Variable::Kind kind = Variable::NORMAL; |
| + if (is_function_declaration) { |
| + kind = Variable::FUNCTION; |
| + } |
| + var = DeclareLocal(name, mode, init, kind, kNotAssigned); |
| + } else if (IsLexicalVariableMode(mode) || |
| + IsLexicalVariableMode(var->mode())) { |
| + // Allow duplicate function decls for web compat, see bug 4693. |
| + bool duplicate_allowed = false; |
| + if (is_sloppy(language_mode()) && is_function_declaration && |
| + var->is_function()) { |
| + DCHECK(IsLexicalVariableMode(mode) && |
| + IsLexicalVariableMode(var->mode())); |
| + // If the duplication is allowed, then the var will show up |
| + // in the SloppyBlockFunctionMap and the new FunctionKind |
| + // will be a permitted duplicate. |
| + FunctionKind function_kind = |
| + declaration->AsFunctionDeclaration()->fun()->kind(); |
| + duplicate_allowed = |
| + GetDeclarationScope()->sloppy_block_function_map()->Lookup( |
| + const_cast<AstRawString*>(name), name->hash()) != nullptr && |
| + !IsAsyncFunction(function_kind) && |
| + !(allow_harmony_restrictive_generators && |
| + IsGeneratorFunction(function_kind)); |
| + } |
| + if (duplicate_allowed) { |
| + *sloppy_mode_block_scope_function_redefinition = true; |
| + } else { |
| + // The name was declared in this scope before; check for conflicting |
|
adamk
2016/08/30 18:58:32
This comment seems out of place and out of date. M
marja
2016/08/31 07:44:53
Ok, then I won't do anything for it..
|
| + // re-declarations. We have a conflict if either of the declarations |
| + // is not a var (in script scope, we also have to ignore legacy const |
| + // for compatibility). There is similar code in runtime.cc in the |
| + // Declare functions. The function CheckConflictingVarDeclarations |
| + // checks for var and let bindings from different scopes whereas this |
| + // is a check for conflicting declarations within the same scope. This |
| + // check also covers the special case |
| + // |
| + // function () { let x; { var x; } } |
| + // |
| + // because the var declaration is hoisted to the function scope where |
| + // 'x' is already bound. |
| + DCHECK(IsDeclaredVariableMode(var->mode())); |
| + // In harmony we treat re-declarations as early errors. See |
|
adamk
2016/08/30 18:58:32
This comment is now out of place (it belongs in th
marja
2016/08/31 07:44:53
Hmm, but the decision to set *ok = false is done h
adamk
2016/08/31 18:10:34
Ah, I hadn't thought about it that way. I was thin
|
| + // ES5 16 for a definition of early errors. |
| + *ok = false; |
| + return nullptr; |
| + } |
| + } else if (mode == VAR) { |
| + var->set_maybe_assigned(); |
| + } |
| + } |
| + DCHECK_NOT_NULL(var); |
| + |
| + // We add a declaration node for every declaration. The compiler |
| + // will only generate code if necessary. In particular, declarations |
| + // for inner local variables that do not represent functions won't |
| + // result in any generated code. |
| + // |
| + // This will lead to multiple declaration nodes for the |
| + // same variable if it is declared several times. This is not a |
| + // semantic issue, but it may be a performance issue since it may |
| + // lead to repeated DeclareEvalVar or DeclareEvalFunction calls. |
| + decls_.Add(declaration, zone()); |
| + proxy->BindTo(var); |
| + return var; |
| +} |
| + |
| Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name, |
| Variable::Kind kind) { |
| DCHECK(is_script_scope()); |
| @@ -735,12 +839,6 @@ Variable* Scope::NewTemporary(const AstRawString* name) { |
| return var; |
| } |
| -void Scope::AddDeclaration(Declaration* declaration) { |
| - DCHECK(!already_resolved_); |
| - decls_.Add(declaration, zone()); |
| -} |
| - |
| - |
| Declaration* Scope::CheckConflictingVarDeclarations() { |
| int length = decls_.length(); |
| for (int i = 0; i < length; i++) { |