• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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