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 "objectType.h"
17
18 #include <typescript/types/indexInfo.h>
19 #include <typescript/types/interfaceType.h>
20 #include <typescript/types/signature.h>
21 #include <typescript/checker.h>
22
23 namespace panda::es2panda::checker {
24
EachSignatureRelatedToSomeSignature(TypeRelation * relation,const ArenaVector<Signature * > & sourceSignatures,const ArenaVector<Signature * > & targetSignatures)25 bool ObjectType::EachSignatureRelatedToSomeSignature(TypeRelation *relation,
26 const ArenaVector<Signature *> &sourceSignatures,
27 const ArenaVector<Signature *> &targetSignatures)
28 {
29 ArenaVector<Signature *> targetCopy = targetSignatures;
30
31 return std::all_of(sourceSignatures.begin(), sourceSignatures.end(), [relation, &targetCopy](Signature *source) {
32 return SignatureRelatedToSomeSignature(relation, source, &targetCopy);
33 });
34 }
35
SignatureRelatedToSomeSignature(TypeRelation * relation,Signature * sourceSignature,ArenaVector<Signature * > * targetSignatures)36 bool ObjectType::SignatureRelatedToSomeSignature(TypeRelation *relation, Signature *sourceSignature,
37 ArenaVector<Signature *> *targetSignatures)
38 {
39 for (auto it = targetSignatures->begin(); it != targetSignatures->end();) {
40 if (relation->IsIdenticalTo(sourceSignature, *it)) {
41 targetSignatures->erase(it);
42 return true;
43 }
44
45 it++;
46 }
47
48 return false;
49 }
50
IsPropertiesIdentical(TypeRelation * relation,ObjectType * otherObj)51 bool ObjectType::IsPropertiesIdentical(TypeRelation *relation, ObjectType *otherObj)
52 {
53 for (auto *it : desc_->properties) {
54 binder::LocalVariable *found = otherObj->Desc()->FindProperty(it->Name());
55 if (!found) {
56 relation->Result(false);
57 return false;
58 }
59
60 relation->IsIdenticalTo(it->TsType(), found->TsType());
61
62 if (!relation->IsTrue()) {
63 return false;
64 }
65
66 if (it->Flags() != found->Flags()) {
67 relation->Result(false);
68 return false;
69 }
70 }
71
72 return true;
73 }
74
IsIndexInfosIdentical(TypeRelation * relation,IndexInfo * descIndexInfo,IndexInfo * otherIndexInfo)75 bool ObjectType::IsIndexInfosIdentical(TypeRelation *relation, IndexInfo *descIndexInfo, IndexInfo *otherIndexInfo)
76 {
77 if (descIndexInfo) {
78 relation->IsIdenticalTo(descIndexInfo, otherIndexInfo);
79 if (!relation->IsTrue()) {
80 return false;
81 }
82 }
83
84 return true;
85 }
86
Identical(TypeRelation * relation,Type * other)87 void ObjectType::Identical(TypeRelation *relation, Type *other)
88 {
89 if (!other->IsObjectType() || kind_ != other->AsObjectType()->Kind()) {
90 return;
91 }
92
93 ObjectType *otherObj = other->AsObjectType();
94 if (desc_->properties.size() != otherObj->Properties().size() ||
95 CallSignatures().size() != otherObj->CallSignatures().size() ||
96 ConstructSignatures().size() != otherObj->ConstructSignatures().size() ||
97 (desc_->numberIndexInfo && !otherObj->NumberIndexInfo()) ||
98 (!desc_->numberIndexInfo && otherObj->NumberIndexInfo()) ||
99 (desc_->stringIndexInfo && !otherObj->StringIndexInfo()) ||
100 (!desc_->stringIndexInfo && otherObj->StringIndexInfo())) {
101 relation->Result(false);
102 return;
103 }
104
105 if (!IsPropertiesIdentical(relation, otherObj)) {
106 return;
107 }
108
109 if (!EachSignatureRelatedToSomeSignature(relation, CallSignatures(), otherObj->CallSignatures()) ||
110 !EachSignatureRelatedToSomeSignature(relation, otherObj->CallSignatures(), CallSignatures())) {
111 return;
112 }
113
114 if (!EachSignatureRelatedToSomeSignature(relation, ConstructSignatures(), otherObj->ConstructSignatures()) ||
115 !EachSignatureRelatedToSomeSignature(relation, otherObj->ConstructSignatures(), ConstructSignatures())) {
116 return;
117 }
118
119 if (!IsIndexInfosIdentical(relation, desc_->numberIndexInfo, otherObj->NumberIndexInfo())||
120 !IsIndexInfosIdentical(relation, desc_->stringIndexInfo, otherObj->StringIndexInfo())) {
121 return;
122 }
123 }
124
AssignProperties(TypeRelation * relation,ObjectType * source)125 void ObjectType::AssignProperties(TypeRelation *relation, ObjectType *source)
126 {
127 const ArenaVector<binder::LocalVariable *> &targetProperties = Properties();
128 IndexInfo *numberInfo = NumberIndexInfo();
129 IndexInfo *stringInfo = StringIndexInfo();
130
131 for (auto *it : targetProperties) {
132 binder::LocalVariable *found = source->GetProperty(it->Name(), true);
133 Type *targetType = relation->GetChecker()->GetTypeOfVariable(it);
134
135 if (found) {
136 Type *sourceType = relation->GetChecker()->GetTypeOfVariable(found);
137
138 if (!relation->IsAssignableTo(sourceType, targetType)) {
139 return;
140 }
141
142 if (found->HasFlag(binder::VariableFlags::OPTIONAL) && !it->HasFlag(binder::VariableFlags::OPTIONAL)) {
143 relation->Result(false);
144 return;
145 }
146
147 continue;
148 }
149
150 if (numberInfo && it->HasFlag(binder::VariableFlags::NUMERIC_NAME) &&
151 !relation->IsAssignableTo(numberInfo->GetType(), targetType)) {
152 return;
153 }
154
155 if (stringInfo && !relation->IsAssignableTo(stringInfo->GetType(), targetType)) {
156 return;
157 }
158
159 if (!it->HasFlag(binder::VariableFlags::OPTIONAL)) {
160 relation->Result(false);
161 return;
162 }
163 }
164 }
165
AssignSignatures(TypeRelation * relation,ObjectType * source,bool assignCallSignatures)166 void ObjectType::AssignSignatures(TypeRelation *relation, ObjectType *source, bool assignCallSignatures)
167 {
168 ArenaVector<Signature *> targetSignatures = assignCallSignatures ? CallSignatures() : ConstructSignatures();
169 ArenaVector<Signature *> sourceSignatures =
170 assignCallSignatures ? source->CallSignatures() : source->ConstructSignatures();
171
172 for (auto *targetSignature : targetSignatures) {
173 bool foundCompatible = false;
174 for (auto *sourceSignature : sourceSignatures) {
175 targetSignature->AssignmentTarget(relation, sourceSignature);
176
177 if (relation->IsTrue()) {
178 foundCompatible = true;
179 break;
180 }
181 }
182
183 if (!foundCompatible) {
184 relation->Result(false);
185 return;
186 }
187 }
188 }
189
AssignIndexInfo(TypeRelation * relation,ObjectType * source,bool assignNumberInfo)190 void ObjectType::AssignIndexInfo([[maybe_unused]] TypeRelation *relation, ObjectType *source, bool assignNumberInfo)
191 {
192 IndexInfo *targetInfo = assignNumberInfo ? NumberIndexInfo() : StringIndexInfo();
193 IndexInfo *sourceInfo = assignNumberInfo ? source->NumberIndexInfo() : source->StringIndexInfo();
194
195 if (targetInfo) {
196 if (sourceInfo) {
197 targetInfo->AssignmentTarget(relation, sourceInfo);
198 return;
199 }
200
201 for (auto *it : source->Properties()) {
202 if (assignNumberInfo && !it->HasFlag(binder::VariableFlags::NUMERIC_NAME)) {
203 continue;
204 }
205
206 if (!relation->IsAssignableTo(relation->GetChecker()->GetTypeOfVariable(it), targetInfo->GetType())) {
207 return;
208 }
209 }
210 }
211 }
212
checkExcessProperties(TypeRelation * relation,ObjectType * source)213 void ObjectType::checkExcessProperties(TypeRelation *relation, ObjectType *source)
214 {
215 for (auto *it : source->Properties()) {
216 auto *found = GetProperty(it->Name(), true);
217
218 if (found || (it->HasFlag(binder::VariableFlags::NUMERIC_NAME) && NumberIndexInfo()) || StringIndexInfo()) {
219 continue;
220 }
221
222 relation->Result(false);
223 return;
224 }
225 }
226
AssignmentTarget(TypeRelation * relation,Type * source)227 void ObjectType::AssignmentTarget(TypeRelation *relation, Type *source)
228 {
229 if (!source->IsObjectType()) {
230 relation->Result(false);
231 return;
232 }
233
234 relation->Result(true);
235
236 ObjectType *sourceObj = source->AsObjectType();
237
238 if (sourceObj->HasObjectFlag(ObjectFlags::CHECK_EXCESS_PROPS)) {
239 checkExcessProperties(relation, sourceObj);
240 }
241
242 if (relation->IsTrue()) {
243 AssignProperties(relation, sourceObj);
244
245 if (relation->IsTrue()) {
246 AssignSignatures(relation, sourceObj);
247
248 if (relation->IsTrue()) {
249 AssignSignatures(relation, sourceObj, false);
250
251 if (relation->IsTrue()) {
252 AssignIndexInfo(relation, sourceObj);
253
254 if (relation->IsTrue()) {
255 AssignIndexInfo(relation, sourceObj, false);
256 }
257 }
258 }
259 }
260 }
261 }
262
263 } // namespace panda::es2panda::checker
264