diff --git a/ets2panda/ir/ts/tsBooleanKeyword.cpp b/ets2panda/ir/ts/tsBooleanKeyword.cpp index bae3ac4ae1e718ae4b90c99062bb9beb761f0568..6c4e40ab63ea9288dfb0396c24b09e82e2dff1dd 100644 --- a/ets2panda/ir/ts/tsBooleanKeyword.cpp +++ b/ets2panda/ir/ts/tsBooleanKeyword.cpp @@ -72,4 +72,26 @@ checker::VerifiedType TSBooleanKeyword::Check(checker::ETSChecker *checker) { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSBooleanKeyword *TSBooleanKeyword::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *clone = allocator->New(allocator); + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsBooleanKeyword.h b/ets2panda/ir/ts/tsBooleanKeyword.h index bf726daf82ca7705ad0c7596a5e236ae0f6550e8..94d597e4452b70e98d2a40bc3a8d85033d0090ef 100644 --- a/ets2panda/ir/ts/tsBooleanKeyword.h +++ b/ets2panda/ir/ts/tsBooleanKeyword.h @@ -32,6 +32,7 @@ public: checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check(checker::ETSChecker *checker) override; + TSBooleanKeyword *Clone(ArenaAllocator *allocator, AstNode *parent) override; void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsFunctionType.cpp b/ets2panda/ir/ts/tsFunctionType.cpp index 89e4751aeb965dd49d3133f81e7346ea7512f16d..29c10a2a2685c43a0d3b3e061477e51ef94a0c1b 100644 --- a/ets2panda/ir/ts/tsFunctionType.cpp +++ b/ets2panda/ir/ts/tsFunctionType.cpp @@ -84,4 +84,42 @@ checker::Type *TSFunctionType::GetType([[maybe_unused]] checker::ETSChecker *che { return nullptr; } + +TSFunctionType *TSFunctionType::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + // Clone the function signature + FunctionSignature clonedSignature = signature_.Clone(allocator); + + auto *clone = allocator->New(std::move(clonedSignature), allocator); + + // Set parent relationships for cloned signature components + if (clone->signature_.TypeParams() != nullptr) { + clone->signature_.TypeParams()->SetParent(clone); + } + for (auto *param : clone->signature_.Params()) { + param->SetParent(clone); + } + if (clone->signature_.ReturnType() != nullptr) { + clone->signature_.ReturnType()->SetParent(clone); + } + + clone->SetNullable(nullable_); + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsFunctionType.h b/ets2panda/ir/ts/tsFunctionType.h index b66474ef0ee9e61a68413734a5d58f92ccb4c5fb..dcf8375b4c4f1e44f637e203fd3e7da0fb00d4be 100644 --- a/ets2panda/ir/ts/tsFunctionType.h +++ b/ets2panda/ir/ts/tsFunctionType.h @@ -95,6 +95,8 @@ public: checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; + TSFunctionType *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsIndexedAccessType.cpp b/ets2panda/ir/ts/tsIndexedAccessType.cpp index e1e110231a601b905106b838db5c8fa0c83df80d..b13cd33e4428fda31065a87be5a1533af45557ab 100644 --- a/ets2panda/ir/ts/tsIndexedAccessType.cpp +++ b/ets2panda/ir/ts/tsIndexedAccessType.cpp @@ -95,4 +95,33 @@ checker::VerifiedType TSIndexedAccessType::Check([[maybe_unused]] checker::ETSCh { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSIndexedAccessType *TSIndexedAccessType::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *clonedObjectType = objectType_->Clone(allocator, nullptr)->AsTypeNode(); + auto *clonedIndexType = indexType_->Clone(allocator, nullptr)->AsTypeNode(); + + auto *clone = allocator->New(clonedObjectType, clonedIndexType, allocator); + + // Set parent relationships + clonedObjectType->SetParent(clone); + clonedIndexType->SetParent(clone); + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsIndexedAccessType.h b/ets2panda/ir/ts/tsIndexedAccessType.h index a50a4c24d648c5c0843debb23dc41b262a4a4a2d..769d134fdc2e15a561d752043747a1979fc770c8 100644 --- a/ets2panda/ir/ts/tsIndexedAccessType.h +++ b/ets2panda/ir/ts/tsIndexedAccessType.h @@ -52,6 +52,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + TSIndexedAccessType *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsLiteralType.cpp b/ets2panda/ir/ts/tsLiteralType.cpp index a679912bf4dbec77ce97320c56050f0a5e95b96b..5bf04d111fbe64997803600b4182578d903ae98a 100644 --- a/ets2panda/ir/ts/tsLiteralType.cpp +++ b/ets2panda/ir/ts/tsLiteralType.cpp @@ -83,4 +83,37 @@ checker::VerifiedType TSLiteralType::Check([[maybe_unused]] checker::ETSChecker { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSLiteralType *TSLiteralType::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + // Clone the literal expression + Expression *clonedLiteral = nullptr; + if (literal_ != nullptr) { + clonedLiteral = literal_->Clone(allocator, nullptr)->AsExpression(); + } + + auto *clone = allocator->New(clonedLiteral, allocator); + + // Set parent for cloned literal + if (clonedLiteral != nullptr) { + clonedLiteral->SetParent(clone); + } + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsLiteralType.h b/ets2panda/ir/ts/tsLiteralType.h index 41c53908727c083505c8b889313f6155a5c5e76c..bc6695a68c3cab7304a1d5036713616b27709230 100644 --- a/ets2panda/ir/ts/tsLiteralType.h +++ b/ets2panda/ir/ts/tsLiteralType.h @@ -41,6 +41,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + TSLiteralType *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsMappedType.cpp b/ets2panda/ir/ts/tsMappedType.cpp index 61da853b75b4d81a1f1d2f1f6cb77ddda83e1e78..2cd6624fbbf2f2ba40a05050dc55c21652811983 100644 --- a/ets2panda/ir/ts/tsMappedType.cpp +++ b/ets2panda/ir/ts/tsMappedType.cpp @@ -97,4 +97,37 @@ checker::VerifiedType TSMappedType::Check([[maybe_unused]] checker::ETSChecker * { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSMappedType *TSMappedType::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *clonedTypeParameter = typeParameter_->Clone(allocator, nullptr)->AsTSTypeParameter(); + auto *clonedTypeAnnotation = + typeAnnotation_ != nullptr ? typeAnnotation_->Clone(allocator, nullptr)->AsTypeNode() : nullptr; + + auto *clone = + allocator->New(clonedTypeParameter, clonedTypeAnnotation, readonly_, optional_, allocator); + + // Set parent relationships + clonedTypeParameter->SetParent(clone); + if (clonedTypeAnnotation != nullptr) { + clonedTypeAnnotation->SetParent(clone); + } + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsMappedType.h b/ets2panda/ir/ts/tsMappedType.h index a452b880dccc405f72f0a93afd88de30148ac235..0b2faa31d02b5d3e9f608668b7f1c70785e7b45f 100644 --- a/ets2panda/ir/ts/tsMappedType.h +++ b/ets2panda/ir/ts/tsMappedType.h @@ -62,6 +62,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + TSMappedType *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsNumberKeyword.cpp b/ets2panda/ir/ts/tsNumberKeyword.cpp index afcee6e7b57be49fbceed2b822755658ede6cfb5..2110b59d50b24dcfdfa02294d40f2331398a3d75 100644 --- a/ets2panda/ir/ts/tsNumberKeyword.cpp +++ b/ets2panda/ir/ts/tsNumberKeyword.cpp @@ -72,4 +72,26 @@ checker::VerifiedType TSNumberKeyword::Check(checker::ETSChecker *checker) { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSNumberKeyword *TSNumberKeyword::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *clone = allocator->New(allocator); + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsNumberKeyword.h b/ets2panda/ir/ts/tsNumberKeyword.h index b0b174c3f5f61280dfec1a96a783c8240ebfef81..5762a5a801894e30c9d9853a09bb2268a3a8cbda 100644 --- a/ets2panda/ir/ts/tsNumberKeyword.h +++ b/ets2panda/ir/ts/tsNumberKeyword.h @@ -33,6 +33,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check(checker::ETSChecker *checker) override; + TSNumberKeyword *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsStringKeyword.cpp b/ets2panda/ir/ts/tsStringKeyword.cpp index be62a340044c1d0222feeb0fb32d75ad919a71d6..8f1eb75b0f5b7147ae791655322f6d0fbe6a5301 100644 --- a/ets2panda/ir/ts/tsStringKeyword.cpp +++ b/ets2panda/ir/ts/tsStringKeyword.cpp @@ -72,4 +72,26 @@ checker::VerifiedType TSStringKeyword::Check(checker::ETSChecker *checker) { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSStringKeyword *TSStringKeyword::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *clone = allocator->New(allocator); + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsStringKeyword.h b/ets2panda/ir/ts/tsStringKeyword.h index ec264c131359011093d4ea7f56e63e180d0d7dd5..8bb71e94e7ed1e7f6795898b77f3c234f77349d5 100644 --- a/ets2panda/ir/ts/tsStringKeyword.h +++ b/ets2panda/ir/ts/tsStringKeyword.h @@ -33,6 +33,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check(checker::ETSChecker *checker) override; + TSStringKeyword *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsTupleType.cpp b/ets2panda/ir/ts/tsTupleType.cpp index d98cbd162299827eb3f569f9e88ad891da90f6aa..a76a006e52875ba92108f4582cff42f61b03990d 100644 --- a/ets2panda/ir/ts/tsTupleType.cpp +++ b/ets2panda/ir/ts/tsTupleType.cpp @@ -158,4 +158,36 @@ checker::VerifiedType TSTupleType::Check([[maybe_unused]] checker::ETSChecker *c { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSTupleType *TSTupleType::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + ArenaVector clonedElementTypes(allocator->Adapter()); + for (auto *elementType : elementTypes_) { + clonedElementTypes.push_back(elementType->Clone(allocator, nullptr)->AsTypeNode()); + } + + auto *clone = allocator->New(std::move(clonedElementTypes), allocator); + + // Set parent relationships for cloned element types + for (auto *elementType : clone->elementTypes_) { + elementType->SetParent(clone); + } + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsTupleType.h b/ets2panda/ir/ts/tsTupleType.h index fbf8b51c87ce70244aa1ff3359bc92c205f194ac..9d2527c1cdd883d66d1831d5803cb3722a0d74b1 100644 --- a/ets2panda/ir/ts/tsTupleType.h +++ b/ets2panda/ir/ts/tsTupleType.h @@ -43,6 +43,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + TSTupleType *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsTypeLiteral.cpp b/ets2panda/ir/ts/tsTypeLiteral.cpp index d13f7662cdbe610180fa9735b0f2f7fc4b03e09e..9ebb23b66d715b568b12710e144407c6df08dc87 100644 --- a/ets2panda/ir/ts/tsTypeLiteral.cpp +++ b/ets2panda/ir/ts/tsTypeLiteral.cpp @@ -95,4 +95,36 @@ checker::VerifiedType TSTypeLiteral::Check([[maybe_unused]] checker::ETSChecker { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSTypeLiteral *TSTypeLiteral::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + ArenaVector clonedMembers(allocator->Adapter()); + for (auto *member : members_) { + clonedMembers.push_back(member->Clone(allocator, nullptr)); + } + + auto *clone = allocator->New(std::move(clonedMembers), allocator); + + // Set parent relationships for cloned members + for (auto *member : clone->members_) { + member->SetParent(clone); + } + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeLiteral.h b/ets2panda/ir/ts/tsTypeLiteral.h index 368d3585d32cb004bb4abe04fb3307252fd2784a..a546f2af0d5c6ad5aa27db2d325d52bebe414436 100644 --- a/ets2panda/ir/ts/tsTypeLiteral.h +++ b/ets2panda/ir/ts/tsTypeLiteral.h @@ -41,6 +41,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + TSTypeLiteral *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsTypeOperator.cpp b/ets2panda/ir/ts/tsTypeOperator.cpp index 2fa2ad26adb615ba84351e83fc4004db8bf77aed..d2342545fd89c0a1e08816d2295e501a7dadc7a3 100644 --- a/ets2panda/ir/ts/tsTypeOperator.cpp +++ b/ets2panda/ir/ts/tsTypeOperator.cpp @@ -79,4 +79,37 @@ checker::VerifiedType TSTypeOperator::Check([[maybe_unused]] checker::ETSChecker { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSTypeOperator *TSTypeOperator::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + // Clone the type annotation + TypeNode *clonedType = nullptr; + if (type_ != nullptr) { + clonedType = type_->Clone(allocator, nullptr)->AsTypeNode(); + } + + auto *clone = allocator->New(clonedType, operatorType_, allocator); + + // Set parent for cloned type + if (clonedType != nullptr) { + clonedType->SetParent(clone); + } + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeOperator.h b/ets2panda/ir/ts/tsTypeOperator.h index 453206e1f0809a92a9b11d815768acd84386e623..1c8e52791c9003e0a7e0c674b73c172806c55430 100644 --- a/ets2panda/ir/ts/tsTypeOperator.h +++ b/ets2panda/ir/ts/tsTypeOperator.h @@ -56,6 +56,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + TSTypeOperator *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsTypeReference.cpp b/ets2panda/ir/ts/tsTypeReference.cpp index e6748d33c67ccf5ab0e02f0d8ce4ade8124d3495..c84f392770bc4c95fca88f6f109b4d11ff7767f0 100644 --- a/ets2panda/ir/ts/tsTypeReference.cpp +++ b/ets2panda/ir/ts/tsTypeReference.cpp @@ -137,4 +137,36 @@ checker::VerifiedType TSTypeReference::Check([[maybe_unused]] checker::ETSChecke { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSTypeReference *TSTypeReference::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *clonedTypeName = typeName_->Clone(allocator, nullptr)->AsExpression(); + auto *clonedTypeParams = + typeParams_ != nullptr ? typeParams_->Clone(allocator, nullptr)->AsTSTypeParameterInstantiation() : nullptr; + + auto *clone = allocator->New(clonedTypeName, clonedTypeParams, allocator); + + // Set parent relationships + clonedTypeName->SetParent(clone); + if (clonedTypeParams != nullptr) { + clonedTypeParams->SetParent(clone); + } + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeReference.h b/ets2panda/ir/ts/tsTypeReference.h index 6391925d31994b1a86bd0cb7579d6c7c24e19197..c5201c14faee1ec78535080cb72e537457e8abe6 100644 --- a/ets2panda/ir/ts/tsTypeReference.h +++ b/ets2panda/ir/ts/tsTypeReference.h @@ -55,6 +55,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; + TSTypeReference *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsUnionType.cpp b/ets2panda/ir/ts/tsUnionType.cpp index aca8a8aa8995d717e562b865296923db544b551e..6841974f5c71086b975b53da8575b953fd212414 100644 --- a/ets2panda/ir/ts/tsUnionType.cpp +++ b/ets2panda/ir/ts/tsUnionType.cpp @@ -92,4 +92,41 @@ checker::Type *TSUnionType::GetType(checker::TSChecker *checker) SetTsType(checker->CreateUnionType(std::move(types))); return TsType(); } + +TSUnionType *TSUnionType::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + // Clone all type nodes in the union + ArenaVector clonedTypes(allocator->Adapter()); + for (auto *type : types_) { + if (type != nullptr) { + clonedTypes.push_back(type->Clone(allocator, nullptr)->AsTypeNode()); + } + } + + auto *clone = allocator->New(std::move(clonedTypes), allocator); + + // Set parent for all cloned types + for (auto *clonedType : clone->Types()) { + if (clonedType != nullptr) { + clonedType->SetParent(clone); + } + } + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsUnionType.h b/ets2panda/ir/ts/tsUnionType.h index 4e51d62068d2a22a9f001aa4d59bbbe190a534fc..a788ee5f6b8f280b70de2f617cedb8fc74729e45 100644 --- a/ets2panda/ir/ts/tsUnionType.h +++ b/ets2panda/ir/ts/tsUnionType.h @@ -41,6 +41,8 @@ public: checker::VerifiedType Check([[maybe_unused]] checker::ETSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; + TSUnionType *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/ir/ts/tsVoidKeyword.cpp b/ets2panda/ir/ts/tsVoidKeyword.cpp index ff09cc56d86b65be9f42072b644186486fbf5a7c..1e7851024076fbf3e8692719d00c6c9856c0056b 100644 --- a/ets2panda/ir/ts/tsVoidKeyword.cpp +++ b/ets2panda/ir/ts/tsVoidKeyword.cpp @@ -72,4 +72,26 @@ checker::VerifiedType TSVoidKeyword::Check(checker::ETSChecker *checker) { return {this, checker->GetAnalyzer()->Check(this)}; } + +TSVoidKeyword *TSVoidKeyword::Clone(ArenaAllocator *allocator, AstNode *parent) +{ + auto *clone = allocator->New(allocator); + + if (parent != nullptr) { + clone->SetParent(parent); + } + + clone->SetRange(Range()); + + // Clone annotations if any + if (!Annotations().empty()) { + ArenaVector annotationUsages {allocator->Adapter()}; + for (auto *annotationUsage : Annotations()) { + annotationUsages.push_back(annotationUsage->Clone(allocator, clone)->AsAnnotationUsage()); + } + clone->SetAnnotations(std::move(annotationUsages)); + } + + return clone; +} } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ts/tsVoidKeyword.h b/ets2panda/ir/ts/tsVoidKeyword.h index afcffd999dfccad0a3ca80300bc86a6a38c6b65c..9a131fe57ac9935a8abb671e5439269c27ce5c35 100644 --- a/ets2panda/ir/ts/tsVoidKeyword.h +++ b/ets2panda/ir/ts/tsVoidKeyword.h @@ -33,6 +33,8 @@ public: checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::VerifiedType Check(checker::ETSChecker *checker) override; + TSVoidKeyword *Clone(ArenaAllocator *allocator, AstNode *parent) override; + void Accept(ASTVisitorT *v) override { v->Accept(this); diff --git a/ets2panda/test/ast/parser/ets/generic_type_alias_clone_fix.ets b/ets2panda/test/ast/parser/ets/generic_type_alias_clone_fix.ets new file mode 100644 index 0000000000000000000000000000000000000000..661d448ab5e739ba97f88096f633d38ebf7d30e9 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/generic_type_alias_clone_fix.ets @@ -0,0 +1,31 @@ +/* + * 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. + */ + +type MyMap = { + kind: K +}; + +type RecordMap = { n: number }; + +let myMap: MyMap<"n"> = { kind: "n" }; + +/* Expected errors - these should NOT cause assertion failures or crashes: */ +/* @@? 16:37 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 16:41 Error SyntaxError: Invalid Type. */ +/* @@? 17:11 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 17:11 Error TypeError: Unresolved reference K */ +/* @@? 20:18 Error SyntaxError: Invalid Type. */ +/* @@? 20:23 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 20:23 Error TypeError: Type name 'number' used in the wrong context */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/type_node_clone_assertion_fix.ets b/ets2panda/test/ast/parser/ets/type_node_clone_assertion_fix.ets new file mode 100644 index 0000000000000000000000000000000000000000..d28120b38d17af8f5663e90155adf747b3998d20 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/type_node_clone_assertion_fix.ets @@ -0,0 +1,35 @@ +/* + * 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. + */ + +// Minimal test case for TypeNode::Clone() fix +// Previously caused: ASSERTION FAILED: clonedNode != typeAliasNode->TypeAnnotation() +// in ValidateGenericTypeAliasForClonedNode at validateHelpers.cpp:242 + +// This specific pattern triggered the assertion failure because TypeNode::Clone() +// was returning 'this' instead of creating a proper clone when TsType() was nullptr +type MyMap = { + kind: K +}; + +type RecordMap = { n: number }; + +// Expected compilation errors for unsupported TypeScript features in ETS: +/* @@? 22:37 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 22:41 Error SyntaxError: Invalid Type. */ +/* @@? 23:11 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 23:11 Error TypeError: Unresolved reference K */ +/* @@? 26:18 Error SyntaxError: Invalid Type. */ +/* @@? 26:23 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 26:23 Error TypeError: Type name 'number' used in the wrong context */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/typenode_clone_brokentype.ets b/ets2panda/test/ast/parser/ets/typenode_clone_brokentype.ets new file mode 100644 index 0000000000000000000000000000000000000000..c3712f9c1f1ba200a2d6d9e11947a44654d381a3 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/typenode_clone_brokentype.ets @@ -0,0 +1,59 @@ +/* + * 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. + */ + +// Focused test case for BrokenTypeNode::Clone() implementation +// This test specifically exercises the BrokenTypeNode cloning that was causing +// the "ASSERTION FAILED: clonedNode != typeAliasNode->TypeAnnotation()" crash + +// This creates BrokenTypeNode instances during parsing due to invalid TypeScript syntax +type BrokenType = { + kind: K +}; + +// Multiple instances to test different patterns +type AnotherBroken = T; +type YetAnother = U; + +// Nested broken types +type NestedBroken = { + nested: K, + value: UndefinedType[K] +}; + +// Function with broken parameter types +type BrokenFunc = (param: T) => void; + +// Test instantiation to trigger ValidateGenericTypeAliasForClonedNode +declare const broken1: BrokenType; +declare const broken2: AnotherBroken; + +/* Expected errors - these should NOT cause assertion failures or crashes: */ +/* @@? 21:33 Error TypeError: Cannot find type 'UndefinedMap'. */ +/* @@? 21:45 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 21:49 Error SyntaxError: Invalid Type. */ +/* @@? 22:11 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 22:11 Error TypeError: Unresolved reference K */ +/* @@? 26:36 Error TypeError: Cannot find type 'NonExistent'. */ +/* @@? 26:47 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 27:27 Error TypeError: Cannot find type 'InvalidInterface'. */ +/* @@? 30:52 Error SyntaxError: Invalid Type. */ +/* @@? 31:13 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 31:14 Error SyntaxError: Unexpected token ','. */ +/* @@? 32:12 Error SyntaxError: Class cannot be used as object. */ +/* @@? 32:12 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 32:12 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@? 36:27 Error TypeError: Cannot find type 'UndefinedInterface'. */ +/* @@? 39:35 Error TypeError: Cannot find type 'any'. */ +/* @@? 40:38 Error TypeError: Cannot find type 'any'. */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/typenode_clone_comprehensive.ets b/ets2panda/test/ast/parser/ets/typenode_clone_comprehensive.ets new file mode 100644 index 0000000000000000000000000000000000000000..e3f3d7459d5343cfb766fb696909123331a969c7 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/typenode_clone_comprehensive.ets @@ -0,0 +1,140 @@ +/* + * 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. + */ + +// Comprehensive test case for TypeNode::Clone() implementations +// This test covers all TypeNode subclasses that were missing Clone implementations +// and caused assertion failures in ValidateGenericTypeAliasForClonedNode + +// Test 1: TSTypeLiteral Clone +type ObjectType = { n: number, s: string, b: boolean }; + +// Test 2: TSNumberKeyword, TSStringKeyword, TSBooleanKeyword Clone +type NumType = number; +type StrType = string; +type BoolType = boolean; + +// Test 3: TSVoidKeyword Clone (in function types) +type VoidFunc = () => void; + +// Test 4: TSTypeOperator Clone (keyof operations) +type KeyofType = T; + +// Test 5: TSIndexedAccessType Clone +type IndexedType = ObjectType[K]; + +// Test 6: TSTupleType Clone +type TupleType = [a: number, b: string]; + +// Test 7: TSMappedType Clone +type MappedType = { [K in keyof ObjectType]: string }; + +// Test 8: TSFunctionType Clone +type FuncType = (v: ObjectType[K]) => void; + +// Test 9: TSLiteralType Clone (string literals) +type LiteralType = K; + +// Test 10: TSUnionType Clone +type UnionType = string | number | boolean; + +// Test 11: BrokenTypeNode Clone (created for invalid syntax) +// This will create BrokenTypeNode instances that need proper cloning +type InvalidType = K; + +// Test 12: Complex nested type with multiple Clone implementations +type ComplexType = { + kind: K, + value: ObjectType[K], + handler: (v: ObjectType[K]) => void, + tuple: [K, ObjectType[K]], + mapped: { [P in K]: ObjectType[P] } +}; + +// Test instantiation to trigger ValidateGenericTypeAliasForClonedNode +declare const test1: ComplexType<'n'>; +declare const test2: ComplexType<'s'>; +declare const test3: ComplexType<'b'>; + +/* Expected errors (these are normal for ETS, but should not crash): */ +/* @@? 1:3 Error TypeError: Class 'UnionType' is already defined with different type. */ +/* @@? 1:3 Error TypeError: Class 'TupleType' is already defined with different type. */ +/* @@? 21:19 Error SyntaxError: Invalid Type. */ +/* @@? 21:24 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 21:24 Error TypeError: Type name 'number' used in the wrong context */ +/* @@? 21:30 Error SyntaxError: Unexpected token ','. */ +/* @@? 21:32 Error SyntaxError: Unexpected token 's'. */ +/* @@? 21:35 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 21:35 Error TypeError: Type name 'string' used in the wrong context */ +/* @@? 21:41 Error SyntaxError: Unexpected token ','. */ +/* @@? 21:43 Error SyntaxError: Unexpected token 'b'. */ +/* @@? 21:46 Error SyntaxError: Unexpected token 'boolean'. */ +/* @@? 21:46 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 32:42 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 35:44 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 35:59 Error SyntaxError: Unexpected token ']'. */ +/* @@? 35:59 Error SyntaxError: Unexpected token, expected ']'. */ +/* @@? 35:60 Error SyntaxError: Unexpected token ']'. */ +/* @@? 38:19 Error TypeError: Cannot find type 'a'. */ +/* @@? 38:20 Error SyntaxError: Unexpected token, expected ',' or ']'. */ +/* @@? 38:20 Error SyntaxError: Unexpected token ':'. */ +/* @@? 38:22 Error SyntaxError: Unexpected token 'number'. */ +/* @@? 38:22 Error TypeError: Type name 'number' used in the wrong context */ +/* @@? 38:28 Error SyntaxError: Unexpected token ','. */ +/* @@? 38:30 Error SyntaxError: Unexpected token 'b'. */ +/* @@? 38:33 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 38:33 Error TypeError: Type name 'string' used in the wrong context */ +/* @@? 38:39 Error SyntaxError: Unexpected token ']'. */ +/* @@? 41:19 Error SyntaxError: Invalid Type. */ +/* @@? 41:22 Error TypeError: Unresolved reference K */ +/* @@? 41:24 Error SyntaxError: Unexpected token, expected ',' or ']'. */ +/* @@? 41:24 Error SyntaxError: Unexpected token 'in'. */ +/* @@? 41:24 Error TypeError: Unresolved reference in */ +/* @@? 41:27 Error SyntaxError: Unexpected token 'keyof'. */ +/* @@? 41:27 Error TypeError: Unresolved reference keyof */ +/* @@? 41:33 Error SyntaxError: Unexpected token 'ObjectType'. */ +/* @@? 41:33 Error TypeError: Type name 'ObjectType' used in the wrong context */ +/* @@? 41:43 Error SyntaxError: Unexpected token ']'. */ +/* @@? 41:44 Error SyntaxError: Unexpected token ':'. */ +/* @@? 41:46 Error SyntaxError: Unexpected token 'string'. */ +/* @@? 41:46 Error TypeError: Type name 'string' used in the wrong context */ +/* @@? 44:41 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 44:60 Error SyntaxError: Unexpected token, expected ']'. */ +/* @@? 54:34 Error TypeError: Cannot find type 'InvalidMap'. */ +/* @@? 54:44 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ +/* @@? 57:67 Error SyntaxError: Invalid Type. */ +/* @@? 58:11 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 58:12 Error SyntaxError: Unexpected token ','. */ +/* @@? 59:12 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 59:12 Error TypeError: Indexed access is not supported for such expression type. */ +/* @@? 59:12 Error TypeError: Type name 'ObjectType' used in the wrong context */ +/* @@? 59:25 Error SyntaxError: Unexpected token ','. */ +/* @@? 60:14 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 60:29 Error SyntaxError: Unexpected token, expected ']'. */ +/* @@? 60:36 Error SyntaxError: Unexpected token 'void'. */ +/* @@? 60:40 Error SyntaxError: Unexpected token ','. */ +/* @@? 61:12 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 61:16 Error TypeError: Type name 'ObjectType' used in the wrong context */ +/* @@? 61:16 Error TypeError: Indexed access is not supported for such expression type. */ +/* @@? 61:30 Error SyntaxError: Unexpected token ','. */ +/* @@? 62:13 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 62:16 Error TypeError: Unresolved reference P */ +/* @@? 62:18 Error SyntaxError: Unexpected token, expected ',' or ']'. */ +/* @@? 62:18 Error SyntaxError: Unexpected token 'in'. */ +/* @@? 62:21 Error SyntaxError: Unexpected token 'K'. */ +/* @@? 62:22 Error SyntaxError: Unexpected token ']'. */ +/* @@? 62:23 Error SyntaxError: Unexpected token ':'. */ +/* @@? 62:25 Error SyntaxError: Unexpected token 'ObjectType'. */ +/* @@? 62:25 Error TypeError: Type name 'ObjectType' used in the wrong context */ +/* @@? 62:25 Error TypeError: Indexed access is not supported for such expression type. */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/typenode_clone_primitives.ets b/ets2panda/test/ast/parser/ets/typenode_clone_primitives.ets new file mode 100644 index 0000000000000000000000000000000000000000..045aaf46b1496574677a8c42db112eaba7a8ad02 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/typenode_clone_primitives.ets @@ -0,0 +1,71 @@ +/* + * 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. + */ + +// Focused test case for primitive TypeNode Clone implementations +// Tests TSNumberKeyword, TSStringKeyword, TSBooleanKeyword, TSVoidKeyword cloning + +// Simple primitive type aliases that exercise Clone +type NumAlias = T; +type StrAlias = T; +type BoolAlias = T; +type VoidAlias = T; + +// Generic constraints using primitives +type NumericConstraint = T; +type StringConstraint = T; +type BooleanConstraint = T; + +// Function types with primitive returns (exercises TSVoidKeyword) +type VoidFunction = (param: T) => void; +type NumberFunction = (param: T) => number; +type StringFunction = (param: T) => string; +type BooleanFunction = (param: T) => boolean; + +// Complex types mixing primitives +type MixedType = { + numField: N, + strField: S, + boolField: B, + voidMethod: () => void +}; + +// Test instantiation to trigger ValidateGenericTypeAliasForClonedNode +declare const num: NumAlias<42>; +declare const str: StrAlias<"test">; +declare const bool: BoolAlias; + +/* Expected syntax errors (normal for ETS): */ +/* @@? 37:73 Error SyntaxError: Invalid Type. */ +/* @@? 38:15 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 38:15 Error TypeError: Unresolved reference N */ +/* @@? 38:16 Error SyntaxError: Unexpected token ','. */ +/* @@? 39:15 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 39:15 Error TypeError: Unresolved reference S */ +/* @@? 39:16 Error SyntaxError: Unexpected token ','. */ +/* @@? 40:16 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 40:16 Error TypeError: Unresolved reference B */ +/* @@? 40:17 Error SyntaxError: Unexpected token ','. */ +/* @@? 41:17 Error SyntaxError: Label must be followed by a loop statement. */ +/* @@? 41:23 Error SyntaxError: Unexpected token 'void'. */ +/* @@? 45:20 Error TypeError: Type alias declaration is generic, but no type parameters were provided */ +/* @@? 45:29 Error SyntaxError: Unexpected token, expected '>'. */ +/* @@? 45:29 Error SyntaxError: Unexpected token '>'. */ +/* @@? 45:29 Error SyntaxError: Invalid Type. */ +/* @@? 45:32 Error SyntaxError: Unexpected token ';'. */ +/* @@? 47:21 Error TypeError: Type alias declaration is generic, but no type parameters were provided */ +/* @@? 47:31 Error SyntaxError: Invalid Type. */ +/* @@? 47:31 Error SyntaxError: Unexpected token, expected '>'. */ +/* @@? 47:31 Error SyntaxError: Unexpected token '>'. */ +/* @@? 47:36 Error SyntaxError: Unexpected token ';'. */ \ No newline at end of file