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