1 /**
2 * Copyright (c) 2021 - 2024 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 "checker/types/ts/indexInfo.h"
19 #include "checker/types/ts/interfaceType.h"
20 #include "checker/types/signature.h"
21 #include "checker/checker.h"
22
23 namespace ark::es2panda::checker {
EachSignatureRelatedToSomeSignature(TypeRelation * relation,const ArenaVector<Signature * > & sourceSignatures,const ArenaVector<Signature * > & targetSignatures)24 bool ObjectType::EachSignatureRelatedToSomeSignature(TypeRelation *relation,
25 const ArenaVector<Signature *> &sourceSignatures,
26 const ArenaVector<Signature *> &targetSignatures)
27 {
28 ArenaVector<Signature *> targetCopy = targetSignatures;
29
30 return std::all_of(sourceSignatures.begin(), sourceSignatures.end(), [relation, &targetCopy](Signature *source) {
31 return SignatureRelatedToSomeSignature(relation, source, &targetCopy);
32 });
33 }
34
SignatureRelatedToSomeSignature(TypeRelation * relation,Signature * sourceSignature,ArenaVector<Signature * > * targetSignatures)35 bool ObjectType::SignatureRelatedToSomeSignature(TypeRelation *relation, Signature *sourceSignature,
36 ArenaVector<Signature *> *targetSignatures)
37 {
38 for (auto it = targetSignatures->begin(); it != targetSignatures->end();) {
39 if (relation->IsCompatibleTo(sourceSignature, *it)) {
40 targetSignatures->erase(it);
41 return true;
42 }
43
44 it++;
45 }
46
47 return false;
48 }
49
FindPropertyAndCheckIdentical(TypeRelation * relation,ObjectType * otherObj)50 bool ObjectType::FindPropertyAndCheckIdentical(TypeRelation *relation, ObjectType *otherObj)
51 {
52 for (auto *it : desc_->properties) {
53 varbinder::LocalVariable *found = otherObj->Desc()->FindProperty(it->Name());
54 if (found == nullptr) {
55 relation->Result(false);
56 return true;
57 }
58
59 relation->IsIdenticalTo(it->TsType(), found->TsType());
60
61 if (!relation->IsTrue()) {
62 return true;
63 }
64
65 if (it->Flags() != found->Flags()) {
66 relation->Result(false);
67 return true;
68 }
69 }
70 return false;
71 }
72
Identical(TypeRelation * relation,Type * other)73 void ObjectType::Identical(TypeRelation *relation, Type *other)
74 {
75 if (!other->IsObjectType() || kind_ != other->AsObjectType()->Kind()) {
76 return;
77 }
78
79 ObjectType *otherObj = other->AsObjectType();
80
81 if (desc_->properties.size() != otherObj->Properties().size() ||
82 CallSignatures().size() != otherObj->CallSignatures().size() ||
83 ConstructSignatures().size() != otherObj->ConstructSignatures().size() ||
84 (desc_->numberIndexInfo != nullptr && otherObj->NumberIndexInfo() == nullptr) ||
85 (desc_->numberIndexInfo == nullptr && otherObj->NumberIndexInfo() != nullptr) ||
86 (desc_->stringIndexInfo != nullptr && otherObj->StringIndexInfo() == nullptr) ||
87 (desc_->stringIndexInfo == nullptr && otherObj->StringIndexInfo() != nullptr)) {
88 relation->Result(false);
89 return;
90 }
91
92 if (FindPropertyAndCheckIdentical(relation, otherObj)) {
93 return;
94 }
95
96 if (!EachSignatureRelatedToSomeSignature(relation, CallSignatures(), otherObj->CallSignatures()) ||
97 !EachSignatureRelatedToSomeSignature(relation, otherObj->CallSignatures(), CallSignatures())) {
98 return;
99 }
100
101 if (!EachSignatureRelatedToSomeSignature(relation, ConstructSignatures(), otherObj->ConstructSignatures()) ||
102 !EachSignatureRelatedToSomeSignature(relation, otherObj->ConstructSignatures(), ConstructSignatures())) {
103 return;
104 }
105
106 if (desc_->numberIndexInfo != nullptr) {
107 relation->IsIdenticalTo(desc_->numberIndexInfo, otherObj->NumberIndexInfo());
108 if (!relation->IsTrue()) {
109 return;
110 }
111 }
112
113 if (desc_->stringIndexInfo != nullptr) {
114 relation->IsIdenticalTo(desc_->stringIndexInfo, otherObj->StringIndexInfo());
115 if (!relation->IsTrue()) {
116 return;
117 }
118 }
119 }
120
AssignProperties(TypeRelation * relation,ObjectType * source)121 void ObjectType::AssignProperties(TypeRelation *relation, ObjectType *source)
122 {
123 const ArenaVector<varbinder::LocalVariable *> &targetProperties = Properties();
124 IndexInfo *numberInfo = NumberIndexInfo();
125 IndexInfo *stringInfo = StringIndexInfo();
126
127 for (auto *it : targetProperties) {
128 varbinder::LocalVariable *found = source->GetProperty(it->Name(), true);
129 Type *targetType = relation->GetChecker()->GetTypeOfVariable(it);
130
131 if (found != nullptr) {
132 Type *sourceType = relation->GetChecker()->GetTypeOfVariable(found);
133
134 if (!relation->IsAssignableTo(sourceType, targetType)) {
135 return;
136 }
137
138 if (found->HasFlag(varbinder::VariableFlags::OPTIONAL) &&
139 !it->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
140 relation->Result(false);
141 return;
142 }
143
144 continue;
145 }
146
147 if (numberInfo != nullptr && it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME) &&
148 !relation->IsAssignableTo(numberInfo->GetType(), targetType)) {
149 return;
150 }
151
152 if (stringInfo != nullptr && !relation->IsAssignableTo(stringInfo->GetType(), targetType)) {
153 return;
154 }
155
156 if (!it->HasFlag(varbinder::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 != nullptr) {
193 if (sourceInfo != nullptr) {
194 targetInfo->AssignmentTarget(relation, sourceInfo);
195 return;
196 }
197
198 for (auto *it : source->Properties()) {
199 if (assignNumberInfo && !it->HasFlag(varbinder::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 != nullptr || (it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME) && NumberIndexInfo() != nullptr) ||
216 StringIndexInfo() != nullptr) {
217 continue;
218 }
219
220 relation->Result(false);
221 return;
222 }
223 }
224
AssignmentTarget(TypeRelation * relation,Type * source)225 void ObjectType::AssignmentTarget(TypeRelation *relation, Type *source)
226 {
227 if (!source->IsObjectType()) {
228 relation->Result(false);
229 return;
230 }
231
232 relation->Result(true);
233
234 ObjectType *sourceObj = source->AsObjectType();
235
236 if (sourceObj->HasObjectFlag(ObjectFlags::CHECK_EXCESS_PROPS)) {
237 CheckExcessProperties(relation, sourceObj);
238 }
239
240 // Just to avoid extra nesting level(s):
241 auto const assignIndexInfo = [this, relation, sourceObj]() -> void {
242 if (relation->IsTrue()) {
243 AssignIndexInfo(relation, sourceObj);
244
245 if (relation->IsTrue()) {
246 AssignIndexInfo(relation, sourceObj, false);
247 }
248 }
249 };
250
251 if (relation->IsTrue()) {
252 AssignProperties(relation, sourceObj);
253
254 if (relation->IsTrue()) {
255 AssignSignatures(relation, sourceObj);
256
257 if (relation->IsTrue()) {
258 AssignSignatures(relation, sourceObj, false);
259
260 assignIndexInfo();
261 }
262 }
263 }
264 }
265 } // namespace ark::es2panda::checker
266