• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 <functional>
17 #include "checker/ETSchecker.h"
18 
19 #include "checker/types/globalTypesHolder.h"
20 #include "checker/types/ets/byteType.h"
21 #include "checker/types/ets/charType.h"
22 #include "checker/types/ets/etsDynamicFunctionType.h"
23 #include "checker/types/ets/etsDynamicType.h"
24 #include "checker/types/ets/etsStringType.h"
25 #include "checker/types/ets/etsUnionType.h"
26 #include "checker/types/ets/shortType.h"
27 #include "compiler/lowering/ets/enumLowering.h"
28 #include "generated/signatures.h"
29 #include "ir/base/classDefinition.h"
30 #include "ir/statements/classDeclaration.h"
31 #include "ir/base/scriptFunction.h"
32 #include "ir/ets/etsScript.h"
33 #include "ir/expressions/identifier.h"
34 #include "ir/ts/tsEnumDeclaration.h"
35 #include "ir/ts/tsEnumMember.h"
36 #include "ir/ts/tsInterfaceDeclaration.h"
37 #include "checker/ets/boxingConverter.h"
38 #include "util/helpers.h"
39 #include "checker/types/ts/bigintType.h"
40 
41 namespace ark::es2panda::checker {
CreateByteType(int8_t value)42 ByteType *ETSChecker::CreateByteType(int8_t value)
43 {
44     return Allocator()->New<ByteType>(value);
45 }
46 
CreateETSBooleanType(bool value)47 ETSBooleanType *ETSChecker::CreateETSBooleanType(bool value)
48 {
49     return Allocator()->New<ETSBooleanType>(value);
50 }
51 
CreateDoubleType(double value)52 DoubleType *ETSChecker::CreateDoubleType(double value)
53 {
54     return Allocator()->New<DoubleType>(value);
55 }
56 
CreateFloatType(float value)57 FloatType *ETSChecker::CreateFloatType(float value)
58 {
59     return Allocator()->New<FloatType>(value);
60 }
61 
CreateIntType(int32_t value)62 IntType *ETSChecker::CreateIntType(int32_t value)
63 {
64     return Allocator()->New<IntType>(value);
65 }
66 
CreateIntTypeFromType(Type * type)67 IntType *ETSChecker::CreateIntTypeFromType(Type *type)
68 {
69     if (!type->HasTypeFlag(TypeFlag::CONSTANT)) {
70         return GlobalIntType()->AsIntType();
71     }
72 
73     if (type->IsIntType()) {
74         return type->AsIntType();
75     }
76 
77     switch (ETSType(type)) {
78         case TypeFlag::CHAR: {
79             return CreateIntType(static_cast<int32_t>(type->AsCharType()->GetValue()));
80         }
81         case TypeFlag::BYTE: {
82             return CreateIntType(static_cast<int32_t>(type->AsByteType()->GetValue()));
83         }
84         case TypeFlag::SHORT: {
85             return CreateIntType(static_cast<int32_t>(type->AsShortType()->GetValue()));
86         }
87         default: {
88             return nullptr;
89         }
90     }
91 }
92 
CreateLongType(int64_t value)93 LongType *ETSChecker::CreateLongType(int64_t value)
94 {
95     return Allocator()->New<LongType>(value);
96 }
97 
CreateShortType(int16_t value)98 ShortType *ETSChecker::CreateShortType(int16_t value)
99 {
100     return Allocator()->New<ShortType>(value);
101 }
102 
CreateCharType(char16_t value)103 CharType *ETSChecker::CreateCharType(char16_t value)
104 {
105     return Allocator()->New<CharType>(value);
106 }
107 
CreateETSBigIntLiteralType(util::StringView value)108 ETSBigIntType *ETSChecker::CreateETSBigIntLiteralType(util::StringView value)
109 {
110     return Allocator()->New<ETSBigIntType>(Allocator(), GlobalBuiltinETSBigIntType(), Relation(), value);
111 }
112 
CreateETSStringLiteralType(util::StringView value)113 ETSStringType *ETSChecker::CreateETSStringLiteralType(util::StringView value)
114 {
115     return Allocator()->New<ETSStringType>(Allocator(), GlobalBuiltinETSStringType(), Relation(), value);
116 }
117 
CreateETSArrayType(Type * elementType)118 ETSArrayType *ETSChecker::CreateETSArrayType(Type *elementType)
119 {
120     auto res = arrayTypes_.find(elementType);
121     if (res != arrayTypes_.end()) {
122         return res->second;
123     }
124 
125     auto *arrayType = Allocator()->New<ETSArrayType>(elementType);
126 
127     std::stringstream ss;
128     arrayType->ToAssemblerTypeWithRank(ss);
129     arrayType->SetAssemblerName(util::UString(ss.str(), Allocator()).View());
130 
131     auto it = arrayTypes_.insert({elementType, arrayType});
132     if (it.second && (!elementType->IsTypeParameter() || !elementType->IsETSTypeParameter())) {
133         CreateBuiltinArraySignature(arrayType, arrayType->Rank());
134     }
135 
136     return arrayType;
137 }
138 
139 namespace {
MakeProxyFunctionType(checker::ETSChecker * const checker,const util::StringView & name,const std::initializer_list<varbinder::LocalVariable * > & params,ir::ScriptFunction * const globalFunction,checker::Type * const returnType)140 [[nodiscard]] checker::ETSFunctionType *MakeProxyFunctionType(
141     checker::ETSChecker *const checker, const util::StringView &name,
142     const std::initializer_list<varbinder::LocalVariable *> &params, ir::ScriptFunction *const globalFunction,
143     checker::Type *const returnType)
144 {
145     auto *const signatureInfo = checker->CreateSignatureInfo();
146     signatureInfo->params.insert(signatureInfo->params.end(), params);
147     signatureInfo->minArgCount = signatureInfo->params.size();
148 
149     auto *const signature = checker->CreateSignature(signatureInfo, returnType, name);
150     signature->SetFunction(globalFunction);
151     signature->AddSignatureFlag(checker::SignatureFlags::PROXY);
152 
153     return checker->CreateETSFunctionType(signature, name);
154 }
155 
MakeGlobalSignature(checker::ETSChecker * const checker,ir::ScriptFunction * const function,checker::Type * const returnType)156 [[nodiscard]] checker::Signature *MakeGlobalSignature(checker::ETSChecker *const checker,
157                                                       ir::ScriptFunction *const function,
158                                                       checker::Type *const returnType)
159 {
160     auto *const signatureInfo = checker->CreateSignatureInfo();
161     signatureInfo->params.reserve(function->Params().size());
162     for (const auto *const param : function->Params()) {
163         signatureInfo->params.push_back(param->AsETSParameterExpression()->Variable()->AsLocalVariable());
164     }
165     signatureInfo->minArgCount = signatureInfo->params.size();
166 
167     auto *const signature = checker->CreateSignature(signatureInfo, returnType, function);
168     signature->AddSignatureFlag(checker::SignatureFlags::PUBLIC | checker::SignatureFlags::STATIC);
169     function->SetSignature(signature);
170 
171     return signature;
172 }
173 
SetTypesForScriptFunction(checker::ETSChecker * const checker,ir::ScriptFunction * function)174 void SetTypesForScriptFunction(checker::ETSChecker *const checker, ir::ScriptFunction *function)
175 {
176     for (auto param : function->Params()) {
177         ASSERT(param->IsETSParameterExpression());
178         auto paramType = param->AsETSParameterExpression()->TypeAnnotation()->Check(checker);
179         param->AsETSParameterExpression()->Ident()->SetTsType(paramType);
180         param->AsETSParameterExpression()->Ident()->Variable()->SetTsType(paramType);
181         param->SetTsType(paramType);
182     }
183 }
184 
185 }  // namespace
186 
MakeMethod(ir::TSEnumDeclaration const * const enumDecl,const std::string_view & name,bool buildPorxyParam,Type * returnType,bool buildProxy)187 ETSEnumType::Method ETSChecker::MakeMethod(ir::TSEnumDeclaration const *const enumDecl, const std::string_view &name,
188                                            bool buildPorxyParam, Type *returnType, bool buildProxy)
189 {
190     auto function = FindFunction(enumDecl, name);
191     if (function == nullptr) {
192         return {};
193     }
194 
195     SetTypesForScriptFunction(this, function);
196 
197     if (buildPorxyParam) {
198         return {MakeGlobalSignature(this, function, returnType),
199                 MakeProxyFunctionType(
200                     this, name, {function->Params()[0]->AsETSParameterExpression()->Variable()->AsLocalVariable()},
201                     function, returnType)};
202     }
203     return {MakeGlobalSignature(this, function, returnType),
204             buildProxy ? MakeProxyFunctionType(this, name, {}, function, returnType) : nullptr};
205 }
206 
FindFunction(ir::TSEnumDeclaration const * const enumDecl,const std::string_view & name)207 [[nodiscard]] ir::ScriptFunction *ETSChecker::FindFunction(ir::TSEnumDeclaration const *const enumDecl,
208                                                            const std::string_view &name)
209 {
210     if (enumDecl->BoxedClass() == nullptr) {
211         return nullptr;
212     }
213 
214     for (auto m : enumDecl->BoxedClass()->Body()) {
215         if (m->IsMethodDefinition()) {
216             if (m->AsMethodDefinition()->Id()->Name() == name) {
217                 return m->AsMethodDefinition()->Function();
218             }
219         }
220     }
221     return nullptr;
222 }
223 
224 template <typename EnumType>
CreateEnumTypeFromEnumDeclaration(ir::TSEnumDeclaration const * const enumDecl)225 EnumType *ETSChecker::CreateEnumTypeFromEnumDeclaration(ir::TSEnumDeclaration const *const enumDecl)
226 {
227     static_assert(std::is_same_v<EnumType, ETSIntEnumType> || std::is_same_v<EnumType, ETSStringEnumType>);
228     SavedCheckerContext savedContext(this, Context().Status(), Context().ContainingClass(),
229                                      Context().ContainingSignature());
230 
231     varbinder::Variable *enumVar = enumDecl->Key()->Variable();
232     ASSERT(enumVar != nullptr);
233 
234     checker::ETSEnumType::UType ordinal = -1;
235     auto *const enumType = Allocator()->New<EnumType>(enumDecl, ordinal++);
236     auto *const boxedEnumType = enumDecl->BoxedClass()->TsType();
237 
238     enumType->SetVariable(enumVar);
239     enumVar->SetTsType(enumType);
240 
241     auto const getNameMethod =
242         MakeMethod(enumDecl, ETSEnumType::GET_NAME_METHOD_NAME, false, GlobalETSStringLiteralType());
243     enumType->SetGetNameMethod(getNameMethod);
244 
245     auto getValueOfMethod = MakeMethod(enumDecl, ETSEnumType::GET_VALUE_OF_METHOD_NAME, true, enumType);
246     enumType->SetGetValueOfMethod(getValueOfMethod);
247 
248     auto const fromIntMethod = MakeMethod(enumDecl, ETSEnumType::FROM_INT_METHOD_NAME, false, enumType, false);
249     enumType->SetFromIntMethod(fromIntMethod);
250 
251     auto const boxedFromIntMethod =
252         MakeMethod(enumDecl, ETSEnumType::BOXED_FROM_INT_METHOD_NAME, false, boxedEnumType, false);
253     enumType->SetBoxedFromIntMethod(boxedFromIntMethod);
254 
255     auto const unboxMethod = MakeMethod(enumDecl, ETSEnumType::UNBOX_METHOD_NAME, false, enumType);
256     enumType->SetUnboxMethod(unboxMethod);
257 
258     auto const toStringMethod =
259         MakeMethod(enumDecl, ETSEnumType::TO_STRING_METHOD_NAME, false, GlobalETSStringLiteralType());
260     enumType->SetToStringMethod(toStringMethod);
261 
262     ETSEnumType::Method valueOfMethod = toStringMethod;
263     if (std::is_same_v<EnumType, ETSIntEnumType>) {
264         valueOfMethod = MakeMethod(enumDecl, ETSEnumType::VALUE_OF_METHOD_NAME, false, GlobalIntType());
265     }
266     enumType->SetValueOfMethod(valueOfMethod);
267 
268     auto const valuesMethod =
269         MakeMethod(enumDecl, ETSEnumType::VALUES_METHOD_NAME, false, CreateETSArrayType(enumType));
270     enumType->SetValuesMethod(valuesMethod);
271 
272     for (auto *const member : enumType->GetMembers()) {
273         auto *const memberVar = member->AsTSEnumMember()->Key()->AsIdentifier()->Variable();
274         auto *const enumLiteralType = Allocator()->New<EnumType>(enumDecl, ordinal++, member->AsTSEnumMember());
275         enumLiteralType->SetVariable(memberVar);
276         memberVar->SetTsType(enumLiteralType);
277 
278         enumLiteralType->SetGetNameMethod(getNameMethod);
279         enumLiteralType->SetGetValueOfMethod(getValueOfMethod);
280         enumLiteralType->SetFromIntMethod(fromIntMethod);
281         enumLiteralType->SetBoxedFromIntMethod(boxedFromIntMethod);
282         enumLiteralType->SetUnboxMethod(unboxMethod);
283         enumLiteralType->SetValueOfMethod(valueOfMethod);
284         enumLiteralType->SetToStringMethod(toStringMethod);
285         enumLiteralType->SetValuesMethod(valuesMethod);
286     }
287     return enumType;
288 }
289 
CreateEnumIntTypeFromEnumDeclaration(ir::TSEnumDeclaration * const enumDecl)290 ETSIntEnumType *ETSChecker::CreateEnumIntTypeFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl)
291 {
292     auto etsEnumType = CreateEnumTypeFromEnumDeclaration<ETSIntEnumType>(enumDecl);
293     enumDecl->SetTsType(etsEnumType);
294     return etsEnumType;
295 }
296 
CreateEnumStringTypeFromEnumDeclaration(ir::TSEnumDeclaration * const enumDecl)297 ETSStringEnumType *ETSChecker::CreateEnumStringTypeFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl)
298 {
299     auto etsEnumType = CreateEnumTypeFromEnumDeclaration<ETSStringEnumType>(enumDecl);
300     enumDecl->SetTsType(etsEnumType);
301     return etsEnumType;
302 }
303 
CreateETSUnionType(Span<Type * const> constituentTypes)304 Type *ETSChecker::CreateETSUnionType(Span<Type *const> constituentTypes)
305 {
306     if (constituentTypes.empty()) {
307         return nullptr;
308     }
309 
310     ArenaVector<Type *> newConstituentTypes(Allocator()->Adapter());
311     newConstituentTypes.assign(constituentTypes.begin(), constituentTypes.end());
312 
313     ETSUnionType::NormalizeTypes(Relation(), newConstituentTypes);
314     if (newConstituentTypes.size() == 1) {
315         return newConstituentTypes[0];
316     }
317     return Allocator()->New<ETSUnionType>(this, std::move(newConstituentTypes));
318 }
319 
CreateETSTypeAliasType(util::StringView name,const ir::AstNode * declNode,bool isRecursive)320 ETSTypeAliasType *ETSChecker::CreateETSTypeAliasType(util::StringView name, const ir::AstNode *declNode,
321                                                      bool isRecursive)
322 {
323     return Allocator()->New<ETSTypeAliasType>(this, name, declNode, isRecursive);
324 }
325 
CreateETSFunctionType(ArenaVector<Signature * > & signatures)326 ETSFunctionType *ETSChecker::CreateETSFunctionType(ArenaVector<Signature *> &signatures)
327 {
328     auto *funcType = Allocator()->New<ETSFunctionType>(signatures[0]->Function()->Id()->Name(), Allocator());
329 
330     for (auto *it : signatures) {
331         funcType->AddCallSignature(it);
332     }
333 
334     return funcType;
335 }
336 
CreateETSFunctionType(Signature * signature)337 ETSFunctionType *ETSChecker::CreateETSFunctionType(Signature *signature)
338 {
339     return Allocator()->New<ETSFunctionType>(signature->Function()->Id()->Name(), signature, Allocator());
340 }
341 
CreateETSFunctionType(Signature * signature,util::StringView name)342 ETSFunctionType *ETSChecker::CreateETSFunctionType(Signature *signature, util::StringView name)
343 {
344     return Allocator()->New<ETSFunctionType>(name, signature, Allocator());
345 }
346 
CreateETSFunctionType(ir::ScriptFunction * func,Signature * signature,util::StringView name)347 ETSFunctionType *ETSChecker::CreateETSFunctionType(ir::ScriptFunction *func, Signature *signature,
348                                                    util::StringView name)
349 {
350     if (func->IsDynamic()) {
351         return Allocator()->New<ETSDynamicFunctionType>(name, signature, Allocator(), func->Language());
352     }
353 
354     return Allocator()->New<ETSFunctionType>(name, signature, Allocator());
355 }
356 
CreateETSFunctionType(ir::ScriptFunction * func,ArenaVector<Signature * > && signatures,util::StringView name)357 ETSFunctionType *ETSChecker::CreateETSFunctionType(ir::ScriptFunction *func, ArenaVector<Signature *> &&signatures,
358                                                    util::StringView name)
359 {
360     if (func->IsDynamic()) {
361         return Allocator()->New<ETSDynamicFunctionType>(this, name, std::move(signatures), func->Language());
362     }
363 
364     return Allocator()->New<ETSFunctionType>(this, name, std::move(signatures));
365 }
366 
CreateSignature(SignatureInfo * info,Type * returnType,ir::ScriptFunction * func)367 Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func)
368 {
369     return Allocator()->New<Signature>(info, returnType, func);
370 }
371 
CreateSignature(SignatureInfo * info,Type * returnType,util::StringView internalName)372 Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, util::StringView internalName)
373 {
374     return Allocator()->New<Signature>(info, returnType, internalName);
375 }
376 
CreateSignatureInfo()377 SignatureInfo *ETSChecker::CreateSignatureInfo()
378 {
379     return Allocator()->New<SignatureInfo>(Allocator());
380 }
381 
CreateTypeParameter()382 ETSTypeParameter *ETSChecker::CreateTypeParameter()
383 {
384     return Allocator()->New<ETSTypeParameter>();
385 }
386 
CreateETSFunctionType(util::StringView name)387 ETSFunctionType *ETSChecker::CreateETSFunctionType(util::StringView name)
388 {
389     return Allocator()->New<ETSFunctionType>(name, Allocator());
390 }
391 
CreateETSExtensionFuncHelperType(ETSFunctionType * classMethodType,ETSFunctionType * extensionFunctionType)392 ETSExtensionFuncHelperType *ETSChecker::CreateETSExtensionFuncHelperType(ETSFunctionType *classMethodType,
393                                                                          ETSFunctionType *extensionFunctionType)
394 {
395     return Allocator()->New<ETSExtensionFuncHelperType>(classMethodType, extensionFunctionType);
396 }
397 
GetNameToTypeIdMap()398 std::map<util::StringView, GlobalTypeId> &GetNameToTypeIdMap()
399 {
400     static std::map<util::StringView, GlobalTypeId> nameToTypeId = {
401         {compiler::Signatures::BUILTIN_BIGINT_CLASS, GlobalTypeId::ETS_BIG_INT_BUILTIN},
402         {compiler::Signatures::BUILTIN_STRING_CLASS, GlobalTypeId::ETS_STRING_BUILTIN},
403         {compiler::Signatures::BUILTIN_OBJECT_CLASS, GlobalTypeId::ETS_OBJECT_BUILTIN},
404         {compiler::Signatures::BUILTIN_EXCEPTION_CLASS, GlobalTypeId::ETS_EXCEPTION_BUILTIN},
405         {compiler::Signatures::BUILTIN_ERROR_CLASS, GlobalTypeId::ETS_ERROR_BUILTIN},
406         {compiler::Signatures::BUILTIN_TYPE_CLASS, GlobalTypeId::ETS_TYPE_BUILTIN},
407         {compiler::Signatures::BUILTIN_PROMISE_CLASS, GlobalTypeId::ETS_PROMISE_BUILTIN},
408         {compiler::Signatures::BUILTIN_BOX_CLASS, GlobalTypeId::ETS_BOX_BUILTIN},
409         {compiler::Signatures::BUILTIN_BOOLEAN_BOX_CLASS, GlobalTypeId::ETS_BOOLEAN_BOX_BUILTIN},
410         {compiler::Signatures::BUILTIN_BYTE_BOX_CLASS, GlobalTypeId::ETS_BYTE_BOX_BUILTIN},
411         {compiler::Signatures::BUILTIN_CHAR_BOX_CLASS, GlobalTypeId::ETS_CHAR_BOX_BUILTIN},
412         {compiler::Signatures::BUILTIN_SHORT_BOX_CLASS, GlobalTypeId::ETS_SHORT_BOX_BUILTIN},
413         {compiler::Signatures::BUILTIN_INT_BOX_CLASS, GlobalTypeId::ETS_INT_BOX_BUILTIN},
414         {compiler::Signatures::BUILTIN_LONG_BOX_CLASS, GlobalTypeId::ETS_LONG_BOX_BUILTIN},
415         {compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS, GlobalTypeId::ETS_FLOAT_BOX_BUILTIN},
416         {compiler::Signatures::BUILTIN_DOUBLE_BOX_CLASS, GlobalTypeId::ETS_DOUBLE_BOX_BUILTIN},
417     };
418 
419     return nameToTypeId;
420 }
421 
GetNameToGlobalTypeMap()422 std::map<util::StringView, std::function<ETSObjectType *(const ETSChecker *)>> &GetNameToGlobalTypeMap()
423 {
424     static std::map<util::StringView, std::function<ETSObjectType *(const ETSChecker *)>> nameToGlobalType = {
425         {compiler::Signatures::BUILTIN_BIGINT_CLASS, &ETSChecker::GlobalBuiltinETSBigIntType},
426         {compiler::Signatures::BUILTIN_STRING_CLASS, &ETSChecker::GlobalBuiltinETSStringType},
427         {compiler::Signatures::BUILTIN_OBJECT_CLASS, &ETSChecker::GlobalETSObjectType},
428         {compiler::Signatures::BUILTIN_EXCEPTION_CLASS, &ETSChecker::GlobalBuiltinExceptionType},
429         {compiler::Signatures::BUILTIN_ERROR_CLASS, &ETSChecker::GlobalBuiltinErrorType},
430         {compiler::Signatures::BUILTIN_TYPE_CLASS, &ETSChecker::GlobalBuiltinTypeType},
431         {compiler::Signatures::BUILTIN_PROMISE_CLASS, &ETSChecker::GlobalBuiltinPromiseType},
432     };
433 
434     return nameToGlobalType;
435 }
436 
GetNameToGlobalBoxTypeMap()437 std::map<util::StringView, std::function<Type *(const ETSChecker *)>> &GetNameToGlobalBoxTypeMap()
438 {
439     static std::map<util::StringView, std::function<Type *(const ETSChecker *)>> nameToGlobalBoxType = {
440         {compiler::Signatures::BUILTIN_BOX_CLASS, &ETSChecker::GlobalETSObjectType},
441         {compiler::Signatures::BUILTIN_BOOLEAN_BOX_CLASS, &ETSChecker::GlobalETSBooleanType},
442         {compiler::Signatures::BUILTIN_BYTE_BOX_CLASS, &ETSChecker::GlobalByteType},
443         {compiler::Signatures::BUILTIN_CHAR_BOX_CLASS, &ETSChecker::GlobalCharType},
444         {compiler::Signatures::BUILTIN_SHORT_BOX_CLASS, &ETSChecker::GlobalShortType},
445         {compiler::Signatures::BUILTIN_INT_BOX_CLASS, &ETSChecker::GlobalIntType},
446         {compiler::Signatures::BUILTIN_LONG_BOX_CLASS, &ETSChecker::GlobalLongType},
447         {compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS, &ETSChecker::GlobalFloatType},
448         {compiler::Signatures::BUILTIN_DOUBLE_BOX_CLASS, &ETSChecker::GlobalDoubleType},
449     };
450 
451     return nameToGlobalBoxType;
452 }
453 
UpdateBoxedGlobalType(ETSObjectType * objType,util::StringView name)454 ETSObjectType *ETSChecker::UpdateBoxedGlobalType(ETSObjectType *objType, util::StringView name)
455 {
456     auto nameToGlobalBoxType = GetNameToGlobalBoxTypeMap();
457     auto nameToTypeId = GetNameToTypeIdMap();
458 
459     if (nameToGlobalBoxType.find(name) != nameToGlobalBoxType.end()) {
460         std::function<Type *(const ETSChecker *)> globalType = nameToGlobalBoxType[name];
461         if (GlobalBuiltinBoxType(globalType(this)) != nullptr) {
462             return GlobalBuiltinBoxType(globalType(this));
463         }
464 
465         auto id = nameToTypeId.find(name);
466         if (id != nameToTypeId.end()) {
467             GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(id->second)] = objType;
468         }
469     }
470 
471     return objType;
472 }
473 
UpdateGlobalType(ETSObjectType * objType,util::StringView name)474 ETSObjectType *ETSChecker::UpdateGlobalType(ETSObjectType *objType, util::StringView name)
475 {
476     auto nameToGlobalType = GetNameToGlobalTypeMap();
477     auto nameToTypeId = GetNameToTypeIdMap();
478 
479     if (nameToGlobalType.find(name) != nameToGlobalType.end()) {
480         std::function<ETSObjectType *(const ETSChecker *)> globalType = nameToGlobalType[name];
481         if (globalType(this) != nullptr) {
482             return globalType(this);
483         }
484 
485         auto id = nameToTypeId.find(name);
486         if (id != nameToTypeId.end()) {
487             GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(id->second)] = objType;
488         }
489 
490         if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) {
491             auto *nullish = CreateETSUnionType({objType, GlobalETSNullType(), GlobalETSUndefinedType()});
492             GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(GlobalTypeId::ETS_NULLISH_OBJECT)] = nullish;
493             nullish = CreateETSUnionType({GlobalETSNullType(), GlobalETSUndefinedType()});
494             GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(GlobalTypeId::ETS_NULLISH_TYPE)] = nullish;
495         }
496     }
497 
498     return objType;
499 }
500 
CreateETSObjectTypeCheckBuiltins(util::StringView name,ir::AstNode * declNode,ETSObjectFlags flags)501 ETSObjectType *ETSChecker::CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode,
502                                                             ETSObjectFlags flags)
503 {
504     if (name == compiler::Signatures::BUILTIN_BIGINT_CLASS) {
505         if (GlobalBuiltinETSBigIntType() != nullptr) {
506             return GlobalBuiltinETSBigIntType();
507         }
508 
509         GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(GlobalTypeId::ETS_BIG_INT_BUILTIN)] =
510             CreateNewETSObjectType(name, declNode, flags | ETSObjectFlags::BUILTIN_BIGINT);
511         GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(GlobalTypeId::ETS_BIG_INT)] =
512             Allocator()->New<ETSBigIntType>(Allocator(), GlobalBuiltinETSBigIntType());
513 
514         return GlobalBuiltinETSBigIntType();
515     }
516 
517     if (name == compiler::Signatures::BUILTIN_STRING_CLASS) {
518         if (GlobalBuiltinETSStringType() != nullptr) {
519             return GlobalBuiltinETSStringType();
520         }
521         GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(GlobalTypeId::ETS_STRING_BUILTIN)] =
522             CreateNewETSObjectType(name, declNode, flags | ETSObjectFlags::BUILTIN_STRING | ETSObjectFlags::STRING);
523 
524         GetGlobalTypesHolder()->GlobalTypes()[static_cast<size_t>(GlobalTypeId::ETS_STRING)] =
525             Allocator()->New<ETSStringType>(Allocator(), GlobalBuiltinETSStringType(), Relation());
526         return GlobalBuiltinETSStringType();
527     }
528 
529     auto *objType = CreateNewETSObjectType(name, declNode, flags);
530     auto nameToGlobalBoxType = GetNameToGlobalBoxTypeMap();
531 
532     return UpdateGlobalType(objType, name);
533 }
534 
CreateETSObjectType(util::StringView name,ir::AstNode * declNode,ETSObjectFlags flags)535 ETSObjectType *ETSChecker::CreateETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags)
536 {
537     auto res = primitiveWrappers_.Wrappers().find(name);
538     if (res == primitiveWrappers_.Wrappers().end()) {
539         return CreateETSObjectTypeCheckBuiltins(name, declNode, flags);
540     }
541 
542     if (res->second.first != nullptr) {
543         return res->second.first;
544     }
545 
546     auto *objType = CreateNewETSObjectType(name, declNode, flags | res->second.second);
547     primitiveWrappers_.Wrappers().at(name).first = objType;
548     return objType;
549 }
550 
CheckForDynamicLang(ir::AstNode * declNode,util::StringView assemblerName)551 std::tuple<Language, bool> ETSChecker::CheckForDynamicLang(ir::AstNode *declNode, util::StringView assemblerName)
552 {
553     Language lang(Language::Id::ETS);
554     bool hasDecl = false;
555 
556     if (declNode->IsClassDefinition()) {
557         auto *clsDef = declNode->AsClassDefinition();
558         lang = clsDef->Language();
559         hasDecl = clsDef->IsDeclare();
560     }
561 
562     if (declNode->IsTSInterfaceDeclaration()) {
563         auto *ifaceDecl = declNode->AsTSInterfaceDeclaration();
564         lang = ifaceDecl->Language();
565         hasDecl = ifaceDecl->IsDeclare();
566     }
567 
568     auto res = compiler::Signatures::Dynamic::LanguageFromType(assemblerName.Utf8());
569     if (res) {
570         lang = *res;
571     }
572 
573     return std::make_tuple(lang, hasDecl);
574 }
575 
CreateNewETSObjectType(util::StringView name,ir::AstNode * declNode,ETSObjectFlags flags)576 ETSObjectType *ETSChecker::CreateNewETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags)
577 {
578     util::StringView assemblerName = name;
579     util::StringView prefix {};
580 
581     auto *containingObjType = util::Helpers::GetContainingObjectType(declNode->Parent());
582 
583     if (declNode->IsClassDefinition()) {
584         if (declNode->AsClassDefinition()->IsLocal()) {
585             util::UString localName(declNode->AsClassDefinition()->LocalPrefix(), Allocator());
586             localName.Append(name);
587             assemblerName = localName.View();
588         }
589         if (declNode->AsClassDefinition()->OrigEnumDecl() != nullptr) {
590             flags |= ETSObjectFlags::BOXED_ENUM;
591         }
592     }
593 
594     if (containingObjType != nullptr) {
595         prefix = containingObjType->AssemblerName();
596     } else if (const auto *topStatement = declNode->GetTopStatement();
597                topStatement->Type() !=
598                ir::AstNodeType::ETS_SCRIPT) {  // NOTE: should not occur, fix for TS_INTERFACE_DECLARATION
599         ASSERT(declNode->IsTSInterfaceDeclaration());
600         assemblerName = declNode->AsTSInterfaceDeclaration()->InternalName();
601     } else {
602         auto program = static_cast<ir::ETSScript *>(declNode->GetTopStatement())->Program();
603         prefix = program->OmitModuleName() ? util::StringView() : program->ModuleName();
604     }
605 
606     if (!prefix.Empty()) {
607         assemblerName =
608             util::UString(prefix.Mutf8() + compiler::Signatures::METHOD_SEPARATOR.data() + assemblerName.Mutf8(),
609                           Allocator())
610                 .View();
611     }
612 
613     auto [lang, hasDecl] = CheckForDynamicLang(declNode, assemblerName);
614     if (lang.IsDynamic()) {
615         return Allocator()->New<ETSDynamicType>(Allocator(), std::make_tuple(name, assemblerName, lang),
616                                                 std::make_tuple(declNode, flags, Relation()), hasDecl);
617     }
618 
619     return Allocator()->New<ETSObjectType>(Allocator(), name, assemblerName,
620                                            std::make_tuple(declNode, flags, Relation()));
621 }
622 
CreateBuiltinArraySignatureInfo(ETSArrayType * arrayType,size_t dim)623 std::tuple<util::StringView, SignatureInfo *> ETSChecker::CreateBuiltinArraySignatureInfo(ETSArrayType *arrayType,
624                                                                                           size_t dim)
625 {
626     std::stringstream ss;
627     arrayType->ToAssemblerTypeWithRank(ss);
628     ss << compiler::Signatures::METHOD_SEPARATOR << compiler::Signatures::CTOR << compiler::Signatures::MANGLE_BEGIN;
629     arrayType->ToAssemblerTypeWithRank(ss);
630 
631     auto *info = CreateSignatureInfo();
632     info->minArgCount = dim;
633 
634     for (size_t i = 0; i < dim; i++) {
635         util::UString param(std::to_string(i), Allocator());
636         auto *paramVar =
637             varbinder::Scope::CreateVar(Allocator(), param.View(), varbinder::VariableFlags::NONE, nullptr);
638         paramVar->SetTsType(GlobalIntType());
639 
640         info->params.push_back(paramVar);
641 
642         ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_INT;
643     }
644 
645     ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_VOID
646        << compiler::Signatures::MANGLE_SEPARATOR;
647     auto internalName = util::UString(ss.str(), Allocator()).View();
648 
649     return {internalName, info};
650 }
651 
CreateBuiltinArraySignature(ETSArrayType * arrayType,size_t dim)652 Signature *ETSChecker::CreateBuiltinArraySignature(ETSArrayType *arrayType, size_t dim)
653 {
654     auto res = globalArraySignatures_.find(arrayType);
655     if (res != globalArraySignatures_.end()) {
656         return res->second;
657     }
658 
659     auto [internalName, info] = CreateBuiltinArraySignatureInfo(arrayType, dim);
660     auto *signature = CreateSignature(info, GlobalVoidType(), internalName);
661     globalArraySignatures_.insert({arrayType, signature});
662 
663     return signature;
664 }
665 
FunctionTypeToFunctionalInterfaceType(Signature * signature)666 ETSObjectType *ETSChecker::FunctionTypeToFunctionalInterfaceType(Signature *signature)
667 {
668     auto *retType = signature->ReturnType();
669     if (signature->RestVar() != nullptr) {
670         auto *functionN =
671             GlobalBuiltinFunctionType(GlobalBuiltinFunctionTypeVariadicThreshold(), signature->Function()->Flags())
672                 ->AsETSObjectType();
673         auto *substitution = NewSubstitution();
674         substitution->emplace(functionN->TypeArguments()[0]->AsETSTypeParameter(), MaybeBoxType(retType));
675         return functionN->Substitute(Relation(), substitution);
676     }
677 
678     // Note: FunctionN is not supported yet
679     if (signature->Params().size() >= GetGlobalTypesHolder()->VariadicFunctionTypeThreshold()) {
680         return nullptr;
681     }
682 
683     auto *funcIface =
684         GlobalBuiltinFunctionType(signature->Params().size(), signature->Function()->Flags())->AsETSObjectType();
685     auto *substitution = NewSubstitution();
686 
687     for (size_t i = 0; i < signature->Params().size(); i++) {
688         substitution->emplace(funcIface->TypeArguments()[i]->AsETSTypeParameter(),
689                               MaybeBoxType(signature->Params()[i]->TsType()));
690     }
691     substitution->emplace(funcIface->TypeArguments()[signature->Params().size()]->AsETSTypeParameter(),
692                           MaybeBoxType(signature->ReturnType()));
693     return funcIface->Substitute(Relation(), substitution);
694 }
695 
ResolveFunctionalInterfaces(ArenaVector<Signature * > & signatures)696 Type *ETSChecker::ResolveFunctionalInterfaces(ArenaVector<Signature *> &signatures)
697 {
698     ArenaVector<Type *> types(Allocator()->Adapter());
699     for (auto *signature : signatures) {
700         types.push_back(FunctionTypeToFunctionalInterfaceType(signature));
701     }
702     return CreateETSUnionType(std::move(types));
703 }
704 
CreatePromiseOf(Type * type)705 ETSObjectType *ETSChecker::CreatePromiseOf(Type *type)
706 {
707     ETSObjectType *const promiseType = GlobalBuiltinPromiseType();
708     ASSERT(promiseType->TypeArguments().size() == 1);
709     Substitution *substitution = NewSubstitution();
710     ETSChecker::EmplaceSubstituted(substitution, promiseType->TypeArguments()[0]->AsETSTypeParameter()->GetOriginal(),
711                                    type);
712 
713     return promiseType->Substitute(Relation(), substitution);
714 }
715 
716 }  // namespace ark::es2panda::checker
717