• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "etsFunctionType.h"
17 #include "checker/types/typeRelation.h"
18 #include "checker/ETSchecker.h"
19 #include "checker/ets/conversion.h"
20 #include "ir/base/scriptFunction.h"
21 #include "ir/expressions/identifier.h"
22 
23 namespace ark::es2panda::checker {
24 
ETSFunctionType(ETSChecker * checker,util::StringView name,ArenaVector<Signature * > && signatures)25 ETSFunctionType::ETSFunctionType(ETSChecker *checker, util::StringView name, ArenaVector<Signature *> &&signatures)
26     : Type(TypeFlag::FUNCTION),
27       callSignatures_(std::move(signatures)),
28       name_(name),
29       funcInterface_(checker->ResolveFunctionalInterfaces(callSignatures_))
30 {
31 }
32 
FirstAbstractSignature()33 Signature *ETSFunctionType::FirstAbstractSignature()
34 {
35     for (auto *it : callSignatures_) {
36         if (it->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
37             return it;
38         }
39     }
40 
41     return nullptr;
42 }
43 
ToString(std::stringstream & ss,bool precise) const44 void ETSFunctionType::ToString(std::stringstream &ss, bool precise) const
45 {
46     callSignatures_[0]->ToString(ss, nullptr, false, precise);
47 }
48 
Identical(TypeRelation * relation,Type * other)49 void ETSFunctionType::Identical(TypeRelation *relation, Type *other)
50 {
51     if (!other->IsETSFunctionType()) {
52         return;
53     }
54 
55     if (callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE)) {
56         AssignmentTarget(relation, other);
57         return;
58     }
59 
60     callSignatures_[0]->Compatible(relation, other->AsETSFunctionType()->CallSignatures()[0]);
61 }
62 
AssignmentSource(TypeRelation * relation,Type * target)63 bool ETSFunctionType::AssignmentSource(TypeRelation *relation, Type *target)
64 {
65     if (target->IsETSDynamicType()) {
66         ASSERT(relation->GetNode() != nullptr);
67         if (relation->GetNode()->IsArrowFunctionExpression()) {
68             ASSERT(callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::CALL));
69             relation->Result(true);
70             return true;
71         }
72         relation->Result(false);
73         return false;
74     }
75 
76     if (target->IsETSObjectType() && target == relation->GetChecker()->AsETSChecker()->GlobalETSObjectType()) {
77         relation->Result(true);
78         return true;
79     }
80 
81     relation->Result(false);
82     return false;
83 }
84 
EnhanceSignatureSubstitution(TypeRelation * relation,Signature * super,Signature * sub)85 static Signature *EnhanceSignatureSubstitution(TypeRelation *relation, Signature *super, Signature *sub)
86 {
87     auto checker = relation->GetChecker()->AsETSChecker();
88     auto *substitution = checker->NewSubstitution();
89 
90     auto const enhance = [checker, sub, substitution](Type *param, Type *arg) {
91         return checker->EnhanceSubstitutionForType(sub->GetSignatureInfo()->typeParams, param, arg, substitution);
92     };
93     for (size_t ix = 0; ix < super->MinArgCount(); ix++) {
94         if (!enhance(sub->GetSignatureInfo()->params[ix]->TsType(), super->GetSignatureInfo()->params[ix]->TsType())) {
95             return nullptr;
96         }
97     }
98     if (super->RestVar() != nullptr) {
99         if (!enhance(sub->RestVar()->TsType(), super->RestVar()->TsType())) {
100             return nullptr;
101         }
102     }
103     return sub->Substitute(relation, substitution);
104 }
105 
IsCompatibleSignature(TypeRelation * relation,Signature * super,Signature * sub)106 static bool IsCompatibleSignature(TypeRelation *relation, Signature *super, Signature *sub)
107 {
108     if (super->MinArgCount() != sub->MinArgCount()) {
109         return false;
110     }
111     if ((super->RestVar() != nullptr && sub->RestVar() == nullptr) ||
112         (super->RestVar() == nullptr && sub->RestVar() != nullptr)) {
113         return false;
114     }
115     if (!sub->GetSignatureInfo()->typeParams.empty()) {
116         sub = EnhanceSignatureSubstitution(relation, super, sub);
117         if (sub == nullptr) {
118             return false;
119         }
120     }
121 
122     for (size_t idx = 0; idx != super->MinArgCount(); idx++) {
123         if (!relation->IsSupertypeOf(sub->Params()[idx]->TsType(), super->Params()[idx]->TsType())) {
124             return false;
125         }
126     }
127     if (super->RestVar() != nullptr && !relation->IsSupertypeOf(sub->RestVar()->TsType(), super->RestVar()->TsType())) {
128         return false;
129     }
130     if (!relation->IsSupertypeOf(super->ReturnType(), sub->ReturnType())) {
131         return false;
132     }
133     return true;
134 }
135 
CoerceToFunctionType(Type * type)136 static ETSFunctionType *CoerceToFunctionType(Type *type)
137 {
138     if (type->IsETSFunctionType()) {
139         return type->AsETSFunctionType();
140     }
141     if (type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
142         return type->AsETSObjectType()->GetFunctionalInterfaceInvokeType();
143     }
144     return nullptr;
145 }
146 
IsSupertypeOf(TypeRelation * relation,Type * source)147 void ETSFunctionType::IsSupertypeOf(TypeRelation *relation, Type *source)
148 {
149     ETSFunctionType *const targetFnType = this;
150     ETSFunctionType *const sourceFnType = CoerceToFunctionType(source);
151     if (sourceFnType == nullptr) {
152         relation->Result(false);
153         return;
154     }
155 
156     ASSERT(targetFnType->IsETSArrowType() && sourceFnType->IsETSArrowType());
157     Signature *const targetSig = targetFnType->CallSignatures()[0];
158     Signature *const sourceSig = sourceFnType->CallSignatures()[0];
159 
160     SavedTypeRelationFlagsContext savedFlagsCtx(relation, relation->GetTypeRelationFlags() |
161                                                               TypeRelationFlag::ONLY_CHECK_BOXING_UNBOXING);
162     if (!IsCompatibleSignature(relation, targetSig, sourceSig)) {
163         relation->Result(false);
164         return;
165     }
166 
167     if (!(targetSig->Function()->IsThrowing() || targetSig->HasSignatureFlag(SignatureFlags::THROWS))) {
168         if (sourceSig->Function()->IsThrowing() || sourceSig->Function()->IsRethrowing() ||
169             sourceSig->HasSignatureFlag(SignatureFlags::THROWS) ||
170             sourceSig->HasSignatureFlag(SignatureFlags::RETHROWS)) {
171             relation->Result(false);
172             return;
173         }
174     }
175 
176     ASSERT(relation->GetNode() != nullptr);
177     relation->Result(true);
178 }
179 
AssignmentTarget(TypeRelation * relation,Type * source)180 void ETSFunctionType::AssignmentTarget(TypeRelation *relation, Type *source)
181 {
182     ETSFunctionType *const targetFnType = this;
183     ETSFunctionType *const sourceFnType = CoerceToFunctionType(source);
184     if (sourceFnType == nullptr) {
185         relation->Result(false);
186         return;
187     }
188 
189     ASSERT(IsETSArrowType() && CallSignatures()[0]->HasSignatureFlag(SignatureFlags::TYPE));
190     Signature *const targetSig = targetFnType->CallSignatures()[0];
191 
192     SavedTypeRelationFlagsContext savedFlagsCtx(relation, relation->GetTypeRelationFlags() |
193                                                               TypeRelationFlag::ONLY_CHECK_BOXING_UNBOXING);
194 
195     // NOTE(vpukhov): #18866 optionally-typed lambda shouldnt have mulutiple signatures
196     // CC-OFFNXT(G.FMT.14-CPP) project code style
197     Signature *const match = [relation, targetSig, sourceFnType]() -> Signature * {
198         for (auto it : sourceFnType->CallSignatures()) {
199             if (IsCompatibleSignature(relation, targetSig, it)) {
200                 return it;
201             }
202         }
203         return nullptr;
204     }();
205     if (match == nullptr) {
206         relation->Result(false);
207         return;
208     }
209 
210     if (!(targetSig->Function()->IsThrowing() || targetSig->HasSignatureFlag(SignatureFlags::THROWS))) {
211         if (match->Function()->IsThrowing() || match->Function()->IsRethrowing() ||
212             match->HasSignatureFlag(SignatureFlags::THROWS) || match->HasSignatureFlag(SignatureFlags::RETHROWS)) {
213             relation->GetChecker()->LogTypeError(
214                 "Functions that can throw exceptions cannot be assigned to non throwing functions.",
215                 relation->GetNode()->Start());
216             relation->Result(RelationResult::ERROR);
217             return;
218         }
219     }
220 
221     ASSERT(relation->GetNode() != nullptr);
222     relation->Result(true);
223 }
224 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)225 Type *ETSFunctionType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
226                                    [[maybe_unused]] GlobalTypesHolder *globalTypes)
227 {
228     auto *copiedType = relation->GetChecker()->AsETSChecker()->CreateETSFunctionType(name_);
229 
230     for (auto *it : callSignatures_) {
231         copiedType->AddCallSignature(it->Copy(allocator, relation, globalTypes));
232     }
233 
234     return copiedType;
235 }
236 
Substitute(TypeRelation * relation,const Substitution * substitution)237 ETSFunctionType *ETSFunctionType::Substitute(TypeRelation *relation, const Substitution *substitution)
238 {
239     if (substitution == nullptr || substitution->empty()) {
240         return this;
241     }
242 
243     auto *checker = relation->GetChecker()->AsETSChecker();
244 
245     auto *copiedType = checker->CreateETSFunctionType(name_);
246     bool anyChange = false;
247 
248     for (auto *sig : callSignatures_) {
249         auto *newSig = sig->Substitute(relation, substitution);
250         copiedType->AddCallSignature(newSig);
251         if (newSig != sig) {
252             anyChange = true;
253         }
254     }
255 
256     return anyChange ? copiedType : this;
257 }
258 
CastFunctionParams(TypeRelation * relation,Signature * targetInvokeSig)259 checker::RelationResult ETSFunctionType::CastFunctionParams(TypeRelation *relation, Signature *targetInvokeSig)
260 {
261     auto *ourSig = callSignatures_[0];
262     auto &ourParams = ourSig->Params();
263     auto &theirParams = targetInvokeSig->Params();
264     if (ourParams.size() != theirParams.size()) {
265         return RelationResult::FALSE;
266     }
267     for (size_t i = 0; i < theirParams.size(); i++) {
268         relation->Result(RelationResult::FALSE);
269         auto savedBoxFlags = relation->GetNode()->GetBoxingUnboxingFlags();
270         relation->IsCastableTo(ourParams[i]->TsType(), theirParams[i]->TsType());
271         relation->GetNode()->SetBoxingUnboxingFlags(savedBoxFlags);
272         if (!relation->IsTrue()) {
273             return RelationResult::FALSE;
274         }
275     }
276     return RelationResult::TRUE;
277 }
278 
Cast(TypeRelation * relation,Type * target)279 void ETSFunctionType::Cast(TypeRelation *relation, Type *target)
280 {
281     ASSERT(relation->GetNode()->IsArrowFunctionExpression());
282     auto *savedNode = relation->GetNode();
283     conversion::Forbidden(relation);
284     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
285         auto *targetType = target->AsETSObjectType();
286         if (targetType->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
287             auto *targetInvokeVar = targetType->GetProperty(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME,
288                                                             PropertySearchFlags::SEARCH_INSTANCE_METHOD);
289             if (targetInvokeVar == nullptr || !targetInvokeVar->TsType()->IsETSFunctionType()) {
290                 return;
291             }
292             auto *targetInvokeSig = targetInvokeVar->TsType()->AsETSFunctionType()->CallSignatures()[0];
293             relation->Result(CastFunctionParams(relation, targetInvokeSig));
294             auto *targetReturnType = targetInvokeSig->ReturnType();
295             auto savedBoxFlags = relation->GetNode()->GetBoxingUnboxingFlags();
296             relation->IsCastableTo(callSignatures_[0]->ReturnType(), targetReturnType);
297             relation->GetNode()->SetBoxingUnboxingFlags(savedBoxFlags);
298         }
299         if (relation->IsTrue()) {
300             relation->SetNode(savedNode);
301             return;
302         }
303     }
304 }
305 
IsSubtypeOf(TypeRelation * relation,Type * target)306 void ETSFunctionType::IsSubtypeOf(TypeRelation *relation, Type *target)
307 {
308     ETSChecker *checker = relation->GetChecker()->AsETSChecker();
309     auto *source = checker->FunctionTypeToFunctionalInterfaceType(callSignatures_[0]);
310 
311     if (relation->IsSupertypeOf(target, source)) {
312         relation->Result(true);
313         return;
314     }
315 
316     relation->Result(false);
317 }
318 
BoxPrimitives(ETSChecker * checker)319 ETSFunctionType *ETSFunctionType::BoxPrimitives(ETSChecker *checker)
320 {
321     auto *allocator = checker->Allocator();
322     auto *ret = allocator->New<ETSFunctionType>(name_, allocator);
323     for (auto *sig : callSignatures_) {
324         ret->AddCallSignature(sig->BoxPrimitives(checker));
325     }
326     return ret;
327 }
328 }  // namespace ark::es2panda::checker
329