From 3314f152e0f88071d2d2aec929785b5dcf48b783 Mon Sep 17 00:00:00 2001 From: yp9522 Date: Mon, 21 Jul 2025 21:56:15 +0800 Subject: [PATCH] Fix process error if var re-declare with param Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICNTL1 Signed-off-by: yp9522 --- ets2panda/checker/ETSAnalyzer.cpp | 11 ++- .../lowering/scopesInit/scopesInitPhase.cpp | 16 ++-- .../ets/class_without_closing_parentheses.ets | 5 +- .../ast/compiler/ets/interface_partial.ets | 3 +- .../compiler/ets/math_const_as_identifier.ets | 3 +- .../compiler/ets/var-re-decl-with-param.ets | 95 +++++++++++++++++++ .../parser/ets/localTypeAlias-expected.txt | 8 -- ets2panda/varbinder/varbinder.cpp | 10 +- 8 files changed, 129 insertions(+), 22 deletions(-) create mode 100755 ets2panda/test/ast/compiler/ets/var-re-decl-with-param.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 06acf7c826..c980f97d7b 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -3634,7 +3634,16 @@ checker::Type *ETSAnalyzer::Check(ir::VariableDeclarator *st) const // Processing possible parser errors if (ident->Variable() == nullptr) { - ident->Check(checker); + if (checker->IsAnyError() && ident->Start().Program() != nullptr) { + auto loc = ident->Start().ToLocation(); + const auto &vec = checker->DiagnosticEngine().GetDiagnosticStorage(util::DiagnosticType::SEMANTIC); + if (std::any_of(vec.begin(), vec.end(), + [loc](const auto &it) { return it->Line() == loc.line && it->Offset() == loc.col; })) { + return checker->GlobalTypeError(); + } + } else { + ident->Check(checker); + } } auto *const variableType = checker->CheckVariableDeclaration(ident, ident->TypeAnnotation(), st->Init(), flags); diff --git a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp index 120bb9dc25..383928bfd0 100644 --- a/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp +++ b/ets2panda/compiler/lowering/scopesInit/scopesInitPhase.cpp @@ -499,7 +499,7 @@ std::tuple ScopesInitPhase::AddOrGetVa } else if (VarBinder()->IsETSBinder()) { if (auto var = scope->FindLocal(name, varbinder::ResolveBindingOptions::ALL_VARIABLES); var != nullptr) { VarBinder()->ThrowRedeclaration(id->Start(), name, var->Declaration()->Type()); - return {var->Declaration(), var}; + return {nullptr, nullptr}; } } @@ -518,7 +518,9 @@ std::tuple ScopesInitPhase::AddOrGetVa void ScopesInitPhase::BindVarDecl([[maybe_unused]] ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl, [[maybe_unused]] varbinder::Variable *var) { - decl->BindNode(init); + if (decl != nullptr) { + decl->BindNode(init); + } } void ScopesInitPhase::AttachLabelToScope([[maybe_unused]] ir::AstNode *node) {} @@ -892,10 +894,12 @@ void InitScopesPhaseETS::HandleProgram(parser::Program *program) void InitScopesPhaseETS::BindVarDecl(ir::Identifier *binding, ir::Expression *init, varbinder::Decl *decl, varbinder::Variable *var) { - binding->SetVariable(var); - var->SetScope(VarBinder()->GetScope()); - var->AddFlag(varbinder::VariableFlags::LOCAL); - decl->BindNode(init); + if (decl != nullptr) { + binding->SetVariable(var); + var->SetScope(VarBinder()->GetScope()); + var->AddFlag(varbinder::VariableFlags::LOCAL); + decl->BindNode(init); + } } void InitScopesPhaseETS::VisitBlockExpression(ir::BlockExpression *blockExpr) diff --git a/ets2panda/test/ast/compiler/ets/class_without_closing_parentheses.ets b/ets2panda/test/ast/compiler/ets/class_without_closing_parentheses.ets index 4c4d1ca68c..64b9f6e269 100644 --- a/ets2panda/test/ast/compiler/ets/class_without_closing_parentheses.ets +++ b/ets2panda/test/ast/compiler/ets/class_without_closing_parentheses.ets @@ -36,5 +36,6 @@ export default class TreeMap implements ReadonlyTreeMap { /* @@? 19:24 Error SyntaxError: Namespace is allowed only at the top level or inside a namespace. */ /* @@? 21:15 Error TypeError: Variable 'buffer' has already been declared. */ /* @@? 21:15 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ -/* @@? 24:32 Error TypeError: Indexed access is not supported for such expression type. */ -/* @@? 26:20 Error TypeError: Cannot find type 'buffer'. */ +/* @@? 23:29 Error TypeError: Unresolved reference length */ +/* @@? 24:20 Error TypeError: Property 'set' does not exist on type 'buffer' */ +/* @@? 26:20 Error TypeError: Namespace 'buffer' cannot be used as a type. */ diff --git a/ets2panda/test/ast/compiler/ets/interface_partial.ets b/ets2panda/test/ast/compiler/ets/interface_partial.ets index f3f836c47b..f4ac2a9040 100644 --- a/ets2panda/test/ast/compiler/ets/interface_partial.ets +++ b/ets2panda/test/ast/compiler/ets/interface_partial.ets @@ -36,5 +36,4 @@ function main() { /* @@? 27:18 Error TypeError: type I has no property named var_one */ /* @@? 28:11 Error TypeError: Property 'var_one' does not exist on type 'I' */ /* @@? 29:9 Error TypeError: Variable 'a' has already been declared. */ -/* @@? 29:18 Error TypeError: type I has no property named var_two */ -/* @@? 30:9 Error SyntaxError: Unexpected token 'break'. */ \ No newline at end of file +/* @@? 30:9 Error SyntaxError: Unexpected token 'break'. */ diff --git a/ets2panda/test/ast/compiler/ets/math_const_as_identifier.ets b/ets2panda/test/ast/compiler/ets/math_const_as_identifier.ets index ef222fcc9f..5834c7e424 100644 --- a/ets2panda/test/ast/compiler/ets/math_const_as_identifier.ets +++ b/ets2panda/test/ast/compiler/ets/math_const_as_identifier.ets @@ -25,7 +25,6 @@ function foo1() { /* @@? 21:9 Error TypeError: Variable 'NaN' has already been declared. */ /* @@? 22:9 Error TypeError: Variable 'Infinity' has already been declared. */ -/* @@? 22:20 Error TypeError: Unresolved reference test */ /* @@? 23:9 Error SyntaxError: Hard keyword 'undefined' cannot be used as identifier */ /* @@? 23:9 Error SyntaxError: Identifier expected, got 'undefined'. */ -/* @@? 24:1 Error SyntaxError: Variable must be initialized or it's type must be declared. */ +/* @@? 24:1 Error SyntaxError: Variable must be initialized or it's type must be declared. */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/var-re-decl-with-param.ets b/ets2panda/test/ast/compiler/ets/var-re-decl-with-param.ets new file mode 100755 index 0000000000..5ce6dbdc26 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/var-re-decl-with-param.ets @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http: * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class A { + public static newA() + { + return new A(); + } + + public byteMethod(a0: byte, a1: byte): byte + { + return a0 > a1 ? a0 : a1; + } + + public byteMethodVoidParam(): byte + { + return 5 as byte; + } + + public byteMethodMultipleParam(a0: byte, a1: boolean, a2: float, a3: float, a4: byte): byte + { + if (a1) { + return a4; + } else if (a2 > a3) { + return a0; + } else { + return (a4 + a0).toByte(); + } + } + + public nestedMethod(data1: byte, data2: byte): byte + { + let method = (value1: byte, value2: byte): byte => { + return (value1 + value2).toByte(); + } + + return method(data1, data2); + } + + public recursionMethod(a0: byte): byte + { + if (a0 > 100) { + return a0 as byte; + } else { + return this.recursionMethod((a0 + 10).toByte()); + } + } +} + +final class B extends A { + + public subByteMethodVoidParam(): byte + { + return 8 as byte; + } +} + +abstract class C { + public abstract func(a: byte, b: byte): byte; +} + +class D extends C { + public override func(a: byte, b: byte): byte { + return (a + b).toByte(); + } +} + +class E extends D { + public override func(a: byte, b: byte): byte { + let a : Int | null = 7; + let b = bar(a); + + assertEQ(typeOf(b), 1, "b must be type Int") + assertEQ(b, 7) + +} +} + +/* @@? 81:9 Error TypeError: Variable 'a' has already been declared. */ +/* @@? 82:9 Error TypeError: Variable 'b' has already been declared. */ +/* @@? 84:5 Error TypeError: Unresolved reference assertEQ */ +/* @@? 85:5 Error TypeError: This expression is not callable. */ + + diff --git a/ets2panda/test/parser/ets/localTypeAlias-expected.txt b/ets2panda/test/parser/ets/localTypeAlias-expected.txt index 5a63a7ed34..cbca8a21c6 100644 --- a/ets2panda/test/parser/ets/localTypeAlias-expected.txt +++ b/ets2panda/test/parser/ets/localTypeAlias-expected.txt @@ -3568,25 +3568,17 @@ } } } -TypeError: Cannot find type 'a'. [localTypeAlias.ets:17:16] TypeError: Variable 'a' has already been declared. [localTypeAlias.ets:21:9] -TypeError: Cannot find type 'a'. [localTypeAlias.ets:21:13] TypeError: Type name 'a' used in the wrong context [localTypeAlias.ets:23:5] TypeError: Variable 'dsa' has already been declared. [localTypeAlias.ets:31:17] -TypeError: Cannot find type 'dsa'. [localTypeAlias.ets:31:23] TypeError: Cannot find type 'asd'. [localTypeAlias.ets:34:22] TypeError: Cannot find type 'asd'. [localTypeAlias.ets:41:19] TypeError: Variable 'dsa' has already been declared. [localTypeAlias.ets:44:13] -TypeError: Cannot find type 'dsa'. [localTypeAlias.ets:44:19] TypeError: Cannot find type 'asd'. [localTypeAlias.ets:48:19] TypeError: Variable 'dsa' has already been declared. [localTypeAlias.ets:51:13] -TypeError: Cannot find type 'dsa'. [localTypeAlias.ets:51:19] TypeError: Cannot find type 'asd'. [localTypeAlias.ets:56:19] TypeError: Variable 'dsa' has already been declared. [localTypeAlias.ets:60:13] -TypeError: Cannot find type 'dsa'. [localTypeAlias.ets:60:19] TypeError: Cannot find type 'asd'. [localTypeAlias.ets:64:19] TypeError: Variable 'dsa' has already been declared. [localTypeAlias.ets:68:13] -TypeError: Cannot find type 'dsa'. [localTypeAlias.ets:68:19] TypeError: Cannot find type 'asd'. [localTypeAlias.ets:70:19] TypeError: Variable 'dsa' has already been declared. [localTypeAlias.ets:74:13] -TypeError: Cannot find type 'dsa'. [localTypeAlias.ets:74:19] diff --git a/ets2panda/varbinder/varbinder.cpp b/ets2panda/varbinder/varbinder.cpp index 0c8e39ff4e..c63ab46ffc 100644 --- a/ets2panda/varbinder/varbinder.cpp +++ b/ets2panda/varbinder/varbinder.cpp @@ -254,6 +254,7 @@ bool VarBinder::BuildInternalName(ir::ScriptFunction *scriptFunc) return !scriptFunc->IsOverload(); } +// CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic void VarBinder::BuildVarDeclaratorId(ir::AstNode *childNode) { switch (childNode->Type()) { @@ -264,7 +265,14 @@ void VarBinder::BuildVarDeclaratorId(ir::AstNode *childNode) if (IsGlobalIdentifier(name) || name.Is(ERROR_LITERAL)) { break; } - + if (context_->diagnosticEngine->IsAnyError() && ident->Start().Program() != nullptr) { + auto loc = ident->Start().ToLocation(); + const auto &vec = context_->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::SEMANTIC); + if (std::any_of(vec.begin(), vec.end(), + [loc](const auto &it) { return it->Line() == loc.line && it->Offset() == loc.col; })) { + break; + } + } auto *variable = scope_->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS); ES2PANDA_ASSERT(variable); ident->SetVariable(variable); -- Gitee