From d085bbcd02531f4e10f9f81b050ee34b2228f6a1 Mon Sep 17 00:00:00 2001 From: MuSilk Date: Wed, 30 Jul 2025 17:26:22 +0800 Subject: [PATCH] Fix required/partial bug Issue:[Bug]: Required/Patial crash when generic is functionType https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICMZGJ Signed-off-by: MuSilk --- ets2panda/checker/ets/utilityTypeHandlers.cpp | 71 +++++++++++++++---- .../ets/partialType_invalid_generic.ets | 25 +++++++ .../compiler/ets/readonly_invalid_generic.ets | 25 +++++++ .../ets/requiredType_invalid_generic.ets | 25 +++++++ ets2panda/util/diagnostic/semantic.yaml | 4 ++ 5 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/partialType_invalid_generic.ets create mode 100644 ets2panda/test/ast/compiler/ets/readonly_invalid_generic.ets create mode 100644 ets2panda/test/ast/compiler/ets/requiredType_invalid_generic.ets diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index 93f6b5eccc..3cefd7cb57 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -38,6 +38,20 @@ std::optional ETSChecker::GetUtilityTypeTypeParamNode( return typeParams->Params().front(); } +static bool CheckTypeAvailiableAsClassOrInterface(Type *const type) +{ + if (type->IsETSObjectType() || type->IsETSTypeParameter() || type->IsETSArrayType() || type->IsETSTupleType() || + type->IsETSUnionType()) { + return true; + } + + if (type->IsGradualType()) { + return CheckTypeAvailiableAsClassOrInterface(type->AsGradualType()->GetBaseType()); + } + + return false; +} + Type *ETSChecker::HandleUtilityTypeParameterNode(const ir::TSTypeParameterInstantiation *const typeParams, const ir::Identifier *const ident) { @@ -66,6 +80,15 @@ Type *ETSChecker::HandleUtilityTypeParameterNode(const ir::TSTypeParameterInstan return baseType; } + if (utilityType == compiler::Signatures::PARTIAL_TYPE_NAME || + utilityType == compiler::Signatures::READONLY_TYPE_NAME || + utilityType == compiler::Signatures::REQUIRED_TYPE_NAME) { + if (!CheckTypeAvailiableAsClassOrInterface(baseType)) { + LogError(diagnostic::TYPE_INVALID_AS_CLASS_OR_INTERFACE, {baseType, utilityType}, typeParams->Start()); + return baseType; + } + } + if (utilityType == compiler::Signatures::PARTIAL_TYPE_NAME) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) return CreatePartialType(baseType); @@ -122,9 +145,14 @@ static T *CloneNodeIfNotNullptr(T *node, ArenaAllocator *allocator) Type *ETSChecker::CreatePartialType(Type *const typeToBePartial) { + ES2PANDA_ASSERT(typeToBePartial != nullptr); ES2PANDA_ASSERT(typeToBePartial->IsETSReferenceType()); - if (typeToBePartial->IsTypeError() || typeToBePartial->IsETSNeverType() || typeToBePartial->IsETSAnyType()) { - return typeToBePartial; + + if (typeToBePartial->IsETSArrayType()) { + ETSArrayType *const clonedArrayType = + ProgramAllocator()->New(typeToBePartial->AsETSArrayType()->ElementType()); + ES2PANDA_ASSERT(clonedArrayType != nullptr); + return clonedArrayType; } if (typeToBePartial->IsGradualType()) { @@ -141,9 +169,13 @@ Type *ETSChecker::CreatePartialType(Type *const typeToBePartial) return HandleUnionForPartialType(typeToBePartial->AsETSUnionType()); } - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return CreatePartialTypeClass(typeToBePartial->AsETSObjectType(), - typeToBePartial->Variable()->Declaration()->Node()); + if (typeToBePartial->IsETSObjectType()) { + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) + return CreatePartialTypeClass(typeToBePartial->AsETSObjectType(), + typeToBePartial->Variable()->Declaration()->Node()); + } + + return typeToBePartial; } Type *ETSChecker::CreatePartialTypeParameter(ETSTypeParameter *typeToBePartial) @@ -1056,6 +1088,20 @@ Type *ETSChecker::HandleRequiredType(Type *typeToBeRequired) } NamedTypeStackElement ntse(this, typeToBeRequired); + ES2PANDA_ASSERT(typeToBeRequired != nullptr); + if (typeToBeRequired->IsETSArrayType()) { + ETSArrayType *const clonedArrayType = + ProgramAllocator()->New(typeToBeRequired->AsETSArrayType()->ElementType()); + ES2PANDA_ASSERT(clonedArrayType != nullptr); + clonedArrayType->AddTypeFlag(TypeFlag::ETS_REQUIRED_TYPE_PARAMETER); + return clonedArrayType; + } + + if (typeToBeRequired->IsETSTupleType()) { + Type *const clonedType = typeToBeRequired->Clone(this); + clonedType->AddTypeFlag(TypeFlag::ETS_REQUIRED_TYPE_PARAMETER); + return clonedType; + } if (typeToBeRequired->IsETSTypeParameter()) { auto *const requiredClone = typeToBeRequired->Clone(this); @@ -1066,16 +1112,12 @@ Type *ETSChecker::HandleRequiredType(Type *typeToBeRequired) if (typeToBeRequired->IsETSUnionType()) { ArenaVector unionTypes(ProgramAllocator()->Adapter()); for (auto *type : typeToBeRequired->AsETSUnionType()->ConstituentTypes()) { - if (type->IsETSObjectType()) { - type = type->Clone(this); - ES2PANDA_ASSERT(type != nullptr); - MakePropertiesNonNullish(type->AsETSObjectType()); - } - if (type->IsETSNullType() || type->IsETSUndefinedType()) { continue; } + type = HandleRequiredType(type); + unionTypes.emplace_back(type); } @@ -1084,12 +1126,11 @@ Type *ETSChecker::HandleRequiredType(Type *typeToBeRequired) if (typeToBeRequired->IsETSObjectType()) { typeToBeRequired->AsETSObjectType()->InstanceFields(); // call to instantiate properties + auto clonedType = typeToBeRequired->Clone(this); + MakePropertiesNonNullish(clonedType->MaybeBaseTypeOfGradualType()->AsETSObjectType()); + return clonedType; } - typeToBeRequired = typeToBeRequired->Clone(this); - - MakePropertiesNonNullish(typeToBeRequired->MaybeBaseTypeOfGradualType()->AsETSObjectType()); - return typeToBeRequired; } diff --git a/ets2panda/test/ast/compiler/ets/partialType_invalid_generic.ets b/ets2panda/test/ast/compiler/ets/partialType_invalid_generic.ets new file mode 100644 index 0000000000..7921979376 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/partialType_invalid_generic.ets @@ -0,0 +1,25 @@ +/* + * 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 { + let f: Partial/* @@ label1 */<()=>void> = () => {}; + let f1: Partial/* @@ label2 */; + let f2: Partial/* @@ label3 */; + f2=undefined; +} + +/* @@@ label1 Error TypeError: '() => void' is invalid in Partial because it cannot be considered as class or interface. */ +/* @@@ label2 Error TypeError: 'null' is invalid in Partial because it cannot be considered as class or interface. */ +/* @@@ label3 Error TypeError: 'undefined' is invalid in Partial because it cannot be considered as class or interface. */ diff --git a/ets2panda/test/ast/compiler/ets/readonly_invalid_generic.ets b/ets2panda/test/ast/compiler/ets/readonly_invalid_generic.ets new file mode 100644 index 0000000000..fd91b24607 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/readonly_invalid_generic.ets @@ -0,0 +1,25 @@ +/* + * 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 { + let f: Readonly/* @@ label1 */<()=>void> = () => {}; + let f1: Readonly/* @@ label2 */; + let f2: Readonly/* @@ label3 */; + f2=undefined; +} + +/* @@@ label1 Error TypeError: '() => void' is invalid in Readonly because it cannot be considered as class or interface. */ +/* @@@ label2 Error TypeError: 'null' is invalid in Readonly because it cannot be considered as class or interface. */ +/* @@@ label3 Error TypeError: 'undefined' is invalid in Readonly because it cannot be considered as class or interface. */ diff --git a/ets2panda/test/ast/compiler/ets/requiredType_invalid_generic.ets b/ets2panda/test/ast/compiler/ets/requiredType_invalid_generic.ets new file mode 100644 index 0000000000..56e2c2a719 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/requiredType_invalid_generic.ets @@ -0,0 +1,25 @@ +/* + * 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 { + let f: Required/* @@ label1 */<()=>void> = () => {}; + let f1: Required/* @@ label2 */; + let f2: Required/* @@ label3 */; + f2=undefined; +} + +/* @@@ label1 Error TypeError: '() => void' is invalid in Required because it cannot be considered as class or interface. */ +/* @@@ label2 Error TypeError: 'null' is invalid in Required because it cannot be considered as class or interface. */ +/* @@@ label3 Error TypeError: 'undefined' is invalid in Required because it cannot be considered as class or interface. */ diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index cd533f2c16..cde4f7dd21 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -1466,6 +1466,10 @@ semantic: id: 285 message: "Unable to resolve type." +- name: TYPE_INVALID_AS_CLASS_OR_INTERFACE + id: 1337 + message: "'{}' is invalid in {} because it cannot be considered as class or interface." + - name: TYPE_MISMATCH_AT_IDX id: 46 message: "Type '{}' is not compatible with type '{}' at index {}" -- Gitee