• 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 "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 &parameters =
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