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