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