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