• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "objectType.h"
17 
18 #include <typescript/types/indexInfo.h>
19 #include <typescript/types/interfaceType.h>
20 #include <typescript/types/signature.h>
21 #include <typescript/checker.h>
22 
23 namespace panda::es2panda::checker {
24 
EachSignatureRelatedToSomeSignature(TypeRelation * relation,const ArenaVector<Signature * > & sourceSignatures,const ArenaVector<Signature * > & targetSignatures)25 bool ObjectType::EachSignatureRelatedToSomeSignature(TypeRelation *relation,
26                                                      const ArenaVector<Signature *> &sourceSignatures,
27                                                      const ArenaVector<Signature *> &targetSignatures)
28 {
29     ArenaVector<Signature *> targetCopy = targetSignatures;
30 
31     return std::all_of(sourceSignatures.begin(), sourceSignatures.end(), [relation, &targetCopy](Signature *source) {
32         return SignatureRelatedToSomeSignature(relation, source, &targetCopy);
33     });
34 }
35 
SignatureRelatedToSomeSignature(TypeRelation * relation,Signature * sourceSignature,ArenaVector<Signature * > * targetSignatures)36 bool ObjectType::SignatureRelatedToSomeSignature(TypeRelation *relation, Signature *sourceSignature,
37                                                  ArenaVector<Signature *> *targetSignatures)
38 {
39     for (auto it = targetSignatures->begin(); it != targetSignatures->end();) {
40         if (relation->IsIdenticalTo(sourceSignature, *it)) {
41             targetSignatures->erase(it);
42             return true;
43         }
44 
45         it++;
46     }
47 
48     return false;
49 }
50 
IsPropertiesIdentical(TypeRelation * relation,ObjectType * otherObj)51 bool ObjectType::IsPropertiesIdentical(TypeRelation *relation, ObjectType *otherObj)
52 {
53     for (auto *it : desc_->properties) {
54         binder::LocalVariable *found = otherObj->Desc()->FindProperty(it->Name());
55         if (!found) {
56             relation->Result(false);
57             return false;
58         }
59 
60         relation->IsIdenticalTo(it->TsType(), found->TsType());
61 
62         if (!relation->IsTrue()) {
63             return false;
64         }
65 
66         if (it->Flags() != found->Flags()) {
67             relation->Result(false);
68             return false;
69         }
70     }
71 
72     return true;
73 }
74 
IsIndexInfosIdentical(TypeRelation * relation,IndexInfo * descIndexInfo,IndexInfo * otherIndexInfo)75 bool ObjectType::IsIndexInfosIdentical(TypeRelation *relation, IndexInfo *descIndexInfo, IndexInfo *otherIndexInfo)
76 {
77     if (descIndexInfo) {
78         relation->IsIdenticalTo(descIndexInfo, otherIndexInfo);
79         if (!relation->IsTrue()) {
80             return false;
81         }
82     }
83 
84     return true;
85 }
86 
Identical(TypeRelation * relation,Type * other)87 void ObjectType::Identical(TypeRelation *relation, Type *other)
88 {
89     if (!other->IsObjectType() || kind_ != other->AsObjectType()->Kind()) {
90         return;
91     }
92 
93     ObjectType *otherObj = other->AsObjectType();
94     if (desc_->properties.size() != otherObj->Properties().size() ||
95         CallSignatures().size() != otherObj->CallSignatures().size() ||
96         ConstructSignatures().size() != otherObj->ConstructSignatures().size() ||
97         (desc_->numberIndexInfo && !otherObj->NumberIndexInfo()) ||
98         (!desc_->numberIndexInfo && otherObj->NumberIndexInfo()) ||
99         (desc_->stringIndexInfo && !otherObj->StringIndexInfo()) ||
100         (!desc_->stringIndexInfo && otherObj->StringIndexInfo())) {
101         relation->Result(false);
102         return;
103     }
104 
105     if (!IsPropertiesIdentical(relation, otherObj)) {
106         return;
107     }
108 
109     if (!EachSignatureRelatedToSomeSignature(relation, CallSignatures(), otherObj->CallSignatures()) ||
110         !EachSignatureRelatedToSomeSignature(relation, otherObj->CallSignatures(), CallSignatures())) {
111         return;
112     }
113 
114     if (!EachSignatureRelatedToSomeSignature(relation, ConstructSignatures(), otherObj->ConstructSignatures()) ||
115         !EachSignatureRelatedToSomeSignature(relation, otherObj->ConstructSignatures(), ConstructSignatures())) {
116         return;
117     }
118 
119     if (!IsIndexInfosIdentical(relation, desc_->numberIndexInfo, otherObj->NumberIndexInfo())||
120         !IsIndexInfosIdentical(relation, desc_->stringIndexInfo, otherObj->StringIndexInfo())) {
121         return;
122     }
123 }
124 
AssignProperties(TypeRelation * relation,ObjectType * source)125 void ObjectType::AssignProperties(TypeRelation *relation, ObjectType *source)
126 {
127     const ArenaVector<binder::LocalVariable *> &targetProperties = Properties();
128     IndexInfo *numberInfo = NumberIndexInfo();
129     IndexInfo *stringInfo = StringIndexInfo();
130 
131     for (auto *it : targetProperties) {
132         binder::LocalVariable *found = source->GetProperty(it->Name(), true);
133         Type *targetType = relation->GetChecker()->GetTypeOfVariable(it);
134 
135         if (found) {
136             Type *sourceType = relation->GetChecker()->GetTypeOfVariable(found);
137 
138             if (!relation->IsAssignableTo(sourceType, targetType)) {
139                 return;
140             }
141 
142             if (found->HasFlag(binder::VariableFlags::OPTIONAL) && !it->HasFlag(binder::VariableFlags::OPTIONAL)) {
143                 relation->Result(false);
144                 return;
145             }
146 
147             continue;
148         }
149 
150         if (numberInfo && it->HasFlag(binder::VariableFlags::NUMERIC_NAME) &&
151             !relation->IsAssignableTo(numberInfo->GetType(), targetType)) {
152             return;
153         }
154 
155         if (stringInfo && !relation->IsAssignableTo(stringInfo->GetType(), targetType)) {
156             return;
157         }
158 
159         if (!it->HasFlag(binder::VariableFlags::OPTIONAL)) {
160             relation->Result(false);
161             return;
162         }
163     }
164 }
165 
AssignSignatures(TypeRelation * relation,ObjectType * source,bool assignCallSignatures)166 void ObjectType::AssignSignatures(TypeRelation *relation, ObjectType *source, bool assignCallSignatures)
167 {
168     ArenaVector<Signature *> targetSignatures = assignCallSignatures ? CallSignatures() : ConstructSignatures();
169     ArenaVector<Signature *> sourceSignatures =
170         assignCallSignatures ? source->CallSignatures() : source->ConstructSignatures();
171 
172     for (auto *targetSignature : targetSignatures) {
173         bool foundCompatible = false;
174         for (auto *sourceSignature : sourceSignatures) {
175             targetSignature->AssignmentTarget(relation, sourceSignature);
176 
177             if (relation->IsTrue()) {
178                 foundCompatible = true;
179                 break;
180             }
181         }
182 
183         if (!foundCompatible) {
184             relation->Result(false);
185             return;
186         }
187     }
188 }
189 
AssignIndexInfo(TypeRelation * relation,ObjectType * source,bool assignNumberInfo)190 void ObjectType::AssignIndexInfo([[maybe_unused]] TypeRelation *relation, ObjectType *source, bool assignNumberInfo)
191 {
192     IndexInfo *targetInfo = assignNumberInfo ? NumberIndexInfo() : StringIndexInfo();
193     IndexInfo *sourceInfo = assignNumberInfo ? source->NumberIndexInfo() : source->StringIndexInfo();
194 
195     if (targetInfo) {
196         if (sourceInfo) {
197             targetInfo->AssignmentTarget(relation, sourceInfo);
198             return;
199         }
200 
201         for (auto *it : source->Properties()) {
202             if (assignNumberInfo && !it->HasFlag(binder::VariableFlags::NUMERIC_NAME)) {
203                 continue;
204             }
205 
206             if (!relation->IsAssignableTo(relation->GetChecker()->GetTypeOfVariable(it), targetInfo->GetType())) {
207                 return;
208             }
209         }
210     }
211 }
212 
checkExcessProperties(TypeRelation * relation,ObjectType * source)213 void ObjectType::checkExcessProperties(TypeRelation *relation, ObjectType *source)
214 {
215     for (auto *it : source->Properties()) {
216         auto *found = GetProperty(it->Name(), true);
217 
218         if (found || (it->HasFlag(binder::VariableFlags::NUMERIC_NAME) && NumberIndexInfo()) || StringIndexInfo()) {
219             continue;
220         }
221 
222         relation->Result(false);
223         return;
224     }
225 }
226 
AssignmentTarget(TypeRelation * relation,Type * source)227 void ObjectType::AssignmentTarget(TypeRelation *relation, Type *source)
228 {
229     if (!source->IsObjectType()) {
230         relation->Result(false);
231         return;
232     }
233 
234     relation->Result(true);
235 
236     ObjectType *sourceObj = source->AsObjectType();
237 
238     if (sourceObj->HasObjectFlag(ObjectFlags::CHECK_EXCESS_PROPS)) {
239         checkExcessProperties(relation, sourceObj);
240     }
241 
242     if (relation->IsTrue()) {
243         AssignProperties(relation, sourceObj);
244 
245         if (relation->IsTrue()) {
246             AssignSignatures(relation, sourceObj);
247 
248             if (relation->IsTrue()) {
249                 AssignSignatures(relation, sourceObj, false);
250 
251                 if (relation->IsTrue()) {
252                     AssignIndexInfo(relation, sourceObj);
253 
254                     if (relation->IsTrue()) {
255                         AssignIndexInfo(relation, sourceObj, false);
256                     }
257                 }
258             }
259         }
260     }
261 }
262 
263 }  // namespace panda::es2panda::checker
264