From 8723051efdfba506303005c0b11010df3bf3f86e Mon Sep 17 00:00:00 2001 From: MuSilk Date: Fri, 11 Jul 2025 10:32:03 +0800 Subject: [PATCH] Fix update expression bug Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICLLD2?from=project-issue Signed-off-by: MuSilk --- ets2panda/checker/ETSAnalyzer.cpp | 10 ++++----- ets2panda/checker/ETSchecker.h | 2 +- ets2panda/checker/ets/validateHelpers.cpp | 4 ++-- .../ets/constantExpressionLowering.cpp | 9 ++++++++ .../convert_const_to_let.cpp | 4 ++-- .../test/ast/compiler/ets/assign_const.ets | 21 +++++++++++++++++++ .../ets/package_invalid_initializer/P3/P3.ets | 2 +- .../test/ast/compiler/ets/readonlyField.ets | 4 ++-- .../test/ast/compiler/ets/readonlyField_2.ets | 4 ++-- .../test/ast/compiler/ets/readonlyType_1.ets | 6 +++--- .../test/ast/compiler/ets/readonlyType_2.ets | 6 +++--- .../test/ast/compiler/ets/readonlyType_3.ets | 6 +++--- .../test/ast/compiler/ets/readonlyType_4.ets | 6 +++--- .../test/ast/compiler/ets/update_const.ets | 21 +++++++++++++++++++ .../ast/parser/ets/global_const_vars4.ets | 4 ++-- .../readonly_reference_CTE_err_elimilate.ets | 6 +++--- .../ast/parser/ets/unexpected_token_61.ets | 3 ++- ets2panda/util/diagnostic/semantic.yaml | 2 +- 18 files changed, 86 insertions(+), 34 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/assign_const.ets create mode 100644 ets2panda/test/ast/compiler/ets/update_const.ets diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 4748735b14..7c2edff7e0 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1218,7 +1218,7 @@ checker::Type *ETSAnalyzer::Check(ir::AssignmentExpression *const expr) const } if (expr->target_ != nullptr && !expr->IsIgnoreConstAssign()) { - checker->ValidateUnaryOperatorOperand(expr->target_); + checker->ValidateUnaryOperatorOperand(expr->target_, expr); } auto [rightType, relationNode] = CheckAssignmentExprOperatorType(expr, leftType); @@ -2764,20 +2764,20 @@ checker::Type *ETSAnalyzer::Check(ir::UpdateExpression *expr) const } if (expr->Argument()->IsIdentifier()) { - checker->ValidateUnaryOperatorOperand(expr->Argument()->AsIdentifier()->Variable()); + checker->ValidateUnaryOperatorOperand(expr->Argument()->AsIdentifier()->Variable(), expr); } else if (expr->Argument()->IsTSAsExpression()) { if (auto *const asExprVar = expr->Argument()->AsTSAsExpression()->Variable(); asExprVar != nullptr) { - checker->ValidateUnaryOperatorOperand(asExprVar); + checker->ValidateUnaryOperatorOperand(asExprVar, expr); } } else if (expr->Argument()->IsTSNonNullExpression()) { if (auto *const nonNullExprVar = expr->Argument()->AsTSNonNullExpression()->Variable(); nonNullExprVar != nullptr) { - checker->ValidateUnaryOperatorOperand(nonNullExprVar); + checker->ValidateUnaryOperatorOperand(nonNullExprVar, expr); } } else if (expr->Argument()->IsMemberExpression()) { varbinder::LocalVariable *propVar = expr->argument_->AsMemberExpression()->PropVar(); if (propVar != nullptr) { - checker->ValidateUnaryOperatorOperand(propVar); + checker->ValidateUnaryOperatorOperand(propVar, expr); } } else { ES2PANDA_ASSERT(checker->IsAnyError()); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 40549ea102..c8e6bae7da 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -620,7 +620,7 @@ public: const checker::Type *GetElementTypeOfArray(const checker::Type *type) const; bool IsNullLikeOrVoidExpression(const ir::Expression *expr) const; bool IsConstantExpression(ir::Expression *expr, Type *type); - void ValidateUnaryOperatorOperand(varbinder::Variable *variable); + void ValidateUnaryOperatorOperand(varbinder::Variable *variable, ir::Expression *expr); void CheckFunctionSignatureAnnotations(const ArenaVector ¶ms, ir::TSTypeParameterDeclaration *typeParams, ir::TypeNode *returnTypeAnnotation); diff --git a/ets2panda/checker/ets/validateHelpers.cpp b/ets2panda/checker/ets/validateHelpers.cpp index feee4a04aa..11043e0dee 100644 --- a/ets2panda/checker/ets/validateHelpers.cpp +++ b/ets2panda/checker/ets/validateHelpers.cpp @@ -203,7 +203,7 @@ void ETSChecker::ValidateResolvedIdentifier(ir::Identifier *const ident) } } -void ETSChecker::ValidateUnaryOperatorOperand(varbinder::Variable *variable) +void ETSChecker::ValidateUnaryOperatorOperand(varbinder::Variable *variable, ir::Expression *expr) { if (IsVariableGetterSetter(variable)) { return; @@ -221,7 +221,7 @@ void ETSChecker::ValidateUnaryOperatorOperand(varbinder::Variable *variable) } if (!HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK)) { std::ignore = TypeError(variable, diagnostic::FIELD_ASSIGN_TYPE_MISMATCH, {fieldType, variable->Name()}, - variable->Declaration()->Node()->Start()); + expr->Start()); } if (variable->HasFlag(varbinder::VariableFlags::INIT_IN_STATIC_BLOCK)) { diff --git a/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp b/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp index 6a08c07932..eaf664e55e 100644 --- a/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp +++ b/ets2panda/compiler/lowering/ets/constantExpressionLowering.cpp @@ -1280,6 +1280,15 @@ ir::AstNode *ConstantExpressionLowering::MaybeUnfoldIdentifier(ir::Identifier *n return node; } + // Left-Hand-Side identifiers in UpdateExpression or BinaryExpression cannot be unfolded + if (node->Parent()->IsUpdateExpression() && node->Parent()->AsUpdateExpression()->Argument() == node) { + return node; + } + + if (node->Parent()->IsAssignmentExpression() && node->Parent()->AsAssignmentExpression()->Left() == node) { + return node; + } + auto *resolved = ResolveIdentifier(node); if (resolved == nullptr || !(resolved->Declaration()->IsConstDecl() || resolved->Declaration()->IsReadonlyDecl())) { return node; diff --git a/ets2panda/lsp/src/register_code_fix/convert_const_to_let.cpp b/ets2panda/lsp/src/register_code_fix/convert_const_to_let.cpp index 057b14b581..4d91d17813 100644 --- a/ets2panda/lsp/src/register_code_fix/convert_const_to_let.cpp +++ b/ets2panda/lsp/src/register_code_fix/convert_const_to_let.cpp @@ -33,12 +33,12 @@ void FixConvertConstToLet::MakeChangeForConvertConstToLet(ChangeTracker &changeT size_t pos) { auto *token = GetTouchingToken(context, pos, false); - if (token == nullptr || !token->IsNumberLiteral() || token->OriginalNode() == nullptr) { + if (token == nullptr) { return; } auto *scope = compiler::NearestScope(token); - auto *resolvedDecl = FindDeclInScopeWithFallback(scope, token->OriginalNode()->AsIdentifier()->Name()); + auto *resolvedDecl = FindDeclInScopeWithFallback(scope, token->AsIdentifier()->Name()); if (resolvedDecl == nullptr) { return; } diff --git a/ets2panda/test/ast/compiler/ets/assign_const.ets b/ets2panda/test/ast/compiler/ets/assign_const.ets new file mode 100644 index 0000000000..150e93078f --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/assign_const.ets @@ -0,0 +1,21 @@ +/* + * 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://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +function main(): void { + const c = 0; + /* @@ label */c = c + 1; +} + +/* @@@ label Error TypeError: Cannot assign to a constant variable c */ diff --git a/ets2panda/test/ast/compiler/ets/package_invalid_initializer/P3/P3.ets b/ets2panda/test/ast/compiler/ets/package_invalid_initializer/P3/P3.ets index 809e03282c..3609cbb822 100644 --- a/ets2panda/test/ast/compiler/ets/package_invalid_initializer/P3/P3.ets +++ b/ets2panda/test/ast/compiler/ets/package_invalid_initializer/P3/P3.ets @@ -47,8 +47,8 @@ static { /* @@? P3.ets:29:14 Error SyntaxError: Missing initialization for const package property */ /* @@? P3.ets:29:18 Error SyntaxError: Variable must be initialized or it's type must be declared. */ /* @@? P3.ets:30:30 Error SyntaxError: Non-constant initializer of Package should be apply in Initializer Block. */ +/* @@? P3.ets:31:14 Error TypeError: Cannot reassign constant c_nn2 */ /* @@? P3.ets:32:6 Error SyntaxError: Non-constant initializer of Package should be apply in Initializer Block. */ /* @@? P3.ets:33:1 Error SyntaxError: Invalid package toplevel statement */ /* @@? P3.ets:34:1 Error SyntaxError: Invalid package toplevel statement */ -/* @@? P3.ets:36:5 Error TypeError: Invalid left-hand side of assignment expression */ /* @@? P3.ets:39:14 Error SyntaxError: Missing initialization for const package property */ diff --git a/ets2panda/test/ast/compiler/ets/readonlyField.ets b/ets2panda/test/ast/compiler/ets/readonlyField.ets index 808ae692ee..4b48970029 100644 --- a/ets2panda/test/ast/compiler/ets/readonlyField.ets +++ b/ets2panda/test/ast/compiler/ets/readonlyField.ets @@ -13,7 +13,7 @@ * limitations under the License. */ class ReadonlyData { - readonly /* @@ label */value: T; + readonly value: T; constructor(value: T) { this.value = value; } @@ -21,7 +21,7 @@ class ReadonlyData { function main(): void { let myData = new ReadonlyData("import data"); - myData.value = "new data"; + /* @@ label */myData.value = "new data"; } /* @@@ label Error TypeError: Cannot assign to a readonly variable value */ diff --git a/ets2panda/test/ast/compiler/ets/readonlyField_2.ets b/ets2panda/test/ast/compiler/ets/readonlyField_2.ets index 96451387fa..9dc39f7fa4 100644 --- a/ets2panda/test/ast/compiler/ets/readonlyField_2.ets +++ b/ets2panda/test/ast/compiler/ets/readonlyField_2.ets @@ -14,12 +14,12 @@ */ class ReadonlyPerson { - readonly /* @@ label */name: string; + readonly name: string; readonly age: number; } function updatePerson(person: ReadonlyPerson): ReadonlyPerson { - person.name = "Bob"; //CTE + /* @@ label */person.name = "Bob"; //CTE return person; } function main(): void { diff --git a/ets2panda/test/ast/compiler/ets/readonlyType_1.ets b/ets2panda/test/ast/compiler/ets/readonlyType_1.ets index 8a677d6521..b2680473fc 100644 --- a/ets2panda/test/ast/compiler/ets/readonlyType_1.ets +++ b/ets2panda/test/ast/compiler/ets/readonlyType_1.ets @@ -14,7 +14,7 @@ */ class A { - /* @@ label */fld: Number + fld: Number constructor (fld : Number) { this.fld = fld } @@ -22,9 +22,9 @@ class A { function foo(a0: A) { let a: Readonly = new A(2) - /* @@ label2 */a.fld = 5 + /* @@ label */a.fld = 5 } /* @@@ label Error TypeError: Cannot assign to a readonly variable fld */ -/* @@@ label2 Error TypeError: The 'Readonly' property cannot be reassigned. */ +/* @@@ label Error TypeError: The 'Readonly' property cannot be reassigned. */ diff --git a/ets2panda/test/ast/compiler/ets/readonlyType_2.ets b/ets2panda/test/ast/compiler/ets/readonlyType_2.ets index 17d1eaf99c..5685a9042e 100644 --- a/ets2panda/test/ast/compiler/ets/readonlyType_2.ets +++ b/ets2panda/test/ast/compiler/ets/readonlyType_2.ets @@ -14,13 +14,13 @@ */ class A { - /* @@ label */fld: Number = 2 + fld: Number = 2 } function foo(a0: A) { let a: Readonly = {fld: 3} - /* @@ label2 */a.fld = 5 + /* @@ label */a.fld = 5 } /* @@@ label Error TypeError: Cannot assign to a readonly variable fld */ -/* @@@ label2 Error TypeError: The 'Readonly' property cannot be reassigned. */ +/* @@@ label Error TypeError: The 'Readonly' property cannot be reassigned. */ diff --git a/ets2panda/test/ast/compiler/ets/readonlyType_3.ets b/ets2panda/test/ast/compiler/ets/readonlyType_3.ets index 9c5e0a1b2d..7ef6007189 100644 --- a/ets2panda/test/ast/compiler/ets/readonlyType_3.ets +++ b/ets2panda/test/ast/compiler/ets/readonlyType_3.ets @@ -14,11 +14,11 @@ */ class A { - /* @@ label */fld: Number = 2 + fld: Number = 2 foo (a0: Readonly) { - /* @@ label2 */a0.fld = 5 + /* @@ label */a0.fld = 5 } } /* @@@ label Error TypeError: Cannot assign to a readonly variable fld */ -/* @@@ label2 Error TypeError: The 'Readonly' property cannot be reassigned. */ +/* @@@ label Error TypeError: The 'Readonly' property cannot be reassigned. */ diff --git a/ets2panda/test/ast/compiler/ets/readonlyType_4.ets b/ets2panda/test/ast/compiler/ets/readonlyType_4.ets index 82d154132b..4d3bf9936e 100644 --- a/ets2panda/test/ast/compiler/ets/readonlyType_4.ets +++ b/ets2panda/test/ast/compiler/ets/readonlyType_4.ets @@ -14,7 +14,7 @@ */ class A { - /* @@ label */fld: Number = 2 + fld: Number = 2 foo (a0: A) { a0.fld = 5 } @@ -25,9 +25,9 @@ class B extends A {} class C extends B { fld: Number = 2 foo (a0: Readonly) { - /* @@ label2 */a0.fld = 6 + /* @@ label */a0.fld = 6 } } /* @@@ label Error TypeError: Cannot assign to a readonly variable fld */ -/* @@@ label2 Error TypeError: The 'Readonly' property cannot be reassigned. */ +/* @@@ label Error TypeError: The 'Readonly' property cannot be reassigned. */ diff --git a/ets2panda/test/ast/compiler/ets/update_const.ets b/ets2panda/test/ast/compiler/ets/update_const.ets new file mode 100644 index 0000000000..15ffd43067 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/update_const.ets @@ -0,0 +1,21 @@ +/* + * 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://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +function main(): void { + const c = 0; + /* @@ label */++c; +} + +/* @@@ label Error TypeError: Cannot assign to a constant variable c */ diff --git a/ets2panda/test/ast/parser/ets/global_const_vars4.ets b/ets2panda/test/ast/parser/ets/global_const_vars4.ets index f1d3d77aa9..7cc9886ebc 100644 --- a/ets2panda/test/ast/parser/ets/global_const_vars4.ets +++ b/ets2panda/test/ast/parser/ets/global_const_vars4.ets @@ -14,14 +14,14 @@ */ class ABC { - public readonly /* @@ label */date: Date = new Date(); + public readonly date: Date = new Date(); constructor() { this.init() } private init(): void { - this.date = new Date(); + /* @@ label */this.date = new Date(); } public main(): void {} diff --git a/ets2panda/test/ast/parser/ets/readonly_reference_CTE_err_elimilate.ets b/ets2panda/test/ast/parser/ets/readonly_reference_CTE_err_elimilate.ets index 7452c97120..435c77d20a 100644 --- a/ets2panda/test/ast/parser/ets/readonly_reference_CTE_err_elimilate.ets +++ b/ets2panda/test/ast/parser/ets/readonly_reference_CTE_err_elimilate.ets @@ -14,7 +14,7 @@ */ class A { - /* @@ label */x: int = 444 + x: int = 444 } let changeAbleVar = new A(); @@ -22,7 +22,7 @@ let changeAbleVar = new A(); changeAbleVar.x=333 function bar(a:Readonly){ - /* @@ label2 */a.x=111 + /* @@ label */a.x=111 console.log(a) } @@ -30,4 +30,4 @@ bar(changeAbleVar) /* @@@ label Error TypeError: Cannot assign to a readonly variable x */ -/* @@@ label2 Error TypeError: The 'Readonly' property cannot be reassigned. */ +/* @@@ label Error TypeError: The 'Readonly' property cannot be reassigned. */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_61.ets b/ets2panda/test/ast/parser/ets/unexpected_token_61.ets index bf42eb21ad..76c41c3aa4 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_61.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_61.ets @@ -14,9 +14,10 @@ */ function main(): void { - for (const i : int = 0 /* @@ label1 */i < 10; i++) { + for (const i : int = 0 /* @@ label1 */i < 10; /* @@ label */i++) { console.log("a") } } +/* @@@ label Error TypeError: Cannot assign to a constant variable i */ /* @@@ label1 Error SyntaxError: Expected ';', got 'identification literal'. */ diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index aad4b5292a..b313a43555 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -185,7 +185,6 @@ semantic: - name: ASSIGNMENT_INVALID_LHS id: 25 message: "Invalid left-hand side of assignment expression" - code_fix_ids: [FixConvertConstToLet] - name: ASSIGN_TO_READONLY_PROP id: 209 @@ -522,6 +521,7 @@ semantic: - name: FIELD_ASSIGN_TYPE_MISMATCH id: 298 message: "Cannot assign to a {} variable {}" + code_fix_ids: [FixConvertConstToLet] - name: FIELD_REASSIGNMENT id: 297 -- Gitee