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