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