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