1 /*
2 * Copyright (c) 2021 - 2023 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 panda::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) const36 void ETSFunctionType::ToString(std::stringstream &ss) const
37 {
38 callSignatures_[0]->ToString(ss, nullptr);
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]->Identical(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->GetChecker()->AsETSChecker()->CreateLambdaObjectForLambdaReference(
62 relation->GetNode()->AsArrowFunctionExpression(), callSignatures_[0]->Owner());
63 relation->Result(true);
64 return true;
65 }
66 relation->Result(false);
67 return false;
68 }
69
70 relation->Result(false);
71 return false;
72 }
73
ProcessSignatures(TypeRelation * relation,Signature * target,ETSFunctionType * sourceFuncType)74 static Signature *ProcessSignatures(TypeRelation *relation, Signature *target, ETSFunctionType *sourceFuncType)
75 {
76 Signature *match {};
77 for (auto *it : sourceFuncType->CallSignatures()) {
78 if (target->MinArgCount() != it->MinArgCount()) {
79 continue;
80 }
81
82 if ((target->RestVar() != nullptr && it->RestVar() == nullptr) ||
83 (target->RestVar() == nullptr && it->RestVar() != nullptr)) {
84 continue;
85 }
86
87 if (!it->GetSignatureInfo()->typeParams.empty()) {
88 auto *substitution = relation->GetChecker()->AsETSChecker()->NewSubstitution();
89 auto *instantiatedTypeParams = relation->GetChecker()->AsETSChecker()->NewInstantiatedTypeParamsSet();
90 bool res = true;
91 for (size_t ix = 0; ix < target->MinArgCount(); ix++) {
92 res &= relation->GetChecker()->AsETSChecker()->EnhanceSubstitutionForType(
93 it->GetSignatureInfo()->typeParams, it->GetSignatureInfo()->params[ix]->TsType(),
94 target->GetSignatureInfo()->params[ix]->TsType(), substitution, instantiatedTypeParams);
95 }
96 if (target->RestVar() != nullptr) {
97 res &= relation->GetChecker()->AsETSChecker()->EnhanceSubstitutionForType(
98 it->GetSignatureInfo()->typeParams, it->RestVar()->TsType(), target->RestVar()->TsType(),
99 substitution, instantiatedTypeParams);
100 }
101 if (!res) {
102 continue;
103 }
104 it = it->Substitute(relation, substitution);
105 }
106
107 size_t idx = 0;
108 for (; idx != target->MinArgCount(); idx++) {
109 if (!relation->IsIdenticalTo(target->Params()[idx]->TsType(), it->Params()[idx]->TsType())) {
110 break;
111 }
112 }
113
114 if (idx != target->MinArgCount()) {
115 continue;
116 }
117
118 if (target->RestVar() != nullptr &&
119 !relation->IsIdenticalTo(target->RestVar()->TsType(), it->RestVar()->TsType())) {
120 continue;
121 }
122
123 if (!relation->IsAssignableTo(target->ReturnType(), it->ReturnType())) {
124 continue;
125 }
126
127 match = it;
128 break;
129 }
130 return match;
131 }
132
AssignmentTarget(TypeRelation * relation,Type * source)133 void ETSFunctionType::AssignmentTarget(TypeRelation *relation, Type *source)
134 {
135 if (!source->IsETSFunctionType() &&
136 (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL))) {
137 return;
138 }
139
140 ASSERT(callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE));
141
142 Signature *target = callSignatures_[0];
143 bool sourceIsFunctional = source->IsETSObjectType();
144 auto *sourceFuncType = sourceIsFunctional ? source->AsETSObjectType()->GetFunctionalInterfaceInvokeType()
145 : source->AsETSFunctionType();
146 Signature *match = ProcessSignatures(relation, target, sourceFuncType);
147
148 if (match == nullptr) {
149 relation->Result(false);
150 return;
151 }
152
153 if (!target->Function()->IsThrowing()) {
154 if (match->Function()->IsThrowing() || match->Function()->IsRethrowing()) {
155 relation->GetChecker()->ThrowTypeError(
156 "Functions that can throw exceptions cannot be assigned to non throwing functions.",
157 relation->GetNode()->Start());
158 }
159 }
160
161 ASSERT(relation->GetNode() != nullptr);
162 if (!sourceIsFunctional) {
163 if (relation->GetNode()->IsArrowFunctionExpression()) {
164 relation->GetChecker()->AsETSChecker()->CreateLambdaObjectForLambdaReference(
165 relation->GetNode()->AsArrowFunctionExpression(), callSignatures_[0]->Owner());
166 } else {
167 relation->GetChecker()->AsETSChecker()->CreateLambdaObjectForFunctionReference(relation->GetNode(), match,
168 callSignatures_[0]->Owner());
169 }
170 }
171
172 relation->Result(true);
173 }
174
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)175 Type *ETSFunctionType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
176 [[maybe_unused]] GlobalTypesHolder *globalTypes)
177 {
178 auto *copiedType = relation->GetChecker()->AsETSChecker()->CreateETSFunctionType(name_);
179
180 for (auto *it : callSignatures_) {
181 copiedType->AddCallSignature(it->Copy(allocator, relation, globalTypes));
182 }
183
184 return copiedType;
185 }
186
Substitute(TypeRelation * relation,const Substitution * substitution)187 ETSFunctionType *ETSFunctionType::Substitute(TypeRelation *relation, const Substitution *substitution)
188 {
189 if (substitution == nullptr || substitution->empty()) {
190 return this;
191 }
192
193 auto *checker = relation->GetChecker()->AsETSChecker();
194
195 auto *copiedType = checker->CreateETSFunctionType(name_);
196 bool anyChange = false;
197
198 for (auto *sig : callSignatures_) {
199 auto *newSig = sig->Substitute(relation, substitution);
200 copiedType->AddCallSignature(newSig);
201 if (newSig != sig) {
202 anyChange = true;
203 }
204 }
205
206 return anyChange ? copiedType : this;
207 }
208
CastFunctionParams(TypeRelation * relation,Type * target)209 checker::RelationResult ETSFunctionType::CastFunctionParams(TypeRelation *relation, Type *target)
210 {
211 auto *targetType = target->AsETSObjectType();
212 auto *body = targetType->GetDeclNode()->AsTSInterfaceDeclaration()->Body();
213 auto targetParams = body->AsTSInterfaceBody()->Body()[0]->AsMethodDefinition()->Function()->Params();
214 for (size_t i = 0; i < targetType->TypeArguments().size(); i++) {
215 relation->Result(RelationResult::FALSE);
216 callSignatures_[0]->Function()->Params()[i]->TsType()->Cast(
217 relation, targetParams[i]->AsETSParameterExpression()->Check(relation->GetChecker()->AsETSChecker()));
218 if (relation->IsTrue()) {
219 continue;
220 }
221 return RelationResult::FALSE;
222 }
223 return RelationResult::TRUE;
224 }
225
Cast(TypeRelation * relation,Type * target)226 void ETSFunctionType::Cast(TypeRelation *relation, Type *target)
227 {
228 ASSERT(relation->GetNode()->IsArrowFunctionExpression());
229 if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
230 auto *targetType = target->AsETSObjectType();
231 auto *body = targetType->GetDeclNode()->AsTSInterfaceDeclaration()->Body()->AsTSInterfaceBody();
232 auto targetParams = body->AsTSInterfaceBody()->Body()[0]->AsMethodDefinition()->Function()->Params();
233 if (targetType->HasObjectFlag(ETSObjectFlags::FUNCTIONAL_INTERFACE) &&
234 targetParams.size() == callSignatures_[0]->Function()->Params().size()) {
235 relation->Result(CastFunctionParams(relation, target));
236 }
237 relation->Result(RelationResult::FALSE);
238 auto targetReturnType = body->Body()[0]->AsMethodDefinition()->Function()->ReturnTypeAnnotation();
239 callSignatures_[0]->ReturnType()->Cast(relation, targetReturnType->TsType());
240 if (relation->IsTrue()) {
241 relation->GetChecker()->AsETSChecker()->CreateLambdaObjectForLambdaReference(
242 relation->GetNode()->AsArrowFunctionExpression(), targetType->AsETSObjectType());
243 return;
244 }
245 }
246 conversion::Forbidden(relation);
247 }
248 } // namespace panda::es2panda::checker
249