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