• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "scope.h"
17 
18 #include <binder/declaration.h>
19 #include <util/helpers.h>
20 #include <binder/tsBinding.h>
21 #include <binder/variable.h>
22 #include <binder/variableFlags.h>
23 #include <ir/astNode.h>
24 #include <ir/base/scriptFunction.h>
25 #include <ir/base/classDefinition.h>
26 #include <ir/expressions/identifier.h>
27 #include <ir/expressions/privateIdentifier.h>
28 #include <ir/module/exportAllDeclaration.h>
29 #include <ir/module/exportNamedDeclaration.h>
30 #include <ir/module/exportSpecifier.h>
31 #include <ir/module/importDeclaration.h>
32 #include <macros.h>
33 #include <util/concurrent.h>
34 #include <util/ustring.h>
35 
36 #include <algorithm>
37 #include <sstream>
38 
39 namespace panda::es2panda::binder {
40 
EnclosingVariableScope()41 VariableScope *Scope::EnclosingVariableScope()
42 {
43     Scope *iter = this;
44 
45     while (iter) {
46         if (iter->IsVariableScope()) {
47             return iter->AsVariableScope();
48         }
49 
50         iter = iter->Parent();
51     }
52 
53     return nullptr;
54 }
55 
EnclosingFunctionVariableScope()56 FunctionScope *Scope::EnclosingFunctionVariableScope()
57 {
58     Scope *iter = this;
59     while (iter) {
60         if (iter->IsFunctionVariableScope()) {
61             return iter->AsFunctionVariableScope();
62         }
63 
64         iter = iter->Parent();
65     }
66 
67     return nullptr;
68 }
69 
FindLocal(const util::StringView & name,ResolveBindingOptions options) const70 Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
71 {
72     if (options & ResolveBindingOptions::INTERFACES) {
73         const std::string &interfaceName = binder::TSBinding::ToTSBinding(name);
74 
75         auto res = bindings_.find(util::StringView{interfaceName});
76         if (res != bindings_.end()) {
77             return res->second;
78         }
79 
80         if (!(options & ResolveBindingOptions::BINDINGS)) {
81             return nullptr;
82         }
83     }
84 
85     auto res = bindings_.find(name);
86     if (res == bindings_.end()) {
87         return nullptr;
88     }
89 
90     return res->second;
91 }
92 
HasLexEnvInCorrespondingFunctionScope(const FunctionParamScope * scope) const93 bool Scope::HasLexEnvInCorrespondingFunctionScope(const FunctionParamScope *scope) const
94 {
95     auto *funcVariableScope = scope->GetFunctionScope();
96     // we may only have function param scope without function scope in TS here
97     if ((funcVariableScope != nullptr) && (funcVariableScope->NeedLexEnv())) {
98         return true;
99     }
100     return false;
101 }
102 
Find(const util::StringView & name,ResolveBindingOptions options) const103 ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions options) const
104 {
105     uint32_t level = 0;
106     uint32_t lexLevel = 0;
107     const auto *iter = this;
108     ir::ScriptFunction *concurrentFunc = nullptr;
109     // If the first scope is functionParamScope, it means its corresponding functionScope is not
110     // iterated. so by default we set prevScopeNotFunctionScope as true so under such case,
111     // functionScopeNotIterated will be true.
112     bool prevScopeNotFunctionScope = true;
113     bool lexical = false;
114 
115     while (iter != nullptr) {
116         bool functionScopeNotIterated = iter->IsFunctionParamScope() && prevScopeNotFunctionScope;
117         Variable *v = iter->FindLocal(name, options);
118 
119         if (v != nullptr) {
120             return {name, const_cast<Scope *>(iter), level, lexLevel, v, concurrentFunc};
121         }
122 
123         if (iter->IsFunctionVariableScope() && !lexical) {
124             lexical = true;
125         }
126 
127         if (iter->IsVariableScope()) {
128             if (lexical) {
129                 level++;
130             }
131 
132             if (util::Helpers::ShouldCheckConcurrent(iter, name) && !concurrentFunc) {
133                 concurrentFunc = const_cast<ir::ScriptFunction *>(iter->Node()->AsScriptFunction());
134             }
135 
136             if (iter->AsVariableScope()->NeedLexEnv() &&
137                 (!iter->IsClassScope() || !iter->Node()->AsClassDefinition()->IsSendable())) {
138                 lexLevel++;
139             }
140         } else if (functionScopeNotIterated) {
141             level++;
142             if (HasLexEnvInCorrespondingFunctionScope(iter->AsFunctionParamScope())) {
143                 lexLevel++;
144             }
145         }
146 
147         prevScopeNotFunctionScope = !iter->IsFunctionVariableScope();
148         util::Helpers::SendableCheckForClassStaticInitializer(name, iter, concurrentFunc);
149         iter = iter->Parent();
150     }
151 
152     return {name, nullptr, 0, 0, nullptr, concurrentFunc};
153 }
154 
Find(const ir::Expression * expr,bool onlyLevel) const155 std::pair<uint32_t, uint32_t> Scope::Find(const ir::Expression *expr, bool onlyLevel) const
156 {
157     uint32_t lexLevel = 0;
158     const auto *iter = this;
159 
160     while (iter != nullptr) {
161         if (iter->Type() == ScopeType::CLASS) {
162             if (onlyLevel) {
163                 return {lexLevel, 0};
164             }
165             return {lexLevel, iter->AsClassScope()->GetSlot(expr)};
166         }
167 
168         if (iter->IsVariableScope()) {
169             if (iter->AsVariableScope()->NeedLexEnv()) {
170                 lexLevel++;
171             }
172         }
173         iter = iter->Parent();
174     }
175 
176     UNREACHABLE();
177 }
178 
GetPrivateProperty(const util::StringView & name,bool isSetter) const179 Result ClassScope::GetPrivateProperty(const util::StringView &name, bool isSetter) const
180 {
181     if (name.Is("#method")) {
182         return {instanceMethodValidation_, false, false, false, false, 0};
183     }
184 
185     uint32_t slot{0};
186     bool setter{false};
187     bool getter{false};
188 
189     if (privateNames_.find(name) != privateNames_.end()) {
190         slot = privateNames_.find(name)->second;
191     } else {
192         auto accessor = isSetter ? privateSetters_ : privateGetters_;
193         auto unexpectedAccessor = isSetter ? privateGetters_ : privateSetters_;
194 
195         if (accessor.find(name) != accessor.end()) {
196             setter = isSetter;
197             getter = !setter;
198             slot = accessor.find(name)->second;
199         } else {
200             getter = isSetter;
201             setter = !getter;
202             slot = unexpectedAccessor.find(name)->second;
203         }
204     }
205 
206     uint32_t validateMethodSlot{0};
207 
208     if (IsMethod(slot)) {
209         validateMethodSlot = IsStaticMethod(slot) ? staticMethodValidation_ : instanceMethodValidation_;
210     }
211 
212     return {slot, IsMethod(slot), IsStaticMethod(slot), getter, setter, validateMethodSlot};
213 }
214 
AddPrivateName(std::vector<const ir::Statement * > privateProperties,uint32_t privateFieldCnt,uint32_t instancePrivateMethodCnt,uint32_t staticPrivateMethodCnt)215 void ClassScope::AddPrivateName(std::vector<const ir::Statement *> privateProperties, uint32_t privateFieldCnt,
216                                 uint32_t instancePrivateMethodCnt, uint32_t staticPrivateMethodCnt)
217 {
218     privateFieldCnt_ = privateFieldCnt;
219     instancePrivateMethodStartSlot_ = slotIndex_ + privateFieldCnt_;
220     staticPrivateMethodStartSlot_ = instancePrivateMethodStartSlot_ + instancePrivateMethodCnt;
221     uint32_t instancePrivateMethodSlot = instancePrivateMethodStartSlot_;
222     uint32_t staticPrivateMethodSlot = staticPrivateMethodStartSlot_;
223     for (const auto *stmt : privateProperties) {
224         if (stmt->IsClassProperty()) {
225             privateNames_[stmt->AsClassProperty()->Key()->AsPrivateIdentifier()->Name()] = slotIndex_++;
226             continue;
227         }
228         ASSERT(stmt->IsMethodDefinition());
229         auto *methodDef = stmt->AsMethodDefinition();
230         uint32_t *start = methodDef->IsStatic() ? &staticPrivateMethodSlot : &instancePrivateMethodSlot;
231         auto name = methodDef->Key()->AsPrivateIdentifier()->Name();
232         switch (methodDef->Kind()) {
233             case ir::MethodDefinitionKind::GET: {
234                 privateGetters_[name] =  (*start)++;
235                 continue;
236             }
237             case ir::MethodDefinitionKind::SET: {
238                 privateSetters_[name] =  (*start)++;
239                 continue;
240             }
241             default: {
242                 privateNames_[name]=  (*start)++;
243                 continue;
244             }
245         }
246     }
247     slotIndex_ = staticPrivateMethodSlot;
248     privateMethodEndSlot_ = slotIndex_;
249     if (instancePrivateMethodCnt != 0) {
250         instanceMethodValidation_ = slotIndex_++;
251     }
252 
253     if (staticPrivateMethodCnt != 0) {
254         staticMethodValidation_ = slotIndex_++;
255     }
256 }
257 
FindPrivateName(const util::StringView & name,bool isSetter) const258 PrivateNameFindResult Scope::FindPrivateName(const util::StringView &name, bool isSetter) const
259 {
260     uint32_t lexLevel = 0;
261     const auto *iter = this;
262 
263     while (iter != nullptr) {
264         if (iter->Type() == ScopeType::CLASS) {
265             const auto *classScope = iter->AsClassScope();
266             if (name.Is("#method") || classScope->HasPrivateName(name)) {
267                 return {lexLevel, classScope->GetPrivateProperty(name, isSetter)};
268             }
269         }
270 
271         if (iter->IsVariableScope()) {
272             if (iter->AsVariableScope()->NeedLexEnv()) {
273                 lexLevel++;
274             }
275         }
276         iter = iter->Parent();
277     }
278 
279     UNREACHABLE();
280 }
281 
FindDecl(const util::StringView & name) const282 Decl *Scope::FindDecl(const util::StringView &name) const
283 {
284     for (auto *it : decls_) {
285         if (it->Name() == name) {
286             return it;
287         }
288     }
289 
290     return nullptr;
291 }
292 
HasVarDecl(const util::StringView & name) const293 bool Scope::HasVarDecl(const util::StringView &name) const
294 {
295     for (auto *it : decls_) {
296         if (it->Name() == name && it->IsVarDecl()) {
297             return true;
298         }
299     }
300 
301     return false;
302 }
303 
IterateShadowedVariables(const util::StringView & name,const VariableVisitior & visitor)304 std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)
305 {
306     auto *iter = this;
307 
308     while (true) {
309         auto *v = iter->FindLocal(name);
310 
311         if (v && visitor(v)) {
312             return {iter, true};
313         }
314 
315         if (iter->IsFunctionVariableScope()) {
316             break;
317         }
318 
319         iter = iter->Parent();
320     }
321 
322     return {iter, false};
323 }
324 
AddLocal(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)325 bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
326                      [[maybe_unused]] ScriptExtension extension)
327 {
328     VariableFlags flags = VariableFlags::NONE;
329     switch (newDecl->Type()) {
330         case DeclType::VAR: {
331             auto [scope, shadowed] = IterateShadowedVariables(
332                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
333 
334             if (shadowed) {
335                 return false;
336             }
337 
338             VariableFlags varFlags = VariableFlags::HOIST_VAR;
339             if (scope->IsGlobalScope()) {
340                 scope->Bindings().insert({newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)});
341             } else {
342                 scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
343             }
344 
345             return true;
346         }
347         case DeclType::ENUM_LITERAL: {
348             return tsBindings_.AddTSVariable<TSBindingType::ENUMLITERAL>(
349                 newDecl->Name(), allocator->New<EnumLiteralVariable>(newDecl, VariableFlags::ENUM_LITERAL));
350         }
351         case DeclType::INTERFACE: {
352             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)});
353             return true;
354         }
355         case DeclType::FUNC: {
356             flags = VariableFlags::HOIST;
357             [[fallthrough]];
358         }
359         default: {
360             if (currentVariable) {
361                 return false;
362             }
363 
364             if (HasVarDecl(newDecl->Name())) {
365                 return false;
366             }
367 
368             bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)});
369             return true;
370         }
371     }
372 }
373 
AddParam(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,VariableFlags flags)374 bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
375 {
376     ASSERT(newDecl->IsParameterDecl());
377 
378     if (currentVariable) {
379         return false;
380     }
381 
382     auto *param = allocator->New<LocalVariable>(newDecl, flags);
383 
384     params_.push_back(param);
385     bindings_.insert({newDecl->Name(), param});
386     return true;
387 }
388 
AddParamDecl(ArenaAllocator * allocator,const ir::AstNode * param)389 std::tuple<ParameterDecl *, const ir::AstNode *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
390                                                                           const ir::AstNode *param)
391 {
392     const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
393 
394     auto *decl = NewDecl<ParameterDecl>(allocator, name);
395 
396     if (!AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR)) {
397         return {decl, param};
398     }
399 
400     if (!pattern) {
401         decl->BindNode(param);
402         return {decl, nullptr};
403     }
404 
405     std::vector<const ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
406 
407     for (const auto *binding : bindings) {
408         auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
409         varDecl->BindNode(binding);
410 
411         if (FindLocal(varDecl->Name())) {
412             return {decl, binding};
413         }
414 
415         auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR);
416         bindings_.insert({varDecl->Name(), paramVar});
417     }
418 
419     return {decl, nullptr};
420 }
421 
BindName(ArenaAllocator * allocator,util::StringView name)422 void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
423 {
424     nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
425     functionScope_->Bindings().insert({name, nameVar_});
426 }
427 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)428 bool FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
429                                     [[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
430                                     [[maybe_unused]] ScriptExtension extension)
431 {
432     UNREACHABLE();
433 }
434 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)435 bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
436                                [[maybe_unused]] ScriptExtension extension)
437 {
438     switch (newDecl->Type()) {
439         case DeclType::VAR: {
440             return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
441         }
442         case DeclType::FUNC: {
443             return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
444         }
445         case DeclType::CLASS: {
446             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
447         }
448         case DeclType::ENUM_LITERAL: {
449             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
450         }
451         case DeclType::NAMESPACE: {
452             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
453         }
454         case DeclType::IMPORT_EQUALS: {
455             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
456         }
457         case DeclType::INTERFACE: {
458             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
459         }
460         default: {
461             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
462         }
463     }
464 }
465 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)466 bool TSEnumScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
467                              [[maybe_unused]] ScriptExtension extension)
468 {
469     ASSERT(newDecl->Type() == DeclType::ENUM);
470     return enumMemberBindings_->insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)}).second;
471 }
472 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)473 bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
474                              [[maybe_unused]] ScriptExtension extension)
475 {
476     switch (newDecl->Type()) {
477         case DeclType::VAR: {
478             return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
479         }
480         case DeclType::FUNC: {
481             return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
482         }
483         case DeclType::CLASS: {
484             return AddClass<LocalVariable>(allocator, currentVariable, newDecl);
485         }
486         case DeclType::ENUM_LITERAL: {
487             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
488         }
489         case DeclType::NAMESPACE: {
490             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
491         }
492         case DeclType::IMPORT_EQUALS: {
493             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
494         }
495         case DeclType::INTERFACE: {
496             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
497         }
498         default: {
499             return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
500         }
501     }
502 
503     return true;
504 }
505 
506 // ModuleScope
507 
ConvertLocalVariableToModuleVariable(ArenaAllocator * allocator,util::StringView localName)508 void ModuleScope::ConvertLocalVariableToModuleVariable(ArenaAllocator *allocator, util::StringView localName)
509 {
510     auto res = bindings_.find(localName);
511     // Since the module's exported [localName] has been validated before,
512     // [localName] must have a binding now.
513     ASSERT(res != bindings_.end());
514     if (!res->second->IsModuleVariable()) {
515         auto *decl = res->second->Declaration();
516         decl->AddFlag(DeclarationFlags::EXPORT);
517         VariableFlags flags = res->second->Flags();
518         res->second = allocator->New<ModuleVariable>(decl, flags | VariableFlags::LOCAL_EXPORT);
519     }
520 }
521 
AssignIndexToModuleVariable(util::StringView name,uint32_t index)522 void ModuleScope::AssignIndexToModuleVariable(util::StringView name, uint32_t index)
523 {
524     auto *moduleVar = FindLocal(name);
525     ASSERT(moduleVar != nullptr);
526     ASSERT(moduleVar->IsModuleVariable());
527     moduleVar->AsModuleVariable()->AssignIndex(index);
528 }
529 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)530 bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
531                              [[maybe_unused]] ScriptExtension extension)
532 {
533     switch (newDecl->Type()) {
534         case DeclType::VAR: {
535             auto [scope, shadowed] = IterateShadowedVariables(
536                 newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
537 
538             if (shadowed) {
539                 return false;
540             }
541             return newDecl->IsImportOrExportDecl() ?
542                    AddVar<ModuleVariable>(allocator, currentVariable, newDecl) :
543                    AddVar<LocalVariable>(allocator, currentVariable, newDecl);
544         }
545         case DeclType::FUNC: {
546             if (currentVariable) {
547                 auto decl = currentVariable->Declaration();
548                 if (!decl->IsClassDecl() || !decl->AsClassDecl()->IsDeclare()) {
549                     return false;
550                 }
551             }
552             return newDecl->IsImportOrExportDecl() ?
553                    AddFunction<ModuleVariable>(allocator, currentVariable, newDecl, extension) :
554                    AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
555         }
556         case DeclType::CLASS: {
557             return newDecl->IsImportOrExportDecl() ?
558                    AddClass<ModuleVariable>(allocator, currentVariable, newDecl) :
559                    AddClass<LocalVariable>(allocator, currentVariable, newDecl);
560         }
561         case DeclType::ENUM_LITERAL: {
562             return AddTSBinding<EnumLiteralVariable>(allocator, newDecl, VariableFlags::ENUM_LITERAL);
563         }
564         case DeclType::NAMESPACE: {
565             return AddTSBinding<NamespaceVariable>(allocator, newDecl, VariableFlags::NAMESPACE);
566         }
567         case DeclType::IMPORT_EQUALS: {
568             return AddTSBinding<ImportEqualsVariable>(allocator, newDecl, VariableFlags::IMPORT_EQUALS);
569         }
570         case DeclType::INTERFACE: {
571             return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
572         }
573         default: {
574             if (currentVariable) {
575                 return false;
576             }
577             return newDecl->IsImportOrExportDecl() ?
578                    AddLexical<ModuleVariable>(allocator, currentVariable, newDecl) :
579                    AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
580         }
581     }
582 }
583 
584 // LocalScope
585 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)586 bool LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
587                             [[maybe_unused]] ScriptExtension extension)
588 {
589     return AddLocal(allocator, currentVariable, newDecl, extension);
590 }
591 
InitVariable()592 void LoopScope::InitVariable()
593 {
594     for (const auto &[name, var] : bindings_) {
595         if (!var->Declaration()->IsLetOrConstOrClassDecl()) {
596             continue;
597         }
598 
599         var->AddFlag(VariableFlags::INITIALIZED);
600         if (var->LexicalBound()) {
601             var->AddFlag(VariableFlags::PER_ITERATION);
602         }
603     }
604 }
605 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)606 bool CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
607                                  [[maybe_unused]] ScriptExtension extension)
608 {
609     return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
610 }
611 
AddBinding(ArenaAllocator * allocator,Variable * currentVariable,Decl * newDecl,ScriptExtension extension)612 bool CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
613                             [[maybe_unused]] ScriptExtension extension)
614 {
615     if (!newDecl->IsVarDecl() && paramScope_->FindLocal(newDecl->Name())) {
616         return false;
617     }
618 
619     return AddLocal(allocator, currentVariable, newDecl, extension);
620 }
621 
622 }  // namespace panda::es2panda::binder
623