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