• 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 
FirstAbstractSignature()25 Signature *ETSFunctionType::FirstAbstractSignature()
26 {
27     for (auto *it : callSignatures_) {
28         if (it->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
29             return it;
30         }
31     }
32 
33     return nullptr;
34 }
35 
ToString(std::stringstream & ss,bool precise) const36 void ETSFunctionType::ToString(std::stringstream &ss, bool precise) const
37 {
38     callSignatures_[0]->ToString(ss, nullptr, false, precise);
39 }
40 
Identical(TypeRelation * relation,Type * other)41 void ETSFunctionType::Identical(TypeRelation *relation, Type *other)
42 {
43     if (!other->IsETSFunctionType()) {
44         return;
45     }
46 
47     if (callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE)) {
48         AssignmentTarget(relation, other);
49         return;
50     }
51 
52     callSignatures_[0]->Compatible(relation, other->AsETSFunctionType()->CallSignatures()[0]);
53 }
54 
AssignmentSource(TypeRelation * relation,Type * target)55 bool ETSFunctionType::AssignmentSource(TypeRelation *relation, Type *target)
56 {
57     if (target->IsETSDynamicType()) {
58         ASSERT(relation->GetNode() != nullptr);
59         if (relation->GetNode()->IsArrowFunctionExpression()) {
60             ASSERT(callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::CALL));
61             relation->Result(true);
62             return true;
63         }
64         relation->Result(false);
65         return false;
66     }
67 
68     if (target->IsETSObjectType() && target == relation->GetChecker()->AsETSChecker()->GlobalETSObjectType()) {
69         relation->Result(true);
70         return true;
71     }
72 
73     relation->Result(false);
74     return false;
75 }
76 
ProcessSignatures(TypeRelation * relation,Signature * target,ETSFunctionType * sourceFuncType)77 static Signature *ProcessSignatures(TypeRelation *relation, Signature *target, ETSFunctionType *sourceFuncType)
78 {
79     Signature *match {};
80     for (auto *it : sourceFuncType->CallSignatures()) {
81         if (target->MinArgCount() != it->MinArgCount()) {
82             continue;
83         }
84 
85         if ((target->RestVar() != nullptr && it->RestVar() == nullptr) ||
86             (target->RestVar() == nullptr && it->RestVar() != nullptr)) {
87             continue;
88         }
89 
90         if (!it->GetSignatureInfo()->typeParams.empty()) {
91             auto *substitution = relation->GetChecker()->AsETSChecker()->NewSubstitution();
92             bool res = true;
93             for (size_t ix = 0; ix < target->MinArgCount(); ix++) {
94                 res &= relation->GetChecker()->AsETSChecker()->EnhanceSubstitutionForType(
95                     it->GetSignatureInfo()->typeParams, it->GetSignatureInfo()->params[ix]->TsType(),
96                     target->GetSignatureInfo()->params[ix]->TsType(), substitution);
97             }
98             if (target->RestVar() != nullptr) {
99                 res &= relation->GetChecker()->AsETSChecker()->EnhanceSubstitutionForType(
100                     it->GetSignatureInfo()->typeParams, it->RestVar()->TsType(), target->RestVar()->TsType(),
101                     substitution);
102             }
103             if (!res) {
104                 continue;
105             }
106             it = it->Substitute(relation, substitution);
107         }
108 
109         size_t idx = 0;
110         for (; idx != target->MinArgCount(); idx++) {
111             if (!relation->IsAssignableTo(target->Params()[idx]->TsType(), it->Params()[idx]->TsType())) {
112                 break;
113             }
114         }
115 
116         if (idx != target->MinArgCount()) {
117             continue;
118         }
119 
120         if (target->RestVar() != nullptr &&
121             !relation->IsAssignableTo(target->RestVar()->TsType(), it->RestVar()->TsType())) {
122             continue;
123         }
124 
125         if (!relation->IsAssignableTo(it->ReturnType(), target->ReturnType())) {
126             continue;
127         }
128 
129         match = it;
130         break;
131     }
132     return match;
133 }
134 
AssignmentTarget(TypeRelation * relation,Type * source)135 void ETSFunctionType::AssignmentTarget(TypeRelation *relation, Type *source)
136 {
137     if (!source->IsETSFunctionType() &&
138         (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL))) {
139         return;
140     }
141 
142     ASSERT(callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE));
143 
144     Signature *target = callSignatures_[0];
145     bool sourceIsFunctional = source->IsETSObjectType();
146     auto *sourceFuncType = sourceIsFunctional ? source->AsETSObjectType()->GetFunctionalInterfaceInvokeType()
147                                               : source->AsETSFunctionType();
148 
149     SavedTypeRelationFlagsContext savedFlagsCtx(relation, relation->GetTypeRelationFlags() |
150                                                               TypeRelationFlag::ONLY_CHECK_BOXING_UNBOXING);
151     Signature *match = ProcessSignatures(relation, target, sourceFuncType);
152 
153     if (match == nullptr) {
154         relation->Result(false);
155         return;
156     }
157 
158     if (!(target->Function()->IsThrowing() || target->HasSignatureFlag(SignatureFlags::THROWS))) {
159         if (match->Function()->IsThrowing() || match->Function()->IsRethrowing() ||
160             match->HasSignatureFlag(SignatureFlags::THROWS) || match->HasSignatureFlag(SignatureFlags::RETHROWS)) {
161             relation->GetChecker()->ThrowTypeError(
162                 "Functions that can throw exceptions cannot be assigned to non throwing functions.",
163                 relation->GetNode()->Start());
164         }
165     }
166 
167     ASSERT(relation->GetNode() != nullptr);
168     relation->Result(true);
169 }
170 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)171 Type *ETSFunctionType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
172                                    [[maybe_unused]] GlobalTypesHolder *globalTypes)
173 {
174     auto *copiedType = relation->GetChecker()->AsETSChecker()->CreateETSFunctionType(name_);
175 
176     for (auto *it : callSignatures_) {
177         copiedType->AddCallSignature(it->Copy(allocator, relation, globalTypes));
178     }
179 
180     return copiedType;
181 }
182 
Substitute(TypeRelation * relation,const Substitution * substitution)183 ETSFunctionType *ETSFunctionType::Substitute(TypeRelation *relation, const Substitution *substitution)
184 {
185     if (substitution == nullptr || substitution->empty()) {
186         return this;
187     }
188 
189     auto *checker = relation->GetChecker()->AsETSChecker();
190 
191     auto *copiedType = checker->CreateETSFunctionType(name_);
192     bool anyChange = false;
193 
194     for (auto *sig : callSignatures_) {
195         auto *newSig = sig->Substitute(relation, substitution);
196         copiedType->AddCallSignature(newSig);
197         if (newSig != sig) {
198             anyChange = true;
199         }
200     }
201 
202     return anyChange ? copiedType : this;
203 }
204 
CastFunctionParams(TypeRelation * relation,Signature * targetInvokeSig)205 checker::RelationResult ETSFunctionType::CastFunctionParams(TypeRelation *relation, Signature *targetInvokeSig)
206 {
207     auto *ourSig = callSignatures_[0];
208     auto &ourParams = ourSig->Params();
209     auto &theirParams = targetInvokeSig->Params();
210     if (ourParams.size() != theirParams.size()) {
211         return RelationResult::FALSE;
212     }
213     for (size_t i = 0; i < theirParams.size(); i++) {
214         relation->Result(RelationResult::FALSE);
215         auto savedBoxFlags = relation->GetNode()->GetBoxingUnboxingFlags();
216         relation->IsCastableTo(ourParams[i]->TsType(), theirParams[i]->TsType());
217         relation->GetNode()->SetBoxingUnboxingFlags(savedBoxFlags);
218         if (!relation->IsTrue()) {
219             return RelationResult::FALSE;
220         }
221     }
222     return RelationResult::TRUE;
223 }
224 
Cast(TypeRelation * relation,Type * target)225 void ETSFunctionType::Cast(TypeRelation *relation, Type *target)
226 {
227     ASSERT(relation->GetNode()->IsArrowFunctionExpression());
228     auto *savedNode = relation->GetNode();
229     conversion::Forbidden(relation);
230     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
231         auto *targetType = target->AsETSObjectType();
232         if (targetType->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
233             auto *targetInvokeVar = targetType->GetProperty(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME,
234                                                             PropertySearchFlags::SEARCH_INSTANCE_METHOD);
235             if (targetInvokeVar == nullptr || !targetInvokeVar->TsType()->IsETSFunctionType()) {
236                 return;
237             }
238             auto *targetInvokeSig = targetInvokeVar->TsType()->AsETSFunctionType()->CallSignatures()[0];
239             relation->Result(CastFunctionParams(relation, targetInvokeSig));
240             auto *targetReturnType = targetInvokeSig->ReturnType();
241             auto savedBoxFlags = relation->GetNode()->GetBoxingUnboxingFlags();
242             relation->IsCastableTo(callSignatures_[0]->ReturnType(), targetReturnType);
243             relation->GetNode()->SetBoxingUnboxingFlags(savedBoxFlags);
244         }
245         if (relation->IsTrue()) {
246             relation->SetNode(savedNode);
247             return;
248         }
249     }
250 }
251 
BoxPrimitives(ETSChecker * checker)252 ETSFunctionType *ETSFunctionType::BoxPrimitives(ETSChecker *checker)
253 {
254     auto *allocator = checker->Allocator();
255     auto *ret = allocator->New<ETSFunctionType>(name_, allocator);
256     for (auto *sig : callSignatures_) {
257         ret->AddCallSignature(sig->BoxPrimitives(checker));
258     }
259     return ret;
260 }
261 }  // namespace ark::es2panda::checker
262