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