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