已合并
Defined a CTE for invalid recursive type alias constructions #10173
fanglou创建于 3月17日
Defined a CTE for invalid recursive type alias constructions #10173
已合并
共 3 个文件变更+66-22
| @@ -959,6 +959,10 @@ private: | |||
| 959 | // Check type alias for recursive cases | 959 | // Check type alias for recursive cases |
| 960 | bool IsAllowedTypeAliasRecursion(const ir::TSTypeAliasDeclaration *typeAliasNode, | 960 | bool IsAllowedTypeAliasRecursion(const ir::TSTypeAliasDeclaration *typeAliasNode, |
| 961 | std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases); | 961 | std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases); |
| 962 | + bool CheckTypeReferencePartRecursion(ir::ETSTypeReferencePart *part, | ||
| 963 | + std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases); | ||
| 964 | + bool CheckTypeParamsRecursion(ir::TSTypeParameterInstantiation *typeParams, | ||
| 965 | + std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases); | ||
| 962 | 966 | ||
| 963 | bool IsExceptionOrErrorType(checker::Type *type); | 967 | bool IsExceptionOrErrorType(checker::Type *type); |
| 964 | 968 | ||
| @@ -781,6 +781,43 @@ Type *ETSChecker::GuaranteedTypeForUnionFieldAccess(ir::MemberExpression *member | |||
| 781 | return CreateETSUnionType(std::move(apparentTypes)); | 781 | return CreateETSUnionType(std::move(apparentTypes)); |
| 782 | } | 782 | } |
| 783 | 783 | ||
| 784 | +bool ETSChecker::CheckTypeParamsRecursion(ir::TSTypeParameterInstantiation *typeParams, | ||
| 785 | + std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases) | ||
| 786 | +{ | ||
| 787 | + bool allowed = true; | ||
| 788 | + for (auto *typeParam : typeParams->Params()) { | ||
| 789 | + if (typeParam->IsETSTypeReference()) { | ||
| 790 | + allowed &= CheckTypeReferencePartRecursion(typeParam->AsETSTypeReference()->Part(), typeAliases); | ||
| 791 | + } | ||
| 792 | + } | ||
| 793 | + return allowed; | ||
| 794 | +} | ||
| 795 | + | ||
| 796 | +bool ETSChecker::CheckTypeReferencePartRecursion(ir::ETSTypeReferencePart *part, | ||
| 797 | + std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases) | ||
| 798 | +{ | ||
| 799 | + if (!part->Name()->IsIdentifier() && !part->Name()->IsTSQualifiedName()) { | ||
| 800 | + return false; | ||
| 801 | + } | ||
| 802 | + auto *var = part->Name()->IsIdentifier() ? part->Name()->Variable() | ||
| 803 | + : part->Name()->AsTSQualifiedName()->Right()->Variable(); | ||
| 804 | + if (part->Name()->Variable() == nullptr) { | ||
| 805 | + return true; | ||
| 806 | + } | ||
| 807 | + | ||
| 808 | + auto const *const decl = var->Declaration(); | ||
| 809 | + if (auto const *const node = decl->Node(); node != nullptr && node->IsTSTypeAliasDeclaration()) { | ||
| 810 | + bool allowed = IsAllowedTypeAliasRecursion(node->AsTSTypeAliasDeclaration(), typeAliases); | ||
| 811 | + if (allowed && part->TypeParams() != nullptr) { | ||
| 812 | + allowed &= CheckTypeParamsRecursion(part->TypeParams(), typeAliases); | ||
| 813 | + } | ||
| 814 | + | ||
| 815 | + return allowed; | ||
| 816 | + } | ||
| 817 | + | ||
| 818 | + return true; | ||
| 819 | +} | ||
| 820 | + | ||
| 784 | bool ETSChecker::IsAllowedTypeAliasRecursion(const ir::TSTypeAliasDeclaration *typeAliasNode, | 821 | bool ETSChecker::IsAllowedTypeAliasRecursion(const ir::TSTypeAliasDeclaration *typeAliasNode, |
| 785 | std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases) | 822 | std::unordered_set<const ir::TSTypeAliasDeclaration *> &typeAliases) |
| 786 | { | 823 | { |
| @@ -792,39 +829,23 @@ bool ETSChecker::IsAllowedTypeAliasRecursion(const ir::TSTypeAliasDeclaration *t | |||
| 792 | return false; | 829 | return false; |
| 793 | } | 830 | } |
| 794 | 831 | ||
| 795 | - auto typeAliasDeclarationCheck = [this, &typeAliases](ir::ETSTypeReferencePart *part) { | ||
| 796 | - if (!part->Name()->IsIdentifier() && !part->Name()->IsTSQualifiedName()) { | ||
| 797 | - return false; | ||
| 798 | - } | ||
| 799 | - auto *var = part->Name()->IsIdentifier() ? part->Name()->Variable() | ||
| 800 | - : part->Name()->AsTSQualifiedName()->Right()->Variable(); | ||
| 801 | - if (part->Name()->Variable() == nullptr) { | ||
| 802 | - return true; | ||
| 803 | - } | ||
| 804 | - | ||
| 805 | - auto const *const decl = var->Declaration(); | ||
| 806 | - if (auto const *const node = decl->Node(); node != nullptr && node->IsTSTypeAliasDeclaration()) { | ||
| 807 | - return IsAllowedTypeAliasRecursion(node->AsTSTypeAliasDeclaration(), typeAliases); | ||
| 808 | - } | ||
| 809 | - | ||
| 810 | - return true; | ||
| 811 | - }; | ||
| 812 | - | ||
| 813 | if (typeAliasNode->TypeAnnotation()->IsETSFunctionType() && | 832 | if (typeAliasNode->TypeAnnotation()->IsETSFunctionType() && |
| 814 | typeAliasNode->TypeAnnotation()->AsETSFunctionType()->ReturnType()->IsETSTypeReference()) { | 833 | typeAliasNode->TypeAnnotation()->AsETSFunctionType()->ReturnType()->IsETSTypeReference()) { |
| 815 | - isAllowedRerursiveType &= typeAliasDeclarationCheck( | 834 | + isAllowedRerursiveType &= CheckTypeReferencePartRecursion( |
| 816 | - typeAliasNode->TypeAnnotation()->AsETSFunctionType()->ReturnType()->AsETSTypeReference()->Part()); | 835 | + typeAliasNode->TypeAnnotation()->AsETSFunctionType()->ReturnType()->AsETSTypeReference()->Part(), |
| 836 | + typeAliases); | ||
| 817 | } | 837 | } |
| 818 | 838 | ||
| 819 | if (typeAliasNode->TypeAnnotation()->IsETSTypeReference()) { | 839 | if (typeAliasNode->TypeAnnotation()->IsETSTypeReference()) { |
| 820 | isAllowedRerursiveType &= | 840 | isAllowedRerursiveType &= |
| 821 | - typeAliasDeclarationCheck(typeAliasNode->TypeAnnotation()->AsETSTypeReference()->Part()); | 841 | + CheckTypeReferencePartRecursion(typeAliasNode->TypeAnnotation()->AsETSTypeReference()->Part(), typeAliases); |
| 822 | } | 842 | } |
| 823 | 843 | ||
| 824 | if (isAllowedRerursiveType && typeAliasNode->TypeAnnotation()->IsETSUnionType()) { | 844 | if (isAllowedRerursiveType && typeAliasNode->TypeAnnotation()->IsETSUnionType()) { |
| 825 | for (auto &type : typeAliasNode->TypeAnnotation()->AsETSUnionType()->Types()) { | 845 | for (auto &type : typeAliasNode->TypeAnnotation()->AsETSUnionType()->Types()) { |
| 826 | if (type->IsETSTypeReference()) { | 846 | if (type->IsETSTypeReference()) { |
| 827 | - isAllowedRerursiveType &= typeAliasDeclarationCheck(type->AsETSTypeReference()->Part()); | 847 | + isAllowedRerursiveType &= |
| 848 | + CheckTypeReferencePartRecursion(type->AsETSTypeReference()->Part(), typeAliases); | ||
| 828 | } | 849 | } |
| 829 | } | 850 | } |
| 830 | } | 851 | } |
| @@ -0,0 +1,19 @@ | |||
| 1 | +/* | ||
| 2 | + * Copyright (c) 2026 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 | +type C<T> = T | ||
| 17 | +type A = C<A> | ||
| 18 | + | ||
| 19 | +/* @@? 17:1 Error Semantic error ESE0311: Circular type alias reference */ | ||