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 "interfaceType.h"
17
18 #include "varbinder/variable.h"
19 #include "checker/checker.h"
20 #include "checker/types/ts/typeParameter.h"
21
22 #include <algorithm>
23 #include <utility>
24
25 namespace ark::es2panda::checker {
ToString(std::stringstream & ss,bool precise) const26 void InterfaceType::ToString(std::stringstream &ss, [[maybe_unused]] bool precise) const
27 {
28 ss << name_;
29
30 if (!typeParamTypes_.empty()) {
31 ss << "<";
32
33 for (auto it = typeParamTypes_.begin(); it != typeParamTypes_.end(); it++) {
34 (*it)->ToString(ss);
35
36 if (std::next(it) != typeParamTypes_.end()) {
37 ss << ", ";
38 }
39 }
40
41 ss << ">";
42 }
43 }
44
CheckVarType(TypeRelation * relation,const ArenaVector<varbinder::LocalVariable * > & targetProperties,const ArenaVector<varbinder::LocalVariable * > & sourceProperties)45 bool InterfaceType::CheckVarType(TypeRelation *relation,
46 const ArenaVector<varbinder::LocalVariable *> &targetProperties,
47 const ArenaVector<varbinder::LocalVariable *> &sourceProperties)
48 {
49 for (auto *targetProp : targetProperties) {
50 bool foundProp = std::any_of(sourceProperties.begin(), sourceProperties.end(),
51 [targetProp, relation](varbinder::LocalVariable *sourceProp) {
52 if (targetProp->Name() == sourceProp->Name()) {
53 Type *targetType = relation->GetChecker()->GetTypeOfVariable(targetProp);
54 Type *sourceType = relation->GetChecker()->GetTypeOfVariable(sourceProp);
55 return relation->IsIdenticalTo(targetType, sourceType);
56 }
57
58 return false; // CC-OFF(G.FMT.02) project code style
59 });
60 if (!foundProp) {
61 relation->Result(false);
62 return true;
63 }
64 }
65 return false;
66 }
67
Identical(TypeRelation * relation,Type * other)68 void InterfaceType::Identical(TypeRelation *relation, Type *other)
69 {
70 if (!other->IsObjectType() || !other->AsObjectType()->IsInterfaceType()) {
71 return;
72 }
73
74 InterfaceType *otherInterface = other->AsObjectType()->AsInterfaceType();
75
76 const ArenaVector<varbinder::LocalVariable *> &targetProperties = Properties();
77 const ArenaVector<varbinder::LocalVariable *> &sourceProperties = otherInterface->Properties();
78
79 if (targetProperties.size() != sourceProperties.size()) {
80 relation->Result(false);
81 return;
82 }
83
84 if (CheckVarType(relation, targetProperties, sourceProperties)) {
85 return;
86 }
87
88 const ArenaVector<Signature *> &targetCallSignatures = CallSignatures();
89 const ArenaVector<Signature *> &sourceCallSignatures = otherInterface->CallSignatures();
90 if (targetCallSignatures.size() != sourceCallSignatures.size()) {
91 relation->Result(false);
92 return;
93 }
94
95 if (!EachSignatureRelatedToSomeSignature(relation, targetCallSignatures, sourceCallSignatures) ||
96 !EachSignatureRelatedToSomeSignature(relation, sourceCallSignatures, targetCallSignatures)) {
97 return;
98 }
99
100 const ArenaVector<Signature *> &targetConstructSignatures = ConstructSignatures();
101 const ArenaVector<Signature *> &sourceConstructSignatures = otherInterface->ConstructSignatures();
102
103 if (targetConstructSignatures.size() != sourceConstructSignatures.size()) {
104 relation->Result(false);
105 return;
106 }
107
108 if (!EachSignatureRelatedToSomeSignature(relation, targetConstructSignatures, sourceConstructSignatures) ||
109 !EachSignatureRelatedToSomeSignature(relation, sourceConstructSignatures, targetConstructSignatures)) {
110 return;
111 }
112
113 IndexInfo *targetNumberInfo = NumberIndexInfo();
114 IndexInfo *sourceNumberInfo = otherInterface->NumberIndexInfo();
115
116 if ((targetNumberInfo != nullptr && sourceNumberInfo == nullptr) ||
117 (targetNumberInfo == nullptr && sourceNumberInfo != nullptr)) {
118 relation->Result(false);
119 return;
120 }
121
122 relation->IsIdenticalTo(targetNumberInfo, sourceNumberInfo);
123
124 CheckStringInfo(relation, otherInterface);
125 }
126
CheckStringInfo(TypeRelation * relation,InterfaceType * otherInterface)127 void InterfaceType::CheckStringInfo(TypeRelation *relation, InterfaceType *otherInterface)
128 {
129 if (relation->IsTrue()) {
130 IndexInfo *targetStringInfo = StringIndexInfo();
131 IndexInfo *sourceStringInfo = otherInterface->StringIndexInfo();
132
133 if ((targetStringInfo != nullptr && sourceStringInfo == nullptr) ||
134 (targetStringInfo == nullptr && sourceStringInfo != nullptr)) {
135 relation->Result(false);
136 return;
137 }
138
139 relation->IsIdenticalTo(targetStringInfo, sourceStringInfo);
140 }
141 }
142
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)143 Type *InterfaceType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
144 {
145 ObjectDescriptor *copiedDesc = allocator->New<ObjectDescriptor>(allocator);
146
147 desc_->Copy(allocator, copiedDesc, relation, globalTypes);
148
149 Type *newInterfaceType = allocator->New<InterfaceType>(allocator, name_, copiedDesc);
150
151 ES2PANDA_ASSERT(newInterfaceType != nullptr);
152 for (auto *it : bases_) {
153 newInterfaceType->AsObjectType()->AsInterfaceType()->AddBase(
154 it->Instantiate(allocator, relation, globalTypes)->AsObjectType());
155 }
156
157 return newInterfaceType;
158 }
159
CollectSignatures(ArenaVector<Signature * > * collectedSignatures,bool collectCallSignatures) const160 void InterfaceType::CollectSignatures(ArenaVector<Signature *> *collectedSignatures, bool collectCallSignatures) const
161 {
162 if (collectCallSignatures) {
163 for (auto *it : desc_->callSignatures) {
164 collectedSignatures->push_back(it);
165 }
166 } else {
167 for (auto *it : desc_->constructSignatures) {
168 collectedSignatures->push_back(it);
169 }
170 }
171
172 for (auto *it : bases_) {
173 it->AsInterfaceType()->CollectSignatures(collectedSignatures, collectCallSignatures);
174 }
175 }
176
CollectProperties(ArenaVector<varbinder::LocalVariable * > * collectedProperties) const177 void InterfaceType::CollectProperties(ArenaVector<varbinder::LocalVariable *> *collectedProperties) const
178 {
179 for (auto *currentProp : desc_->properties) {
180 bool propAlreadyCollected = false;
181 for (auto *collectedProp : *collectedProperties) {
182 if (currentProp->Name() == collectedProp->Name()) {
183 propAlreadyCollected = true;
184 break;
185 }
186 }
187
188 if (propAlreadyCollected) {
189 continue;
190 }
191
192 collectedProperties->push_back(currentProp);
193 }
194
195 for (auto *it : bases_) {
196 it->AsInterfaceType()->CollectProperties(collectedProperties);
197 }
198 }
199
FindIndexInfo(bool findNumberInfo) const200 const IndexInfo *InterfaceType::FindIndexInfo(bool findNumberInfo) const
201 {
202 const IndexInfo *foundInfo = nullptr;
203
204 if (findNumberInfo && desc_->numberIndexInfo != nullptr) {
205 foundInfo = desc_->numberIndexInfo;
206 } else if (!findNumberInfo && desc_->stringIndexInfo != nullptr) {
207 foundInfo = desc_->stringIndexInfo;
208 }
209
210 for (auto it = bases_.begin(); it != bases_.end() && foundInfo == nullptr; it++) {
211 foundInfo = (*it)->AsInterfaceType()->FindIndexInfo(findNumberInfo);
212 }
213
214 return foundInfo;
215 }
216
FindIndexInfo(bool findNumberInfo)217 IndexInfo *InterfaceType::FindIndexInfo(bool findNumberInfo)
218 {
219 IndexInfo *foundInfo = nullptr;
220
221 if (findNumberInfo && desc_->numberIndexInfo != nullptr) {
222 foundInfo = desc_->numberIndexInfo;
223 } else if (!findNumberInfo && desc_->stringIndexInfo != nullptr) {
224 foundInfo = desc_->stringIndexInfo;
225 }
226
227 for (auto it = bases_.begin(); it != bases_.end() && foundInfo == nullptr; it++) {
228 foundInfo = (*it)->AsInterfaceType()->FindIndexInfo(findNumberInfo);
229 }
230
231 return foundInfo;
232 }
233
GetTypeFacts() const234 TypeFacts InterfaceType::GetTypeFacts() const
235 {
236 if (desc_->properties.empty() && desc_->callSignatures.empty() && desc_->constructSignatures.empty() &&
237 desc_->stringIndexInfo == nullptr && desc_->numberIndexInfo == nullptr) {
238 if (bases_.empty()) {
239 return TypeFacts::EMPTY_OBJECT_FACTS;
240 }
241
242 bool isEmpty = true;
243 for (auto it = bases_.begin(); isEmpty && it != bases_.end(); it++) {
244 if (!(*it)->Properties().empty() || !(*it)->CallSignatures().empty() ||
245 !(*it)->ConstructSignatures().empty() || (*it)->StringIndexInfo() != nullptr ||
246 (*it)->NumberIndexInfo() != nullptr) {
247 isEmpty = false;
248 }
249 }
250
251 if (isEmpty) {
252 return TypeFacts::EMPTY_OBJECT_FACTS;
253 }
254 }
255
256 return TypeFacts::OBJECT_FACTS;
257 }
258 } // namespace ark::es2panda::checker
259