• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #include "ets/etsObjectType.h"
20 #include "compiler/lowering/util.h"
21 
22 namespace ark::es2panda::checker {
23 
InternalName() const24 util::StringView Signature::InternalName() const
25 {
26     return internalName_.Empty() && func_ != nullptr ? func_->Scope()->InternalName() : internalName_;
27 }
28 
Substitute(TypeRelation * relation,const Substitution * substitution)29 Signature *Signature::Substitute(TypeRelation *relation, const Substitution *substitution)
30 {
31     if (substitution == nullptr || substitution->empty()) {
32         return this;
33     }
34     auto *checker = relation->GetChecker()->AsETSChecker();
35     auto *allocator = checker->ProgramAllocator();
36     bool anyChange = false;
37     SignatureInfo *newSigInfo = allocator->New<SignatureInfo>(allocator);
38     ES2PANDA_ASSERT(newSigInfo != nullptr);
39     if (!signatureInfo_->typeParams.empty()) {
40         for (auto *tparam : signatureInfo_->typeParams) {
41             auto *newTparam = tparam->Substitute(relation, substitution);
42             newSigInfo->typeParams.push_back(newTparam);
43             anyChange |= (newTparam != tparam);
44         }
45     }
46     newSigInfo->minArgCount = signatureInfo_->minArgCount;
47 
48     for (auto *param : signatureInfo_->params) {
49         auto *newParam = param;
50         auto *newParamType = param->TsType()->Substitute(relation, substitution);
51         if (newParamType != param->TsType()) {
52             anyChange = true;
53             newParam = param->Copy(allocator, param->Declaration());
54             if (newParamType->IsETSVoidType()) {
55                 // since `void` is not allowed to be used as param type
56                 newParamType = checker->GlobalETSUndefinedType();
57             }
58             newParam->SetTsType(newParamType);
59         }
60         newSigInfo->params.push_back(newParam);
61     }
62 
63     if (signatureInfo_->restVar != nullptr) {
64         auto *newRestVar = signatureInfo_->restVar;
65         auto *newRestType = signatureInfo_->restVar->TsType()->Substitute(relation, substitution);
66         if (newRestType != signatureInfo_->restVar->TsType()) {
67             anyChange = true;
68             newRestVar = signatureInfo_->restVar->Copy(allocator, signatureInfo_->restVar->Declaration());
69             newRestVar->SetTsType(newRestType);
70         }
71         newSigInfo->restVar = newRestVar;
72     }
73 
74     if (!anyChange) {
75         newSigInfo = signatureInfo_;
76     }
77 
78     auto *newReturnType = returnType_->Substitute(relation, substitution);
79     if (newReturnType == returnType_ && !anyChange) {
80         return this;
81     }
82 
83     return CreateSignatureForSubstitute(allocator, newSigInfo, newReturnType);
84 }
85 
CreateSignatureForSubstitute(ArenaAllocator * allocator,SignatureInfo * sigInfo,Type * returnType)86 Signature *Signature::CreateSignatureForSubstitute(ArenaAllocator *allocator, SignatureInfo *sigInfo, Type *returnType)
87 {
88     auto *result = allocator->New<Signature>(sigInfo, returnType, func_);
89     ES2PANDA_ASSERT(result != nullptr);
90     result->flags_ = flags_;
91     result->internalName_ = internalName_;
92     result->ownerObj_ = ownerObj_;
93     result->ownerVar_ = ownerVar_;
94     return result;
95 }
96 
ToAssemblerType(std::stringstream & ss) const97 void Signature::ToAssemblerType(std::stringstream &ss) const
98 {
99     ss << compiler::Signatures::MANGLE_BEGIN;
100 
101     for (const auto *param : signatureInfo_->params) {
102         param->TsType()->ToAssemblerTypeWithRank(ss);
103         ss << compiler::Signatures::MANGLE_SEPARATOR;
104     }
105 
106     if (signatureInfo_->restVar != nullptr) {
107         signatureInfo_->restVar->TsType()->ToAssemblerTypeWithRank(ss);
108         ss << compiler::Signatures::MANGLE_SEPARATOR;
109     }
110 
111     returnType_->ToAssemblerTypeWithRank(ss);
112     ss << compiler::Signatures::MANGLE_SEPARATOR;
113 }
114 
Copy(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)115 Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
116 {
117     SignatureInfo *copiedInfo = allocator->New<SignatureInfo>(signatureInfo_, allocator);
118     ES2PANDA_ASSERT(copiedInfo != nullptr);
119     for (size_t idx = 0U; idx < signatureInfo_->params.size(); ++idx) {
120         auto *const paramType = signatureInfo_->params[idx]->TsType();
121         if (paramType->HasTypeFlag(TypeFlag::GENERIC) && paramType->IsETSObjectType()) {
122             copiedInfo->params[idx]->SetTsType(paramType->Instantiate(allocator, relation, globalTypes));
123             auto originalTypeArgs = paramType->AsETSObjectType()->GetOriginalBaseType()->TypeArguments();
124             copiedInfo->params[idx]->TsType()->AsETSObjectType()->SetTypeArguments(std::move(originalTypeArgs));
125         } else {
126             copiedInfo->params[idx]->SetTsType(
127                 ETSChecker::TryToInstantiate(paramType, allocator, relation, globalTypes));
128         }
129     }
130 
131     auto *const copiedSignature = allocator->New<Signature>(copiedInfo, returnType_, func_);
132     ES2PANDA_ASSERT(copiedSignature != nullptr);
133     copiedSignature->flags_ = flags_;
134     copiedSignature->internalName_ = internalName_;
135     copiedSignature->ownerObj_ = ownerObj_;
136     copiedSignature->ownerVar_ = ownerVar_;
137 
138     return copiedSignature;
139 }
140 
ToString(std::stringstream & ss,const varbinder::Variable * variable,bool printAsMethod,bool precise) const141 void Signature::ToString(std::stringstream &ss, const varbinder::Variable *variable, bool printAsMethod,
142                          bool precise) const
143 {
144     if (!signatureInfo_->typeParams.empty()) {
145         ss << "<";
146         for (auto it = signatureInfo_->typeParams.begin(); it != signatureInfo_->typeParams.end(); ++it) {
147             (*it)->ToString(ss, precise);
148             if (std::next(it) != signatureInfo_->typeParams.end()) {
149                 ss << ", ";
150             }
151         }
152         ss << ">";
153     }
154 
155     ss << "(";
156 
157     for (auto it = signatureInfo_->params.begin(); it != signatureInfo_->params.end(); it++) {
158         ss << (!(*it)->Name().StartsWith(compiler::GENSYM_CORE) ? (*it)->Name().Utf8() : compiler::DUMMY_ID);
159 
160         if ((*it)->HasFlag(varbinder::VariableFlags::OPTIONAL)) {
161             ss << "?";
162         }
163 
164         ss << ": ";
165 
166         (*it)->TsType()->ToString(ss, precise);
167 
168         if (std::next(it) != signatureInfo_->params.end()) {
169             ss << ", ";
170         }
171     }
172 
173     if (signatureInfo_->restVar != nullptr) {
174         if (!signatureInfo_->params.empty()) {
175             ss << ", ";
176         }
177 
178         ss << "...";
179         ss << (!signatureInfo_->restVar->Name().StartsWith(compiler::GENSYM_CORE)
180                    ? signatureInfo_->restVar->Name().Utf8()
181                    : compiler::DUMMY_ID);
182         ss << ": ";
183         signatureInfo_->restVar->TsType()->ToString(ss, precise);
184     }
185 
186     ss << ")";
187 
188     if (printAsMethod || (variable != nullptr && variable->HasFlag(varbinder::VariableFlags::METHOD))) {
189         ss << ": ";
190     } else {
191         ss << " => ";
192     }
193 
194     returnType_->ToString(ss, precise);
195 
196     if (HasSignatureFlag(SignatureFlags::THROWS)) {
197         ss << " throws";
198     } else if (HasSignatureFlag(SignatureFlags::RETHROWS)) {
199         ss << " rethrows";
200     }
201 }
202 
ToString() const203 std::string Signature::ToString() const
204 {
205     std::stringstream ss;
206     ToString(ss, nullptr);
207     return ss.str();
208 }
209 
210 // this function intentionally ignores relation->Result
MethodSignaturesAreCompatible(TypeRelation * relation,bool checkIdentical,Signature * const super,Signature * const sub)211 static bool MethodSignaturesAreCompatible(TypeRelation *relation, bool checkIdentical, Signature *const super,
212                                           Signature *const sub)
213 {
214     ES2PANDA_ASSERT(!sub->HasRestParameter() || (sub->ArgCount() == sub->MinArgCount()));
215     ES2PANDA_ASSERT(!super->HasRestParameter() || (super->ArgCount() == super->MinArgCount()));
216 
217     if (sub->ArgCount() != super->ArgCount()) {
218         return false;
219     }
220 
221     if (sub->HasRestParameter() != super->HasRestParameter()) {
222         return false;
223     }
224 
225     auto const areCompatible = [relation, checkIdentical](Type *superT, Type *subT) {
226         return checkIdentical ? relation->IsIdenticalTo(superT, subT) : relation->IsSupertypeOf(superT, subT);
227     };
228     if (!relation->NoReturnTypeCheck() && !areCompatible(super->ReturnType(), sub->ReturnType())) {
229         return false;
230     }
231     for (size_t idx = 0; idx < sub->ArgCount(); ++idx) {
232         if (!areCompatible(sub->Params()[idx]->TsType(), super->Params()[idx]->TsType())) {
233             return false;
234         }
235     }
236     return !sub->HasRestParameter() || relation->IsIdenticalTo(sub->RestVar()->TsType(), super->RestVar()->TsType());
237 }
238 
IsSubtypeOf(TypeRelation * relation,Signature * super)239 void Signature::IsSubtypeOf(TypeRelation *relation, Signature *super)
240 {
241     auto sub = this;
242     if (sub->HasSignatureFlag(SignatureFlags::GETTER_OR_SETTER) !=
243         super->HasSignatureFlag(SignatureFlags::GETTER_OR_SETTER)) {
244         relation->Result(false);
245         return;
246     }
247 
248     if (!relation->GetChecker()->IsETSChecker() && sub->MinArgCount() != super->MinArgCount() &&
249         sub->RestVar() == nullptr && super->RestVar() == nullptr) {
250         relation->Result(false);
251         return;
252     }
253 
254     relation->Result(MethodSignaturesAreCompatible(relation, !relation->IsOverridingCheck(), super, sub));
255 }
256 
257 // This function is not used by ets extension
AssignmentTarget(TypeRelation * relation,Signature * source)258 void Signature::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Signature *source)
259 {
260     if (signatureInfo_->restVar == nullptr && source->MinArgCount() > signatureInfo_->params.size()) {
261         relation->Result(false);
262         return;
263     }
264 
265     for (size_t i = 0; i < source->Params().size(); i++) {
266         if (signatureInfo_->restVar == nullptr && i >= Params().size()) {
267             break;
268         }
269 
270         if (signatureInfo_->restVar != nullptr) {
271             relation->IsAssignableTo(source->Params()[i]->TsType(), signatureInfo_->restVar->TsType());
272 
273             if (!relation->IsTrue()) {
274                 return;
275             }
276 
277             continue;
278         }
279 
280         relation->IsAssignableTo(source->Params()[i]->TsType(), Params()[i]->TsType());
281 
282         if (!relation->IsTrue()) {
283             return;
284         }
285     }
286 
287     relation->IsAssignableTo(source->ReturnType(), returnType_);
288 
289     if (relation->IsTrue() && signatureInfo_->restVar != nullptr && source->RestVar() != nullptr) {
290         relation->IsAssignableTo(source->RestVar()->TsType(), signatureInfo_->restVar->TsType());
291     }
292 }
293 
ToArrowSignature(ETSChecker * checker)294 Signature *Signature::ToArrowSignature(ETSChecker *checker)
295 {
296     auto *allocator = checker->ProgramAllocator();
297     auto *sigInfo = allocator->New<SignatureInfo>(signatureInfo_, allocator);
298     ES2PANDA_ASSERT(sigInfo != nullptr);
299     for (auto param : sigInfo->params) {
300         param->SetTsType(checker->MaybeBoxType(param->TsType()));
301     }
302     auto *retType = checker->MaybeBoxType(returnType_);
303 
304     auto *resultSig = allocator->New<Signature>(sigInfo, retType);
305     ES2PANDA_ASSERT(resultSig != nullptr);
306     resultSig->flags_ = flags_;
307     resultSig->SetOwner(Owner());
308     resultSig->SetOwnerVar(OwnerVar());
309     ES2PANDA_ASSERT(!resultSig->HasFunction());
310     return resultSig;
311 }
312 
313 }  // namespace ark::es2panda::checker
314