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