1 /**
2 * Copyright (c) 2021-2025 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->SignatureIsSupertypeOf(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
IdenticalPropertiesHelper(TypeRelation * relation,ObjectType * otherObj)73 bool ObjectType::IdenticalPropertiesHelper(TypeRelation *relation, ObjectType *otherObj)
74 {
75 if (desc_->properties.size() != otherObj->Properties().size() ||
76 CallSignatures().size() != otherObj->CallSignatures().size() ||
77 ConstructSignatures().size() != otherObj->ConstructSignatures().size() ||
78 (desc_->numberIndexInfo != nullptr && otherObj->NumberIndexInfo() == nullptr) ||
79 (desc_->numberIndexInfo == nullptr && otherObj->NumberIndexInfo() != nullptr) ||
80 (desc_->stringIndexInfo != nullptr && otherObj->StringIndexInfo() == nullptr) ||
81 (desc_->stringIndexInfo == nullptr && otherObj->StringIndexInfo() != nullptr)) {
82 relation->Result(false);
83 return false;
84 }
85 return true;
86 }
87
Identical(TypeRelation * relation,Type * other)88 void ObjectType::Identical(TypeRelation *relation, Type *other)
89 {
90 if (!other->IsObjectType() || kind_ != other->AsObjectType()->Kind()) {
91 return;
92 }
93
94 ObjectType *otherObj = other->AsObjectType();
95
96 if (!IdenticalPropertiesHelper(relation, otherObj)) {
97 return;
98 }
99
100 if (FindPropertyAndCheckIdentical(relation, otherObj)) {
101 return;
102 }
103
104 if (!EachSignatureRelatedToSomeSignature(relation, CallSignatures(), otherObj->CallSignatures()) ||
105 !EachSignatureRelatedToSomeSignature(relation, otherObj->CallSignatures(), CallSignatures())) {
106 return;
107 }
108
109 if (!EachSignatureRelatedToSomeSignature(relation, ConstructSignatures(), otherObj->ConstructSignatures()) ||
110 !EachSignatureRelatedToSomeSignature(relation, otherObj->ConstructSignatures(), ConstructSignatures())) {
111 return;
112 }
113
114 if (desc_->numberIndexInfo != nullptr) {
115 relation->IsIdenticalTo(desc_->numberIndexInfo, otherObj->NumberIndexInfo());
116 if (!relation->IsTrue()) {
117 return;
118 }
119 }
120
121 if (desc_->stringIndexInfo != nullptr) {
122 relation->IsIdenticalTo(desc_->stringIndexInfo, otherObj->StringIndexInfo());
123 if (!relation->IsTrue()) {
124 return;
125 }
126 }
127 }
128
AssignProperties(TypeRelation * relation,ObjectType * source)129 void ObjectType::AssignProperties(TypeRelation *relation, ObjectType *source)
130 {
131 const ArenaVector<varbinder::LocalVariable *> &targetProperties = Properties();
132 IndexInfo *numberInfo = NumberIndexInfo();
133 IndexInfo *stringInfo = StringIndexInfo();
134
135 for (auto *it : targetProperties) {
136 varbinder::LocalVariable *found = source->GetProperty(it->Name(), true);
137 Type *targetType = relation->GetChecker()->GetTypeOfVariable(it);
138
139 if (found != nullptr) {
140 Type *sourceType = relation->GetChecker()->GetTypeOfVariable(found);
141
142 if (!relation->IsAssignableTo(sourceType, targetType)) {
143 return;
144 }
145
146 if (found->HasFlag(varbinder::VariableFlags::OPTIONAL) &&
147 !it->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
148 relation->Result(false);
149 return;
150 }
151
152 continue;
153 }
154
155 if (numberInfo != nullptr && it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME) &&
156 !relation->IsAssignableTo(numberInfo->GetType(), targetType)) {
157 return;
158 }
159
160 if (stringInfo != nullptr && !relation->IsAssignableTo(stringInfo->GetType(), targetType)) {
161 return;
162 }
163
164 if (!it->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
165 relation->Result(false);
166 return;
167 }
168 }
169 }
170
AssignSignatures(TypeRelation * relation,ObjectType * source,bool assignCallSignatures)171 void ObjectType::AssignSignatures(TypeRelation *relation, ObjectType *source, bool assignCallSignatures)
172 {
173 ArenaVector<Signature *> targetSignatures = assignCallSignatures ? CallSignatures() : ConstructSignatures();
174 ArenaVector<Signature *> sourceSignatures =
175 assignCallSignatures ? source->CallSignatures() : source->ConstructSignatures();
176
177 for (auto *targetSignature : targetSignatures) {
178 bool foundCompatible = false;
179 for (auto *sourceSignature : sourceSignatures) {
180 targetSignature->AssignmentTarget(relation, sourceSignature);
181
182 if (relation->IsTrue()) {
183 foundCompatible = true;
184 break;
185 }
186 }
187
188 if (!foundCompatible) {
189 relation->Result(false);
190 return;
191 }
192 }
193 }
194
AssignIndexInfo(TypeRelation * relation,ObjectType * source,bool assignNumberInfo)195 void ObjectType::AssignIndexInfo([[maybe_unused]] TypeRelation *relation, ObjectType *source, bool assignNumberInfo)
196 {
197 IndexInfo *targetInfo = assignNumberInfo ? NumberIndexInfo() : StringIndexInfo();
198 IndexInfo *sourceInfo = assignNumberInfo ? source->NumberIndexInfo() : source->StringIndexInfo();
199
200 if (targetInfo != nullptr) {
201 if (sourceInfo != nullptr) {
202 targetInfo->AssignmentTarget(relation, sourceInfo);
203 return;
204 }
205
206 for (auto *it : source->Properties()) {
207 if (assignNumberInfo && !it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME)) {
208 continue;
209 }
210
211 if (!relation->IsAssignableTo(relation->GetChecker()->GetTypeOfVariable(it), targetInfo->GetType())) {
212 return;
213 }
214 }
215 }
216 }
217
CheckExcessProperties(TypeRelation * relation,ObjectType * source)218 void ObjectType::CheckExcessProperties(TypeRelation *relation, ObjectType *source)
219 {
220 for (auto *it : source->Properties()) {
221 auto *found = GetProperty(it->Name(), true);
222
223 if (found != nullptr || (it->HasFlag(varbinder::VariableFlags::NUMERIC_NAME) && NumberIndexInfo() != nullptr) ||
224 StringIndexInfo() != nullptr) {
225 continue;
226 }
227
228 relation->Result(false);
229 return;
230 }
231 }
232
AssignmentTarget(TypeRelation * relation,Type * source)233 void ObjectType::AssignmentTarget(TypeRelation *relation, Type *source)
234 {
235 if (!source->IsObjectType()) {
236 relation->Result(false);
237 return;
238 }
239
240 relation->Result(true);
241
242 ObjectType *sourceObj = source->AsObjectType();
243
244 if (sourceObj->HasObjectFlag(ObjectFlags::CHECK_EXCESS_PROPS)) {
245 CheckExcessProperties(relation, sourceObj);
246 }
247
248 // Just to avoid extra nesting level(s):
249 auto const assignIndexInfo = [this, relation, sourceObj]() -> void {
250 if (relation->IsTrue()) {
251 AssignIndexInfo(relation, sourceObj);
252
253 if (relation->IsTrue()) {
254 AssignIndexInfo(relation, sourceObj, false);
255 }
256 }
257 };
258
259 if (relation->IsTrue()) {
260 AssignProperties(relation, sourceObj);
261
262 if (relation->IsTrue()) {
263 AssignSignatures(relation, sourceObj);
264
265 if (relation->IsTrue()) {
266 AssignSignatures(relation, sourceObj, false);
267
268 assignIndexInfo();
269 }
270 }
271 }
272 }
273 } // namespace ark::es2panda::checker
274