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 "ir/expressions/literals/bigIntLiteral.h"
17 #include "ir/expressions/literals/numberLiteral.h"
18 #include "ir/expressions/literals/stringLiteral.h"
19 #include "ir/expressions/functionExpression.h"
20 #include "ir/expressions/memberExpression.h"
21 #include "ir/expressions/identifier.h"
22 #include "ir/base/property.h"
23 #include "ir/base/scriptFunction.h"
24 #include "ir/base/spreadElement.h"
25 #include "ir/base/tsIndexSignature.h"
26 #include "ir/base/tsMethodSignature.h"
27 #include "ir/base/tsPropertySignature.h"
28 #include "ir/base/tsSignatureDeclaration.h"
29 #include "ir/ts/tsTypeLiteral.h"
30 #include "ir/ts/tsInterfaceDeclaration.h"
31 #include "ir/ts/tsInterfaceHeritage.h"
32 #include "ir/ts/tsInterfaceBody.h"
33 #include "util/helpers.h"
34 #include "varbinder/variable.h"
35 #include "varbinder/scope.h"
36 
37 #include "checker/TSchecker.h"
38 #include "checker/types/ts/indexInfo.h"
39 
40 namespace ark::es2panda::checker {
CheckIndexConstraints(Type *type)41 void TSChecker::CheckIndexConstraints(Type *type)
42 {
43     if (!type->IsObjectType()) {
44         return;
45     }
46 
47     ObjectType *objType = type->AsObjectType();
48     ResolveStructuredTypeMembers(objType);
49 
50     IndexInfo *numberInfo = objType->NumberIndexInfo();
51     IndexInfo *stringInfo = objType->StringIndexInfo();
52     const ArenaVector<varbinder::LocalVariable *> &properties = objType->Properties();
53 
54     if (numberInfo != nullptr) {
55         for (auto *it : properties) {
56             if (it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME)) {
57                 Type *propType = GetTypeOfVariable(it);
58                 IsTypeAssignableTo(propType, numberInfo->GetType(),
59                                    {"Property '", it->Name(), "' of type '", propType,
60                                     "' is not assignable to numeric index type '", numberInfo->GetType(), "'."},
61                                    it->Declaration()->Node()->Start());
62             }
63         }
64     }
65 
66     if (stringInfo != nullptr) {
67         for (auto *it : properties) {
68             Type *propType = GetTypeOfVariable(it);
69             IsTypeAssignableTo(propType, stringInfo->GetType(),
70                                {"Property '", it->Name(), "' of type '", propType,
71                                 "' is not assignable to string index type '", stringInfo->GetType(), "'."},
72                                it->Declaration()->Node()->Start());
73         }
74 
75         if (numberInfo != nullptr && !IsTypeAssignableTo(numberInfo->GetType(), stringInfo->GetType())) {
76             ThrowTypeError({"Number index info type ", numberInfo->GetType(),
77                             " is not assignable to string index info type ", stringInfo->GetType(), "."},
78                            numberInfo->Pos());
79         }
80     }
81 }
82 
ResolveStructuredTypeMembers(Type *type)83 void TSChecker::ResolveStructuredTypeMembers(Type *type)
84 {
85     if (type->IsObjectType()) {
86         ObjectType *objType = type->AsObjectType();
87 
88         if (objType->IsObjectLiteralType()) {
89             ResolveObjectTypeMembers(objType);
90             return;
91         }
92 
93         if (objType->IsInterfaceType()) {
94             ResolveInterfaceOrClassTypeMembers(objType->AsInterfaceType());
95             return;
96         }
97     }
98 
99     if (type->IsUnionType()) {
100         ResolveUnionTypeMembers(type->AsUnionType());
101         return;
102     }
103 }
104 
ResolveUnionTypeMembers(UnionType *type)105 void TSChecker::ResolveUnionTypeMembers(UnionType *type)
106 {
107     if (type->MergedObjectType() != nullptr) {
108         return;
109     }
110 
111     ObjectDescriptor *desc = Allocator()->New<ObjectDescriptor>(Allocator());
112     ArenaVector<Type *> stringInfoTypes(Allocator()->Adapter());
113     ArenaVector<Type *> numberInfoTypes(Allocator()->Adapter());
114     ArenaVector<Signature *> callSignatures(Allocator()->Adapter());
115     ArenaVector<Signature *> constructSignatures(Allocator()->Adapter());
116 
117     for (auto *it : type->AsUnionType()->ConstituentTypes()) {
118         if (!it->IsObjectType()) {
119             continue;
120         }
121 
122         ObjectType *objType = it->AsObjectType();
123         ResolveObjectTypeMembers(objType);
124 
125         if (!objType->CallSignatures().empty()) {
126             for (auto *signature : objType->CallSignatures()) {
127                 callSignatures.push_back(signature);
128             }
129         }
130 
131         if (!objType->ConstructSignatures().empty()) {
132             for (auto *signature : objType->ConstructSignatures()) {
133                 constructSignatures.push_back(signature);
134             }
135         }
136 
137         if (objType->StringIndexInfo() != nullptr) {
138             stringInfoTypes.push_back(objType->StringIndexInfo()->GetType());
139         }
140 
141         if (objType->NumberIndexInfo() != nullptr) {
142             numberInfoTypes.push_back(objType->NumberIndexInfo()->GetType());
143         }
144     }
145 
146     desc->callSignatures = callSignatures;
147     desc->constructSignatures = constructSignatures;
148 
149     if (!stringInfoTypes.empty()) {
150         desc->stringIndexInfo = Allocator()->New<IndexInfo>(CreateUnionType(std::move(stringInfoTypes)), "x", false);
151     }
152 
153     if (!numberInfoTypes.empty()) {
154         desc->numberIndexInfo = Allocator()->New<IndexInfo>(CreateUnionType(std::move(numberInfoTypes)), "x", false);
155     }
156 
157     ObjectType *mergedType = Allocator()->New<ObjectLiteralType>(desc);
158     mergedType->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS);
159     type->SetMergedObjectType(mergedType);
160 }
161 
ResolveInterfaceOrClassTypeMembers(InterfaceType *type)162 void TSChecker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type)
163 {
164     if (type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) {
165         return;
166     }
167 
168     ResolveDeclaredMembers(type);
169     GetBaseTypes(type);
170 
171     type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS);
172 }
173 
ResolveObjectTypeMembers(ObjectType *type)174 void TSChecker::ResolveObjectTypeMembers(ObjectType *type)
175 {
176     if (!type->IsObjectLiteralType() || type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) {
177         return;
178     }
179 
180     ASSERT(type->Variable() && type->Variable()->Declaration()->Node()->IsTSTypeLiteral());
181     auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral();
182     ArenaVector<ir::TSSignatureDeclaration *> signatureDeclarations(Allocator()->Adapter());
183     ArenaVector<ir::TSIndexSignature *> indexDeclarations(Allocator()->Adapter());
184 
185     for (auto *it : typeLiteral->Members()) {
186         ResolvePropertiesOfObjectType(type, it, signatureDeclarations, indexDeclarations, false);
187     }
188 
189     type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS);
190 
191     ResolveSignaturesOfObjectType(type, signatureDeclarations);
192     ResolveIndexInfosOfObjectType(type, indexDeclarations);
193 }
194 
ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, ArenaVector<ir::TSSignatureDeclaration *> &signatureDeclarations, ArenaVector<ir::TSIndexSignature *> &indexDeclarations, bool isInterface)195 void TSChecker::ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member,
196                                               ArenaVector<ir::TSSignatureDeclaration *> &signatureDeclarations,
197                                               ArenaVector<ir::TSIndexSignature *> &indexDeclarations, bool isInterface)
198 {
199     if (member->IsTSPropertySignature()) {
200         varbinder::Variable *prop = member->AsTSPropertySignature()->Variable();
201 
202         if (!isInterface ||
203             ValidateInterfaceMemberRedeclaration(type, prop, member->AsTSPropertySignature()->Key()->Start())) {
204             type->AddProperty(prop->AsLocalVariable());
205         }
206 
207         return;
208     }
209 
210     if (member->IsTSMethodSignature()) {
211         varbinder::Variable *method = member->AsTSMethodSignature()->Variable();
212 
213         if (!isInterface ||
214             ValidateInterfaceMemberRedeclaration(type, method, member->AsTSMethodSignature()->Key()->Start())) {
215             type->AddProperty(method->AsLocalVariable());
216         }
217 
218         return;
219     }
220 
221     if (member->IsTSSignatureDeclaration()) {
222         signatureDeclarations.push_back(member->AsTSSignatureDeclaration());
223         return;
224     }
225 
226     ASSERT(member->IsTSIndexSignature());
227     indexDeclarations.push_back(member->AsTSIndexSignature());
228 }
229 
ResolveSignaturesOfObjectType(ObjectType *type, ArenaVector<ir::TSSignatureDeclaration *> &signatureDeclarations)230 void TSChecker::ResolveSignaturesOfObjectType(ObjectType *type,
231                                               ArenaVector<ir::TSSignatureDeclaration *> &signatureDeclarations)
232 {
233     for (auto *it : signatureDeclarations) {
234         Type *placeholderObj = it->Check(this);
235 
236         if (it->AsTSSignatureDeclaration()->Kind() ==
237             ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CALL_SIGNATURE) {
238             type->AddCallSignature(placeholderObj->AsObjectType()->CallSignatures()[0]);
239             continue;
240         }
241 
242         type->AddConstructSignature(placeholderObj->AsObjectType()->ConstructSignatures()[0]);
243     }
244 }
ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector<ir::TSIndexSignature *> &indexDeclarations)245 void TSChecker::ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector<ir::TSIndexSignature *> &indexDeclarations)
246 {
247     for (auto *it : indexDeclarations) {
248         Type *placeholderObj = it->Check(this);
249 
250         if (it->AsTSIndexSignature()->Kind() == ir::TSIndexSignature::TSIndexSignatureKind::NUMBER) {
251             IndexInfo *numberInfo = placeholderObj->AsObjectType()->NumberIndexInfo();
252 
253             if (type->NumberIndexInfo() != nullptr) {
254                 ThrowTypeError("Duplicated index signature for type 'number'", it->Start());
255             }
256 
257             type->Desc()->numberIndexInfo = numberInfo;
258             continue;
259         }
260 
261         IndexInfo *stringInfo = placeholderObj->AsObjectType()->StringIndexInfo();
262 
263         if (type->StringIndexInfo() != nullptr) {
264             ThrowTypeError("Duplicated index signature for type 'string'", it->Start());
265         }
266 
267         type->Desc()->stringIndexInfo = stringInfo;
268     }
269 }
270 
GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, varbinder::VariableFlags propagateFlags)271 varbinder::Variable *TSChecker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial,
272                                                   varbinder::VariableFlags propagateFlags)
273 {
274     if (type->IsObjectType()) {
275         ResolveObjectTypeMembers(type->AsObjectType());
276         return type->AsObjectType()->GetProperty(name, true);
277     }
278 
279     if (type->IsUnionType()) {
280         return GetPropertyOfUnionType(type->AsUnionType(), name, getPartial, propagateFlags);
281     }
282 
283     return nullptr;
284 }
285 
GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, varbinder::VariableFlags propagateFlags)286 varbinder::Variable *TSChecker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial,
287                                                        varbinder::VariableFlags propagateFlags)
288 {
289     auto found = type->CachedSyntheticProperties().find(name);
290     if (found != type->CachedSyntheticProperties().end()) {
291         return found->second;
292     }
293 
294     varbinder::VariableFlags flags = varbinder::VariableFlags::PROPERTY;
295     ArenaVector<Type *> collectedTypes(Allocator()->Adapter());
296 
297     for (auto *it : type->ConstituentTypes()) {
298         varbinder::Variable *prop = GetPropertyOfType(it, name);
299 
300         if (prop == nullptr) {
301             if (it->IsArrayType()) {
302                 collectedTypes.push_back(it->AsArrayType()->ElementType());
303                 continue;
304             }
305 
306             if (!it->IsObjectType() && getPartial) {
307                 continue;
308             }
309             if (!it->IsObjectType() && !getPartial) {
310                 return nullptr;
311             }
312 
313             ObjectType *objType = it->AsObjectType();
314 
315             if (objType->StringIndexInfo() == nullptr && getPartial) {
316                 continue;
317             }
318             if (objType->StringIndexInfo() == nullptr && !getPartial) {
319                 return nullptr;
320             }
321 
322             collectedTypes.push_back(objType->StringIndexInfo()->GetType());
323             continue;
324         }
325 
326         prop->AddFlag(propagateFlags);
327 
328         if (prop->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
329             flags |= varbinder::VariableFlags::OPTIONAL;
330         }
331 
332         collectedTypes.push_back(GetTypeOfVariable(prop));
333     }
334 
335     if (collectedTypes.empty()) {
336         return nullptr;
337     }
338 
339     varbinder::Variable *syntheticProp = varbinder::Scope::CreateVar(Allocator(), name, flags, nullptr);
340     syntheticProp->SetTsType(CreateUnionType(std::move(collectedTypes)));
341     type->CachedSyntheticProperties().insert({name, syntheticProp});
342     return syntheticProp;
343 }
344 
CheckComputedPropertyName(ir::Expression *key)345 Type *TSChecker::CheckComputedPropertyName(ir::Expression *key)
346 {
347     if (key->TsType() != nullptr) {
348         return key->TsType();
349     }
350 
351     Type *keyType = key->Check(this);
352 
353     if (!keyType->HasTypeFlag(TypeFlag::STRING_LIKE | TypeFlag::NUMBER_LIKE)) {
354         ThrowTypeError(
355             "A computed property name in a type literal must refer to an expression whose type is a literal "
356             "type "
357             "or a 'unique symbol' type",
358             key->Start());
359     }
360 
361     key->SetTsType(keyType);
362     return keyType;
363 }
364 
GetApplicableIndexInfo(Type *type, Type *indexType)365 IndexInfo *TSChecker::GetApplicableIndexInfo(Type *type, Type *indexType)
366 {
367     ResolveStructuredTypeMembers(type);
368     bool getNumberInfo = indexType->HasTypeFlag(TypeFlag::NUMBER_LIKE);
369 
370     if (type->IsObjectType()) {
371         if (getNumberInfo) {
372             return type->AsObjectType()->NumberIndexInfo();
373         }
374 
375         return type->AsObjectType()->StringIndexInfo();
376     }
377 
378     if (type->IsUnionType()) {
379         ASSERT(type->AsUnionType()->MergedObjectType());
380 
381         if (getNumberInfo) {
382             return type->AsUnionType()->MergedObjectType()->NumberIndexInfo();
383         }
384 
385         return type->AsUnionType()->MergedObjectType()->StringIndexInfo();
386     }
387 
388     return nullptr;
389 }
390 
GetPropertyTypeForIndexType(Type *type, Type *indexType)391 Type *TSChecker::GetPropertyTypeForIndexType(Type *type, Type *indexType)
392 {
393     if (type->IsArrayType()) {
394         return type->AsArrayType()->ElementType();
395     }
396 
397     if (indexType->HasTypeFlag(TypeFlag::STRING_LITERAL | TypeFlag::NUMBER_LITERAL)) {
398         varbinder::Variable *prop = nullptr;
399 
400         if (indexType->IsStringLiteralType()) {
401             prop = GetPropertyOfType(type, indexType->AsStringLiteralType()->Value());
402         } else {
403             util::StringView propName =
404                 util::Helpers::ToStringView(Allocator(), indexType->AsNumberLiteralType()->Value());
405             prop = GetPropertyOfType(type, propName);
406         }
407 
408         if (prop != nullptr) {
409             Type *propType = GetTypeOfVariable(prop);
410 
411             if (prop->HasFlag(varbinder::VariableFlags::READONLY)) {
412                 propType->AddTypeFlag(TypeFlag::READONLY);
413             }
414 
415             return propType;
416         }
417     }
418 
419     if (indexType->HasTypeFlag(TypeFlag::STRING_LIKE | TypeFlag::NUMBER_LIKE)) {
420         IndexInfo *indexInfo = GetApplicableIndexInfo(type, indexType);
421 
422         if (indexInfo != nullptr) {
423             Type *indexInfoType = indexInfo->GetType();
424 
425             if (indexInfo->Readonly()) {
426                 indexInfoType->AddTypeFlag(TypeFlag::READONLY);
427             }
428 
429             return indexInfoType;
430         }
431     }
432 
433     return nullptr;
434 }
435 
GetBaseTypes(InterfaceType *type)436 ArenaVector<ObjectType *> TSChecker::GetBaseTypes(InterfaceType *type)
437 {
438     if (type->HasObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES)) {
439         return type->Bases();
440     }
441 
442     ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl());
443     varbinder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl();
444 
445     TypeStackElement tse(this, type, {"Type ", type->Name(), " recursively references itself as a base type."},
446                          decl->Node()->AsTSInterfaceDeclaration()->Id()->Start());
447     if (tse.HasTypeError()) {
448         type->Bases().clear();
449         return type->Bases();
450     }
451 
452     for (const auto *declaration : decl->Decls()) {
453         if (declaration->Extends().empty()) {
454             continue;
455         }
456 
457         for (auto *extends : declaration->Extends()) {
458             Type *baseType = extends->Expr()->GetType(this);
459 
460             if (!baseType->HasTypeFlag(TypeFlag::OBJECT | TypeFlag::NON_PRIMITIVE | TypeFlag::ANY)) {
461                 ThrowTypeError(
462                     "An interface can only extend an object type or intersection of object types with statically "
463                     "known "
464                     "members",
465                     extends->Start());
466             }
467 
468             if (!baseType->IsObjectType()) {
469                 continue;
470             }
471 
472             ObjectType *baseObj = baseType->AsObjectType();
473 
474             if (baseType == type) {
475                 ThrowTypeError({"Type ", type->Name(), " recursively references itself as a base type."},
476                                decl->Node()->AsTSInterfaceDeclaration()->Id()->Start());
477             }
478 
479             type->AddBase(baseObj);
480 
481             if (!baseObj->IsInterfaceType()) {
482                 continue;
483             }
484 
485             CheckExtendsBases(baseObj, type, decl);
486         }
487     }
488 
489     type->AddObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES);
490     return type->Bases();
491 }
492 
CheckExtendsBases(ObjectType *&baseObj, InterfaceType *&type, varbinder::InterfaceDecl *&decl)493 void TSChecker::CheckExtendsBases(ObjectType *&baseObj, InterfaceType *&type, varbinder::InterfaceDecl *&decl)
494 {
495     ArenaVector<ObjectType *> extendsBases = GetBaseTypes(baseObj->AsInterfaceType());
496     for (auto *extendBase : extendsBases) {
497         if (extendBase == type) {
498             ThrowTypeError({"Type ", type->Name(), " recursively references itself as a base type."},
499                            decl->Node()->AsTSInterfaceDeclaration()->Id()->Start());
500         }
501     }
502 }
503 
ResolveDeclaredMembers(InterfaceType *type)504 void TSChecker::ResolveDeclaredMembers(InterfaceType *type)
505 {
506     if (type->HasObjectFlag(ObjectFlags::RESOLVED_DECLARED_MEMBERS)) {
507         return;
508     }
509 
510     ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl());
511     varbinder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl();
512 
513     ArenaVector<ir::TSSignatureDeclaration *> signatureDeclarations(Allocator()->Adapter());
514     ArenaVector<ir::TSIndexSignature *> indexDeclarations(Allocator()->Adapter());
515 
516     for (const auto *declaration : decl->Decls()) {
517         for (auto *member : declaration->Body()->Body()) {
518             ResolvePropertiesOfObjectType(type, member, signatureDeclarations, indexDeclarations, true);
519         }
520 
521         type->AddObjectFlag(ObjectFlags::RESOLVED_DECLARED_MEMBERS);
522 
523         ResolveSignaturesOfObjectType(type, signatureDeclarations);
524         ResolveIndexInfosOfObjectType(type, indexDeclarations);
525     }
526 }
527 
ValidateInterfaceMemberRedeclaration(ObjectType *type, varbinder::Variable *prop, const lexer::SourcePosition &locInfo)528 bool TSChecker::ValidateInterfaceMemberRedeclaration(ObjectType *type, varbinder::Variable *prop,
529                                                      const lexer::SourcePosition &locInfo)
530 {
531     if (prop->HasFlag(varbinder::VariableFlags::COMPUTED)) {
532         return true;
533     }
534 
535     varbinder::Variable *found = type->GetProperty(prop->Name(), false);
536 
537     if (found == nullptr) {
538         return true;
539     }
540 
541     Type *targetType = GetTypeOfVariable(prop);
542     Type *sourceType = GetTypeOfVariable(found);
543     IsTypeIdenticalTo(targetType, sourceType,
544                       {"Subsequent property declarations must have the same type.  Property ", prop->Name(),
545                        " must be of type ", sourceType, ", but here has type ", targetType, "."},
546                       locInfo);
547     return false;
548 }
549 }  // namespace ark::es2panda::checker
550