1 /*
2 * Copyright (c) 2021-2025 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 #include "etsTypeReferencePart.h"
17
18 #include "checker/ETSchecker.h"
19 #include "checker/ets/typeRelationContext.h"
20 #include "checker/TSchecker.h"
21 #include "compiler/core/ETSGen.h"
22 #include "compiler/core/pandagen.h"
23
24 namespace ark::es2panda::ir {
TransformChildren(const NodeTransformer & cb,std::string_view const transformationName)25 void ETSTypeReferencePart::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
26 {
27 if (auto *transformedNode = cb(name_); name_ != transformedNode) {
28 name_->SetTransformedNode(transformationName, transformedNode);
29 name_ = transformedNode->AsExpression();
30 }
31
32 if (typeParams_ != nullptr) {
33 if (auto *transformedNode = cb(typeParams_); typeParams_ != transformedNode) {
34 typeParams_->SetTransformedNode(transformationName, transformedNode);
35 typeParams_ = transformedNode->AsTSTypeParameterInstantiation();
36 }
37 }
38
39 if (prev_ != nullptr) {
40 if (auto *transformedNode = cb(prev_); prev_ != transformedNode) {
41 prev_->SetTransformedNode(transformationName, transformedNode);
42 prev_ = transformedNode->AsETSTypeReferencePart();
43 }
44 }
45 }
46
Iterate(const NodeTraverser & cb) const47 void ETSTypeReferencePart::Iterate(const NodeTraverser &cb) const
48 {
49 cb(name_);
50
51 if (typeParams_ != nullptr) {
52 cb(typeParams_);
53 }
54
55 if (prev_ != nullptr) {
56 cb(prev_);
57 }
58 }
59
Dump(ir::AstDumper * dumper) const60 void ETSTypeReferencePart::Dump(ir::AstDumper *dumper) const
61 {
62 dumper->Add({{"type", "ETSTypeReferencePart"},
63 {"name", name_},
64 {"typeParams", AstDumper::Optional(typeParams_)},
65 {"previous", AstDumper::Optional(prev_)}});
66 }
67
Dump(ir::SrcDumper * dumper) const68 void ETSTypeReferencePart::Dump(ir::SrcDumper *dumper) const
69 {
70 ES2PANDA_ASSERT(name_ != nullptr);
71 name_->Dump(dumper);
72 if (typeParams_ != nullptr) {
73 typeParams_->Dump(dumper);
74 }
75 }
76
Compile(compiler::PandaGen * pg) const77 void ETSTypeReferencePart::Compile(compiler::PandaGen *pg) const
78 {
79 pg->GetAstCompiler()->Compile(this);
80 }
Compile(compiler::ETSGen * etsg) const81 void ETSTypeReferencePart::Compile(compiler::ETSGen *etsg) const
82 {
83 etsg->GetAstCompiler()->Compile(this);
84 }
85
Check(checker::TSChecker * checker)86 checker::Type *ETSTypeReferencePart::Check(checker::TSChecker *checker)
87 {
88 return checker->GetAnalyzer()->Check(this);
89 }
90
Check(checker::ETSChecker * checker)91 checker::VerifiedType ETSTypeReferencePart::Check(checker::ETSChecker *checker)
92 {
93 return {this, checker->GetAnalyzer()->Check(this)};
94 }
95
HandleFixedArrayType(checker::ETSChecker * const checker,ETSTypeReferencePart * ref)96 static checker::Type *HandleFixedArrayType(checker::ETSChecker *const checker, ETSTypeReferencePart *ref)
97 {
98 auto typeParams = ref->TypeParams();
99 if (typeParams == nullptr || typeParams->Params().size() != 1) {
100 checker->LogError(diagnostic::FIXED_ARRAY_PARAM_ERROR, {}, ref->Start());
101 return checker->GlobalTypeError();
102 }
103 return checker->CreateETSArrayType(typeParams->Params()[0]->GetType(checker), ref->IsReadonlyType());
104 }
105
HandlePartialType(checker::ETSChecker * const checker,ETSTypeReferencePart * ref)106 static checker::Type *HandlePartialType(checker::ETSChecker *const checker, ETSTypeReferencePart *ref)
107 {
108 auto *baseType = checker->HandleUtilityTypeParameterNode(ref->TypeParams(), ref->GetIdent());
109 if (baseType != nullptr && baseType->IsETSObjectType() && !baseType->AsETSObjectType()->TypeArguments().empty()) {
110 // we treat Partial<A<T,D>> class as a different copy from A<T,D> now,
111 // but not a generic type param for Partial<>
112 if (ref->TypeParams() != nullptr) {
113 for (auto &typeRef : ref->TypeParams()->Params()) {
114 checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(),
115 typeRef->AsETSTypeReference()->Part()->TypeParams(), ref->Start());
116 baseType = ctx.Result();
117 }
118 }
119 }
120 return baseType;
121 }
122
CheckPredefinedBuiltinTypes(checker::ETSChecker * const checker,ETSTypeReferencePart * ref)123 static checker::Type *CheckPredefinedBuiltinTypes(checker::ETSChecker *const checker, ETSTypeReferencePart *ref)
124 {
125 auto const ident = ref->GetIdent();
126 if (ident->Name() == compiler::Signatures::ANY_TYPE_NAME) {
127 return checker->GlobalETSAnyType();
128 }
129 if (ident->Name() == compiler::Signatures::UNDEFINED) {
130 return checker->GlobalETSUndefinedType();
131 }
132 if (ident->Name() == compiler::Signatures::NULL_LITERAL) {
133 return checker->GlobalETSNullType();
134 }
135 if (ident->Name() == compiler::Signatures::NEVER_TYPE_NAME) {
136 return checker->GlobalETSNeverType();
137 }
138
139 if (ident->Name() == compiler::Signatures::READONLY_TYPE_NAME ||
140 ident->Name() == compiler::Signatures::REQUIRED_TYPE_NAME) {
141 return checker->HandleUtilityTypeParameterNode(ref->TypeParams(), ident);
142 }
143 if (ident->Name() == compiler::Signatures::PARTIAL_TYPE_NAME) {
144 return HandlePartialType(checker, ref);
145 }
146 if (ident->Name() == compiler::Signatures::FIXED_ARRAY_TYPE_NAME) {
147 return HandleFixedArrayType(checker, ref);
148 }
149 return nullptr;
150 }
151
CheckTypeAliaLoop(ETSTypeReferencePart * ref,varbinder::Variable * variable)152 [[maybe_unused]] static bool CheckTypeAliaLoop(ETSTypeReferencePart *ref, varbinder::Variable *variable)
153 {
154 auto typeAliasDecl = variable->Declaration()->Node()->AsTSTypeAliasDeclaration();
155 auto typeDeclaration = typeAliasDecl->TypeParams();
156 if (typeDeclaration == nullptr) {
157 return false;
158 }
159
160 for (auto *param : typeDeclaration->Params()) {
161 auto constraint = param->Constraint();
162 if (constraint == nullptr || !constraint->IsETSTypeReference()) {
163 continue;
164 }
165
166 auto part = constraint->AsETSTypeReference()->Part();
167 if (part == ref) {
168 return true;
169 }
170 }
171
172 return false;
173 }
174
HandleInternalTypes(checker::ETSChecker * const checker)175 checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *const checker)
176 {
177 ES2PANDA_ASSERT(name_->IsIdentifier() || name_->IsTSQualifiedName());
178
179 Identifier *const ident = GetIdent();
180 varbinder::Variable *variable = nullptr;
181
182 if (name_->IsIdentifier()) {
183 variable = ident->Variable();
184 } else {
185 if (name_->AsTSQualifiedName()->Left()->Variable() != nullptr &&
186 name_->AsTSQualifiedName()->Left()->Variable()->TsType() != nullptr &&
187 name_->AsTSQualifiedName()->Left()->Variable()->TsType()->IsETSObjectType()) {
188 variable = name_->AsTSQualifiedName()->Left()->Variable()->TsType()->AsETSObjectType()->GetProperty(
189 ident->Name(), checker::PropertySearchFlags::SEARCH_DECL);
190 }
191 }
192
193 if (variable != nullptr && variable->Declaration()->IsTypeAliasDecl()) {
194 if (CheckTypeAliaLoop(this, variable)) {
195 checker->LogError(diagnostic::CYCLIC_ALIAS, {}, Start());
196 return checker->GlobalTypeError();
197 }
198 return checker->HandleTypeAlias(name_, typeParams_,
199 variable->Declaration()->AsTypeAliasDecl()->Node()->AsTSTypeAliasDeclaration());
200 }
201
202 if (auto res = CheckPredefinedBuiltinTypes(checker, this); res != nullptr) {
203 return res;
204 }
205
206 if (ident->IsErrorPlaceHolder()) {
207 return checker->GlobalTypeError();
208 }
209
210 return nullptr;
211 }
212
GetType(checker::ETSChecker * checker)213 checker::Type *ETSTypeReferencePart::GetType(checker::ETSChecker *checker)
214 {
215 if (TypeParams() != nullptr) {
216 for (auto *param : TypeParams()->Params()) {
217 checker->CheckAnnotations(param->Annotations());
218 if (param->IsETSTypeReference() && param->AsETSTypeReference()->Part()->Name()->IsTSQualifiedName()) {
219 param->Check(checker);
220 }
221 }
222 }
223 if (prev_ == nullptr) {
224 if (name_->IsIdentifier() || name_->IsTSQualifiedName()) {
225 SetTsType(HandleInternalTypes(checker));
226 }
227
228 if (TsType() == nullptr) {
229 checker::Type *baseType = checker->GetReferencedTypeBase(name_);
230
231 ES2PANDA_ASSERT(baseType != nullptr);
232 if (baseType->IsETSObjectType()) {
233 checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), typeParams_, Start());
234 SetTsType(ctx.Result());
235 } else {
236 SetTsType(baseType);
237 }
238 }
239 } else {
240 checker::Type *baseType = prev_->GetType(checker);
241 SetTsType(checker->GetReferencedTypeFromBase(baseType, name_));
242 }
243 return TsType();
244 }
245
Clone(ArenaAllocator * const allocator,AstNode * const parent)246 ETSTypeReferencePart *ETSTypeReferencePart::Clone(ArenaAllocator *const allocator, AstNode *const parent)
247 {
248 auto *const nameClone = name_ != nullptr ? name_->Clone(allocator, nullptr)->AsExpression() : nullptr;
249 auto *const typeParamsClone =
250 typeParams_ != nullptr ? typeParams_->Clone(allocator, nullptr)->AsTSTypeParameterInstantiation() : nullptr;
251 auto *const prevClone = prev_ != nullptr ? prev_->Clone(allocator, nullptr)->AsETSTypeReferencePart() : nullptr;
252 auto *const clone = allocator->New<ETSTypeReferencePart>(nameClone, typeParamsClone, prevClone, allocator);
253
254 if (nameClone != nullptr) {
255 nameClone->SetParent(clone);
256 }
257
258 if (typeParamsClone != nullptr) {
259 typeParamsClone->SetParent(clone);
260 }
261
262 if (prevClone != nullptr) {
263 prevClone->SetParent(clone);
264 }
265
266 ES2PANDA_ASSERT(clone);
267 if (parent != nullptr) {
268 clone->SetParent(parent);
269 }
270
271 clone->SetRange(Range());
272 return clone;
273 }
274
GetIdent()275 ir::Identifier *ETSTypeReferencePart::GetIdent()
276 {
277 if (name_->IsTSQualifiedName()) {
278 auto ident = name_->AsTSQualifiedName()->Right();
279 ES2PANDA_ASSERT(ident->IsIdentifier());
280 return ident->AsIdentifier();
281 }
282 return name_->AsIdentifier();
283 }
284
Construct(ArenaAllocator * allocator)285 ETSTypeReferencePart *ETSTypeReferencePart::Construct(ArenaAllocator *allocator)
286 {
287 return allocator->New<ETSTypeReferencePart>(nullptr, nullptr, nullptr, allocator);
288 }
289
CopyTo(AstNode * other) const290 void ETSTypeReferencePart::CopyTo(AstNode *other) const
291 {
292 auto otherImpl = other->AsETSTypeReferencePart();
293
294 otherImpl->name_ = name_;
295 otherImpl->typeParams_ = typeParams_;
296 otherImpl->prev_ = prev_;
297
298 TypeNode::CopyTo(other);
299 }
300
301 } // namespace ark::es2panda::ir
302