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