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