From c37523c4a587370ab6db35aa4187db79d88e866d Mon Sep 17 00:00:00 2001 From: zmw Date: Wed, 13 Aug 2025 19:09:03 +0800 Subject: [PATCH] CTE for override private field Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICSTU2 Description: CTE for override private field Signed-off-by: zmw --- ets2panda/checker/ETSchecker.h | 3 + ets2panda/checker/ets/object.cpp | 81 ++++++++++++------- .../compiler/ets/override_private_field.ets | 23 ++++++ ets2panda/util/diagnostic/semantic.yaml | 4 + 4 files changed, 82 insertions(+), 29 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/override_private_field.ets diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index a42ab34a91..6739f8426c 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -1022,6 +1022,9 @@ private: std::pair GetTargetIdentifierAndType(ir::Identifier *ident); void NotResolvedError(ir::Identifier *const ident, const varbinder::Variable *classVar, const ETSObjectType *classType); + void LogInheritedMismatchError(ETSObjectType *classType, ir::ClassDefinition *classDef, + varbinder::LocalVariable *it, varbinder::LocalVariable *found, + ETSObjectType *interfaceFound); void ValidateNewClassInstanceIdentifier(ir::Identifier *const ident); void ValidateMemberIdentifier(ir::Identifier *const ident); void ValidateAssignmentIdentifier(ir::Identifier *const ident, Type *const type); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index 7303f27a93..1cfca61364 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -114,6 +114,12 @@ static bool CheckOverloadDecl(varbinder::LocalVariable *child, varbinder::LocalV return true; } +static bool CheckOverrideFieldDecl(varbinder::LocalVariable *child, varbinder::LocalVariable *parent) +{ + return !(child->HasFlag(varbinder::VariableFlags::PROPERTY) && child->Declaration()->Node()->IsOverride() && + parent->HasFlag(varbinder::VariableFlags::PRIVATE)); +} + static bool CheckFunctionDecl(varbinder::LocalVariable *child, varbinder::LocalVariable *parent) { if (child->Declaration()->Node()->IsOverloadDeclaration() || @@ -122,7 +128,7 @@ static bool CheckFunctionDecl(varbinder::LocalVariable *child, varbinder::LocalV } ES2PANDA_ASSERT(child->Declaration()->Type() == parent->Declaration()->Type()); if (!child->TsType()->IsETSMethodType() || !parent->TsType()->IsETSMethodType()) { - return true; + return CheckOverrideFieldDecl(child, parent); } const auto *childType = child->TsType()->AsETSFunctionType(); @@ -2491,6 +2497,50 @@ void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefini } } +static const char *GetTargetType(varbinder::LocalVariable *it) +{ + if (it->HasFlag(varbinder::VariableFlags::PROPERTY)) { + return "field"; + } + if (it->HasFlag(varbinder::VariableFlags::METHOD)) { + return "method"; + } + if (it->HasFlag(varbinder::VariableFlags::CLASS)) { + return "class"; + } + if (it->HasFlag(varbinder::VariableFlags::INTERFACE)) { + return "interface"; + } + if (it->HasFlag(varbinder::VariableFlags::NAMESPACE)) { + return "namespace"; + } + if (it->HasFlag(varbinder::VariableFlags::ENUM_LITERAL)) { + return "enum"; + } + if (it->HasFlag(varbinder::VariableFlags::OVERLOAD)) { + return "overload"; + } + ES2PANDA_UNREACHABLE(); +} + +void ETSChecker::LogInheritedMismatchError(ETSObjectType *classType, ir::ClassDefinition *classDef, + varbinder::LocalVariable *it, varbinder::LocalVariable *found, + ETSObjectType *interfaceFound) +{ + auto pos = classDef->Super() == nullptr ? classDef->Ident()->Start() : classDef->Super()->Start(); + const auto targetType = GetTargetType(it); + if (interfaceFound != nullptr) { + LogError(diagnostic::INHERITED_INTERFACE_TYPE_MISMATCH, {interfaceFound->Name(), targetType, it->Name()}, + interfaceFound->GetDeclNode()->Start()); + } else if (!CheckOverrideFieldDecl(it, found)) { + LogError(diagnostic::INHERITED_CLASS_OVERRIDE_PRIVATE, {classType->SuperType()->Name(), targetType, it->Name()}, + pos); + } else { + LogError(diagnostic::INHERITED_CLASS_TYPE_MISMATCH, {classType->SuperType()->Name(), targetType, it->Name()}, + pos); + } +} + void ETSChecker::CheckProperties(ETSObjectType *classType, ir::ClassDefinition *classDef, varbinder::LocalVariable *it, varbinder::LocalVariable *found, ETSObjectType *interfaceFound) { @@ -2516,34 +2566,7 @@ void ETSChecker::CheckProperties(ETSObjectType *classType, ir::ClassDefinition * } else if (CheckFunctionDecl(it, found)) { return; } - - const char *targetType {}; - - if (it->HasFlag(varbinder::VariableFlags::PROPERTY)) { - targetType = "field"; - } else if (it->HasFlag(varbinder::VariableFlags::METHOD)) { - targetType = "method"; - } else if (it->HasFlag(varbinder::VariableFlags::CLASS)) { - targetType = "class"; - } else if (it->HasFlag(varbinder::VariableFlags::INTERFACE)) { - targetType = "interface"; - } else if (it->HasFlag(varbinder::VariableFlags::NAMESPACE)) { - targetType = "namespace"; - } else if (it->HasFlag(varbinder::VariableFlags::ENUM_LITERAL)) { - targetType = "enum"; - } else if (it->HasFlag(varbinder::VariableFlags::OVERLOAD)) { - targetType = "overload"; - } else { - ES2PANDA_UNREACHABLE(); - } - - if (interfaceFound != nullptr) { - LogError(diagnostic::INHERITED_INTERFACE_TYPE_MISMATCH, {interfaceFound->Name(), targetType, it->Name()}, - interfaceFound->GetDeclNode()->Start()); - return; - } - auto pos = classDef->Super() == nullptr ? classDef->Ident()->Start() : classDef->Super()->Start(); - LogError(diagnostic::INHERITED_CLASS_TYPE_MISMATCH, {classType->SuperType()->Name(), targetType, it->Name()}, pos); + LogInheritedMismatchError(classType, classDef, it, found, interfaceFound); } void ETSChecker::CheckReadonlyClassPropertyInImplementedInterface(ETSObjectType *classType, diff --git a/ets2panda/test/ast/compiler/ets/override_private_field.ets b/ets2panda/test/ast/compiler/ets/override_private_field.ets new file mode 100644 index 0000000000..a6d6958f3b --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/override_private_field.ets @@ -0,0 +1,23 @@ +/** + * 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. + */ + +class C { + private private_member: number = 1 +} +class D extends C { + override private_member: number = 2 +} + +/* @@? 19:17 Error TypeError: Cannot inherit from class C, because field 'private_member' is attempting to override a private member. */ diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index 13edf6570b..eb739e416c 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -591,6 +591,10 @@ semantic: id: 132 message: "The type of parameter '{}' cannot be inferred" +- name: INHERITED_CLASS_OVERRIDE_PRIVATE + id: 402 + message: "Cannot inherit from class {}, because {} '{}' is attempting to override a private member." + - name: INHERITED_CLASS_TYPE_MISMATCH id: 216 message: "Cannot inherit from class {}, because {} {} is inherited with a different declaration type" -- Gitee