• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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