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