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 "signature.h"
17
18 #include "typeFlag.h"
19 #include "varbinder/scope.h"
20 #include "ir/base/scriptFunction.h"
21 #include "ir/ts/tsTypeParameter.h"
22 #include "checker/ETSchecker.h"
23 #include "public/public.h"
24
25 namespace ark::es2panda::checker {
26
InternalName() const27 util::StringView Signature::InternalName() const
28 {
29 return internalName_.Empty() ? func_->Scope()->InternalName() : internalName_;
30 }
31
Substitute(TypeRelation * relation,const Substitution * substitution)32 Signature *Signature::Substitute(TypeRelation *relation, const Substitution *substitution)
33 {
34 if (substitution == nullptr || substitution->empty()) {
35 return this;
36 }
37 auto *checker = relation->GetChecker()->AsETSChecker();
38 auto *allocator = checker->Allocator();
39 bool anyChange = false;
40 SignatureInfo *newSigInfo = allocator->New<SignatureInfo>(allocator);
41
42 if (!signatureInfo_->typeParams.empty()) {
43 for (auto *tparam : signatureInfo_->typeParams) {
44 auto *newTparam = tparam->Substitute(relation, substitution);
45 newSigInfo->typeParams.push_back(newTparam);
46 anyChange |= (newTparam != tparam);
47 }
48 }
49 newSigInfo->minArgCount = signatureInfo_->minArgCount;
50
51 for (auto *param : signatureInfo_->params) {
52 auto *newParam = param;
53 auto *newParamType = param->TsType()->Substitute(relation, substitution);
54 if (newParamType != param->TsType()) {
55 anyChange = true;
56 newParam = param->Copy(allocator, param->Declaration());
57 newParam->SetTsType(newParamType);
58 }
59 newSigInfo->params.push_back(newParam);
60 }
61
62 if (signatureInfo_->restVar != nullptr) {
63 auto *newRestType = signatureInfo_->restVar->TsType()->Substitute(relation, substitution);
64 if (newRestType != signatureInfo_->restVar->TsType()) {
65 anyChange = true;
66 newSigInfo->restVar = signatureInfo_->restVar->Copy(allocator, signatureInfo_->restVar->Declaration());
67 newSigInfo->restVar->SetTsType(newRestType);
68 }
69 }
70
71 if (!anyChange) {
72 newSigInfo = signatureInfo_;
73 }
74
75 auto *newReturnType = returnType_->Substitute(relation, substitution);
76 if (newReturnType == returnType_ && !anyChange) {
77 return this;
78 }
79
80 auto *result = allocator->New<Signature>(newSigInfo, newReturnType);
81 result->func_ = func_;
82 result->flags_ = flags_;
83 result->internalName_ = internalName_;
84 result->ownerObj_ = ownerObj_;
85 result->ownerVar_ = ownerVar_;
86
87 return result;
88 }
89
ToAssemblerType(std::stringstream & ss) const90 void Signature::ToAssemblerType(std::stringstream &ss) const
91 {
92 ss << compiler::Signatures::MANGLE_BEGIN;
93
94 for (const auto *param : signatureInfo_->params) {
95 param->TsType()->ToAssemblerTypeWithRank(ss);
96 ss << compiler::Signatures::MANGLE_SEPARATOR;
97 }
98
99 if (signatureInfo_->restVar != nullptr) {
100 signatureInfo_->restVar->TsType()->ToAssemblerTypeWithRank(ss);
101 ss << compiler::Signatures::MANGLE_SEPARATOR;
102 }
103
104 returnType_->ToAssemblerTypeWithRank(ss);
105 ss << compiler::Signatures::MANGLE_SEPARATOR;
106 }
107
Copy(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)108 Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
109 {
110 SignatureInfo *copiedInfo = allocator->New<SignatureInfo>(signatureInfo_, allocator);
111
112 for (size_t idx = 0; idx < signatureInfo_->params.size(); idx++) {
113 auto *const paramType = signatureInfo_->params[idx]->TsType();
114 if (paramType->HasTypeFlag(TypeFlag::GENERIC) && paramType->IsETSObjectType()) {
115 copiedInfo->params[idx]->SetTsType(paramType->Instantiate(allocator, relation, globalTypes));
116 auto originalTypeArgs = paramType->AsETSObjectType()->GetOriginalBaseType()->TypeArguments();
117 copiedInfo->params[idx]->TsType()->AsETSObjectType()->SetTypeArguments(std::move(originalTypeArgs));
118 } else {
119 copiedInfo->params[idx]->SetTsType(
120 ETSChecker::TryToInstantiate(paramType, allocator, relation, globalTypes));
121 }
122 }
123
124 auto *const copiedSignature = allocator->New<Signature>(copiedInfo, returnType_, func_);
125 copiedSignature->flags_ = flags_;
126 copiedSignature->internalName_ = internalName_;
127 copiedSignature->ownerObj_ = ownerObj_;
128 copiedSignature->ownerVar_ = ownerVar_;
129
130 return copiedSignature;
131 }
132
ToString(std::stringstream & ss,const varbinder::Variable * variable,bool printAsMethod,bool precise) const133 void Signature::ToString(std::stringstream &ss, const varbinder::Variable *variable, bool printAsMethod,
134 bool precise) const
135 {
136 if (!signatureInfo_->typeParams.empty()) {
137 ss << "<";
138 for (auto it = signatureInfo_->typeParams.begin(); it != signatureInfo_->typeParams.end(); ++it) {
139 (*it)->ToString(ss, precise);
140 if (std::next(it) != signatureInfo_->typeParams.end()) {
141 ss << ", ";
142 }
143 }
144 ss << ">";
145 }
146
147 ss << "(";
148
149 for (auto it = signatureInfo_->params.begin(); it != signatureInfo_->params.end(); it++) {
150 ss << (*it)->Name();
151
152 if ((*it)->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
153 ss << "?";
154 }
155
156 ss << ": ";
157
158 (*it)->TsType()->ToString(ss, precise);
159
160 if (std::next(it) != signatureInfo_->params.end()) {
161 ss << ", ";
162 }
163 }
164
165 if (signatureInfo_->restVar != nullptr) {
166 if (!signatureInfo_->params.empty()) {
167 ss << ", ";
168 }
169
170 ss << "...";
171 ss << signatureInfo_->restVar->Name();
172 ss << ": ";
173 signatureInfo_->restVar->TsType()->ToString(ss, precise);
174 }
175
176 ss << ")";
177
178 if (printAsMethod || (variable != nullptr && variable->HasFlag(varbinder::VariableFlags::METHOD))) {
179 ss << ": ";
180 } else {
181 ss << " => ";
182 }
183
184 returnType_->ToString(ss, precise);
185 }
186
ToString() const187 std::string Signature::ToString() const
188 {
189 std::stringstream ss;
190 ToString(ss, nullptr);
191 return ss.str();
192 }
193
194 namespace {
GetToCheckParamCount(Signature * signature,bool isEts)195 std::size_t GetToCheckParamCount(Signature *signature, bool isEts)
196 {
197 auto paramNumber = static_cast<ssize_t>(signature->Params().size());
198 if (!isEts || signature->Function() == nullptr) {
199 return paramNumber;
200 }
201 for (auto i = paramNumber - 1; i >= 0; i--) {
202 if (!signature->Function()->Params()[i]->AsETSParameterExpression()->IsDefault()) {
203 return static_cast<std::size_t>(i + 1);
204 }
205 }
206 return 0;
207 }
208 } // namespace
209
CheckParameter(TypeRelation * relation,Type * type1,Type * type2)210 bool Signature::CheckParameter(TypeRelation *relation, Type *type1, Type *type2)
211 {
212 relation->IsIdenticalTo(type1, type2);
213 if (relation->IsOverridingCheck() && !relation->IsTrue()) {
214 relation->IsSupertypeOf(type1, type2);
215 }
216 return relation->IsTrue();
217 }
218
CheckReturnType(TypeRelation * relation,Type * type1,Type * type2)219 bool Signature::CheckReturnType(TypeRelation *relation, Type *type1, Type *type2)
220 {
221 if (relation->NoReturnTypeCheck()) {
222 return relation->Result(true);
223 }
224 if (relation->IsOverridingCheck()) {
225 relation->IsSupertypeOf(type2, type1);
226 } else {
227 relation->IsIdenticalTo(type1, type2);
228 }
229
230 return relation->IsTrue();
231 }
232
Compatible(TypeRelation * relation,Signature * other)233 void Signature::Compatible(TypeRelation *relation, Signature *other)
234 {
235 relation->Result(false);
236 bool isEts = relation->GetChecker()->IsETSChecker();
237 auto const thisToCheckParametersNumber = GetToCheckParamCount(this, isEts);
238 auto const otherToCheckParametersNumber = GetToCheckParamCount(other, isEts);
239 if ((thisToCheckParametersNumber != otherToCheckParametersNumber || this->MinArgCount() != other->MinArgCount()) &&
240 this->RestVar() == nullptr && other->RestVar() == nullptr) {
241 // skip check for ets cases only when all parameters are mandatory
242 if (!isEts || (thisToCheckParametersNumber == this->Params().size() &&
243 otherToCheckParametersNumber == other->Params().size())) {
244 return;
245 }
246 }
247
248 if (HasSignatureFlag(SignatureFlags::GETTER_OR_SETTER) !=
249 other->HasSignatureFlag(SignatureFlags::GETTER_OR_SETTER) ||
250 !CheckReturnType(relation, this->ReturnType(), other->ReturnType())) {
251 return;
252 }
253
254 /* In ETS, the functions "foo(a: int)" and "foo(a: int, b: int = 1)" should be considered as having an
255 equivalent signature. Hence, we only need to check if the mandatory parameters of the signature with
256 more mandatory parameters can match the parameters of the other signature (including the optional
257 parameter or rest parameters) here.
258
259 XXXToCheckParametersNumber is calculated beforehand by counting mandatory parameters.
260 Signature::params() stores all parameters (mandatory and optional), excluding the rest parameter.
261 Signature::restVar() stores the rest parameters of the function.
262
263 For example:
264 foo(a: int): params().size: 1, ToCheckParametersNumber: 1, restVar: nullptr
265 foo(a: int, b: int = 0): params().size: 2, ToCheckParametersNumber: 1, restVar: nullptr
266 foo(a: int, ...b: int[]): params().size: 1, ToCheckParametersNumber: 1, restVar: ...b: int[]
267
268 Note that optional parameters always come after mandatory parameters, and signatures containing both
269 optional and rest parameters are not allowed.
270
271 "ToCheckParametersNumber" is the number of parameters that need to be checked to ensure identical.
272 "parametersNumber" is the number of parameters that can be checked in Signature::params().
273 */
274 relation->Result(true);
275 auto const toCheckParametersNumber = std::max(thisToCheckParametersNumber, otherToCheckParametersNumber);
276 auto const parametersNumber = std::min({this->Params().size(), other->Params().size(), toCheckParametersNumber});
277
278 std::size_t i = 0U;
279 for (; i < parametersNumber; ++i) {
280 if (!CheckParameter(relation, this->Params()[i]->TsType(), other->Params()[i]->TsType())) {
281 return;
282 }
283 }
284
285 /* "i" could be one of the following three cases:
286 1. == toCheckParametersNumber, we have finished the checking and can directly return.
287 2. == other->Params().size(), must be < thisToCheckParametersNumber in this case since
288 xxx->Params().size() always >= xxxtoCheckParametersNumber. We need to check the remaining
289 mandatory parameters of "this" against ths RestVar of "other".
290 3. == this->Params().size(), must be < otherToCheckParametersNumber as described in 2, and
291 we need to check the remaining mandatory parameters of "other" against the RestVar of "this".
292 */
293 if (other->RestVar() != nullptr && this->RestVar() != nullptr) {
294 relation->IsIdenticalTo(this->RestVar()->TsType(), other->RestVar()->TsType());
295 }
296
297 if (i == toCheckParametersNumber) {
298 return;
299 }
300 bool isOtherMandatoryParamsMatched = i < thisToCheckParametersNumber;
301 ArenaVector<varbinder::LocalVariable *> const ¶meters =
302 isOtherMandatoryParamsMatched ? this->Params() : other->Params();
303 varbinder::LocalVariable const *restParameter = isOtherMandatoryParamsMatched ? other->RestVar() : this->RestVar();
304 if (restParameter == nullptr) {
305 relation->Result(false);
306 return;
307 }
308 auto *const restParameterType = restParameter->TsType()->AsETSArrayType()->ElementType();
309 for (; i < toCheckParametersNumber; ++i) {
310 if (!CheckParameter(relation, parameters[i]->TsType(), restParameterType)) {
311 return;
312 }
313 }
314 }
315
CheckFunctionalInterfaces(TypeRelation * relation,Type * source,Type * target)316 bool Signature::CheckFunctionalInterfaces(TypeRelation *relation, Type *source, Type *target)
317 {
318 if (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
319 return false;
320 }
321
322 if (!target->IsETSObjectType() || !target->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
323 return false;
324 }
325
326 auto sourceInvokeFunc = source->AsETSObjectType()
327 ->GetProperty(util::StringView("invoke"), PropertySearchFlags::SEARCH_INSTANCE_METHOD)
328 ->TsType()
329 ->AsETSFunctionType()
330 ->CallSignatures()[0];
331
332 auto targetInvokeFunc = target->AsETSObjectType()
333 ->GetProperty(util::StringView("invoke"), PropertySearchFlags::SEARCH_INSTANCE_METHOD)
334 ->TsType()
335 ->AsETSFunctionType()
336 ->CallSignatures()[0];
337
338 relation->IsCompatibleTo(sourceInvokeFunc, targetInvokeFunc);
339 return true;
340 }
341
AssignmentTarget(TypeRelation * relation,Signature * source)342 void Signature::AssignmentTarget(TypeRelation *relation, Signature *source)
343 {
344 if (signatureInfo_->restVar == nullptr &&
345 (source->Params().size() - source->OptionalArgCount()) > signatureInfo_->params.size()) {
346 relation->Result(false);
347 return;
348 }
349
350 for (size_t i = 0; i < source->Params().size(); i++) {
351 if (signatureInfo_->restVar == nullptr && i >= Params().size()) {
352 break;
353 }
354
355 if (signatureInfo_->restVar != nullptr) {
356 relation->IsAssignableTo(source->Params()[i]->TsType(), signatureInfo_->restVar->TsType());
357
358 if (!relation->IsTrue()) {
359 return;
360 }
361
362 continue;
363 }
364
365 relation->IsAssignableTo(source->Params()[i]->TsType(), Params()[i]->TsType());
366
367 if (!relation->IsTrue()) {
368 return;
369 }
370 }
371
372 relation->IsAssignableTo(source->ReturnType(), returnType_);
373
374 if (relation->IsTrue() && signatureInfo_->restVar != nullptr && source->RestVar() != nullptr) {
375 relation->IsAssignableTo(source->RestVar()->TsType(), signatureInfo_->restVar->TsType());
376 }
377 }
378
BoxPrimitives(ETSChecker * checker)379 Signature *Signature::BoxPrimitives(ETSChecker *checker)
380 {
381 auto *allocator = checker->Allocator();
382 auto *sigInfo = allocator->New<SignatureInfo>(signatureInfo_, allocator);
383 for (auto param : sigInfo->params) {
384 if (param->TsType()->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
385 param->SetTsType(checker->PrimitiveTypeAsETSBuiltinType(param->TsType()));
386 }
387 }
388 auto *retType = returnType_->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)
389 ? checker->PrimitiveTypeAsETSBuiltinType(returnType_)
390 : returnType_;
391
392 auto *resultSig = allocator->New<Signature>(sigInfo, retType, func_);
393 resultSig->flags_ = flags_;
394 resultSig->SetOwner(Owner());
395 resultSig->SetOwnerVar(OwnerVar());
396 return resultSig;
397 }
398 } // namespace ark::es2panda::checker
399