• 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 "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