• 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 "checker/ETSchecker.h"
17 #include "checker/types/globalTypesHolder.h"
18 
19 namespace ark::es2panda::checker {
20 
ETSFunctionType(ETSChecker * checker,util::StringView name,ArenaVector<Signature * > && signatures)21 ETSFunctionType::ETSFunctionType([[maybe_unused]] ETSChecker *checker, util::StringView name,
22                                  ArenaVector<Signature *> &&signatures)
23     : Type(TypeFlag::FUNCTION | TypeFlag::ETS_METHOD),
24       callSignatures_(std::move(signatures)),
25       extensionFunctionSigs_(ArenaVector<Signature *>(checker->ProgramAllocator()->Adapter())),
26       extensionAccessorSigs_(ArenaVector<Signature *>(checker->ProgramAllocator()->Adapter())),
27       name_(name)
28 {
29     auto flag = TypeFlag::NONE;
30     for (auto *sig : callSignatures_) {
31         flag |= sig->HasSignatureFlag(SignatureFlags::GETTER) ? TypeFlag::GETTER : TypeFlag::NONE;
32         flag |= sig->HasSignatureFlag(SignatureFlags::SETTER) ? TypeFlag::SETTER : TypeFlag::NONE;
33         if (sig->IsExtensionAccessor()) {
34             extensionAccessorSigs_.emplace_back(sig);
35         } else if (sig->IsExtensionFunction()) {
36             extensionFunctionSigs_.emplace_back(sig);
37         }
38     }
39     AddTypeFlag(flag);
40 }
41 
ETSFunctionType(ETSChecker * checker,Signature * signature)42 ETSFunctionType::ETSFunctionType(ETSChecker *checker, Signature *signature)
43     : Type(TypeFlag::FUNCTION),
44       callSignatures_({{signature->ToArrowSignature(checker)}, checker->ProgramAllocator()->Adapter()}),
45       extensionFunctionSigs_(ArenaVector<Signature *>(checker->ProgramAllocator()->Adapter())),
46       extensionAccessorSigs_(ArenaVector<Signature *>(checker->ProgramAllocator()->Adapter())),
47       name_(""),
48       assemblerName_(checker->GlobalBuiltinFunctionType(signature->MinArgCount(), signature->HasRestParameter()) !=
49                              nullptr
50                          ? checker->GlobalBuiltinFunctionType(signature->MinArgCount(), signature->HasRestParameter())
51                                ->AsETSObjectType()
52                                ->AssemblerName()
53                          : "")
54 {
55 }
56 
57 // #22951: proper this type implementation
HackThisParameterInExtensionFunctionInvoke(ETSObjectType * interface,size_t arity)58 static void HackThisParameterInExtensionFunctionInvoke(ETSObjectType *interface, size_t arity)
59 {
60     auto invokeName = FunctionalInterfaceInvokeName(arity, false);
61     auto *property = interface->AsETSObjectType()->GetOwnProperty<checker::PropertyType::INSTANCE_METHOD>(
62         util::StringView(invokeName));
63     ES2PANDA_ASSERT(property != nullptr);
64     auto *tsType = property->TsType();
65     ES2PANDA_ASSERT(tsType != nullptr);
66     auto &callSigsOfInvoke0 = tsType->AsETSFunctionType()->CallSignatures();
67     for (auto sig : callSigsOfInvoke0) {
68         sig->AddSignatureFlag(SignatureFlags::THIS_RETURN_TYPE);
69     }
70 }
71 
FunctionTypeToFunctionalInterfaceType(ETSChecker * checker,Signature * signature,size_t arity)72 static ETSObjectType *FunctionTypeToFunctionalInterfaceType(ETSChecker *checker, Signature *signature, size_t arity)
73 {
74     // #22951: remove flags that affect ETSObjectType::Substitute
75     bool isExtensionHack = signature->HasSignatureFlag(SignatureFlags::EXTENSION_FUNCTION);
76 
77     if (signature->RestVar() != nullptr) {
78         auto sigParamsSize = signature->Params().size();
79         auto nPosParams = arity < sigParamsSize ? arity : sigParamsSize;
80         auto *functionN = checker->GlobalBuiltinFunctionType(nPosParams, true);
81         auto *substitution = checker->NewSubstitution();
82         ES2PANDA_ASSERT(functionN != nullptr && nPosParams <= functionN->TypeArguments().size());
83         ES2PANDA_ASSERT(substitution != nullptr);
84         for (size_t i = 0; i < nPosParams; i++) {
85             substitution->emplace(functionN->TypeArguments()[i]->AsETSTypeParameter(),
86                                   checker->MaybeBoxType(signature->Params()[i]->TsType()));
87         }
88         auto *elementType = !signature->RestVar()->TsType()->IsETSTupleType()
89                                 ? checker->GetElementTypeOfArray(signature->RestVar()->TsType())
90                                 : checker->GlobalETSAnyType();
91         substitution->emplace(functionN->TypeArguments()[0]->AsETSTypeParameter(), checker->MaybeBoxType(elementType));
92         return functionN->Substitute(checker->Relation(), substitution, true, isExtensionHack);
93     }
94 
95     ES2PANDA_ASSERT(arity >= signature->MinArgCount() && arity <= signature->ArgCount());
96 
97     // Note: FunctionN is not supported yet
98     if (arity >= checker->GetGlobalTypesHolder()->VariadicFunctionTypeThreshold()) {
99         return nullptr;
100     }
101 
102     auto *funcIface = checker->GlobalBuiltinFunctionType(arity, false);
103     auto *substitution = checker->NewSubstitution();
104 
105     ES2PANDA_ASSERT(funcIface != nullptr);
106     ES2PANDA_ASSERT(substitution != nullptr);
107     for (size_t i = 0; i < arity; i++) {
108         substitution->emplace(funcIface->TypeArguments()[i]->AsETSTypeParameter(),
109                               checker->MaybeBoxType(signature->Params()[i]->TsType()));
110     }
111     substitution->emplace(funcIface->TypeArguments()[arity]->AsETSTypeParameter(),
112                           checker->MaybeBoxType(signature->ReturnType()));
113     auto result = funcIface->Substitute(checker->Relation(), substitution, true, isExtensionHack);
114 
115     if (signature->HasSignatureFlag(SignatureFlags::THIS_RETURN_TYPE)) {
116         HackThisParameterInExtensionFunctionInvoke(result, arity);
117     }
118     return result;
119 }
120 
ArrowToFunctionalInterface(ETSChecker * checker)121 ETSObjectType *ETSFunctionType::ArrowToFunctionalInterface(ETSChecker *checker)
122 {
123     auto &cached = arrowToFuncInterface_;
124     if (LIKELY(cached != nullptr)) {
125         return cached;
126     }
127     return cached = FunctionTypeToFunctionalInterfaceType(checker, ArrowSignature(), ArrowSignature()->MinArgCount());
128 }
129 
ArrowToFunctionalInterfaceDesiredArity(ETSChecker * checker,size_t arity)130 ETSObjectType *ETSFunctionType::ArrowToFunctionalInterfaceDesiredArity(ETSChecker *checker, size_t arity)
131 {
132     if (LIKELY(arity == ArrowSignature()->MinArgCount())) {
133         return ArrowToFunctionalInterface(checker);
134     }
135     return FunctionTypeToFunctionalInterfaceType(checker, ArrowSignature(), arity);
136 }
137 
MethodToArrow(ETSChecker * checker)138 ETSFunctionType *ETSFunctionType::MethodToArrow(ETSChecker *checker)
139 {
140     auto &cached = invokeToArrowSignature_;
141     if (LIKELY(cached != nullptr)) {
142         return cached;
143     }
144 
145     ES2PANDA_ASSERT(!IsETSArrowType() && CallSignatures().size() == 1);
146     return cached = checker->CreateETSArrowType(CallSignatures()[0]);
147 }
148 
AddCallSignature(Signature * signature)149 void ETSFunctionType::AddCallSignature(Signature *signature)
150 {
151     ES2PANDA_ASSERT(!IsETSArrowType());
152 
153     if (signature->Function()->IsGetter()) {
154         AddTypeFlag(TypeFlag::GETTER);
155     } else if (signature->Function()->IsSetter()) {
156         AddTypeFlag(TypeFlag::SETTER);
157     }
158     callSignatures_.push_back(signature);
159 }
160 
ToString(std::stringstream & ss,bool precise) const161 void ETSFunctionType::ToString(std::stringstream &ss, bool precise) const
162 {
163     callSignatures_[0]->ToString(ss, nullptr, false, precise);
164 }
165 
166 // Method types do not participate in most type relations
AssertNoMethodsInFunctionRelation(Type * left,Type * right)167 static inline void AssertNoMethodsInFunctionRelation([[maybe_unused]] Type *left, [[maybe_unused]] Type *right)
168 {
169     ES2PANDA_ASSERT(!left->IsETSMethodType());
170     ES2PANDA_ASSERT(!right->IsETSMethodType());
171 }
172 
EnhanceSignatureSubstitution(TypeRelation * relation,Signature * super,Signature * sub)173 static Signature *EnhanceSignatureSubstitution(TypeRelation *relation, Signature *super, Signature *sub)
174 {
175     auto checker = relation->GetChecker()->AsETSChecker();
176     auto *substitution = checker->NewSubstitution();
177 
178     auto const enhance = [checker, sub, substitution](Type *param, Type *arg) {
179         return checker->EnhanceSubstitutionForType(sub->GetSignatureInfo()->typeParams, param, arg, substitution);
180     };
181     for (size_t ix = 0; ix < sub->ArgCount(); ix++) {
182         if (!enhance(sub->GetSignatureInfo()->params[ix]->TsType(), super->GetSignatureInfo()->params[ix]->TsType())) {
183             return nullptr;
184         }
185     }
186     if (super->RestVar() != nullptr) {
187         if (!enhance(sub->RestVar()->TsType(), super->RestVar()->TsType())) {
188             return nullptr;
189         }
190     }
191     return sub->Substitute(relation, substitution);
192 }
193 
SignatureThrowKindToOrder(Signature * sig)194 static uint8_t SignatureThrowKindToOrder(Signature *sig)
195 {
196     return sig->HasSignatureFlag(SignatureFlags::THROWS)     ? 0U
197            : sig->HasSignatureFlag(SignatureFlags::RETHROWS) ? 1U
198                                                              : 2U;
199 }
200 
SignatureIsSupertypeOf(TypeRelation * relation,Signature * super,Signature * sub)201 static bool SignatureIsSupertypeOf(TypeRelation *relation, Signature *super, Signature *sub)
202 {
203     if (super->MinArgCount() < sub->MinArgCount()) {
204         return false;
205     }
206     if ((super->RestVar() != nullptr && sub->RestVar() == nullptr) ||
207         (super->RestVar() == nullptr && sub->RestVar() != nullptr)) {
208         return false;
209     }
210     if (!sub->GetSignatureInfo()->typeParams.empty()) {
211         sub = EnhanceSignatureSubstitution(relation, super, sub);
212         if (sub == nullptr) {
213             return false;
214         }
215     }
216     for (size_t idx = 0; idx != sub->MinArgCount(); idx++) {
217         if (!relation->IsSupertypeOf(sub->Params()[idx]->TsType(), super->Params()[idx]->TsType())) {
218             return false;
219         }
220     }
221     if (super->RestVar() != nullptr && !relation->IsSupertypeOf(sub->RestVar()->TsType(), super->RestVar()->TsType())) {
222         return false;
223     }
224     if (!relation->IsSupertypeOf(super->ReturnType(), sub->ReturnType())) {
225         return false;
226     }
227     return SignatureThrowKindToOrder(super) <= SignatureThrowKindToOrder(sub);
228 }
229 
CoerceToArrowType(TypeRelation * relation,Type * type)230 static ETSFunctionType *CoerceToArrowType(TypeRelation *relation, Type *type)
231 {
232     if (type->IsETSFunctionType()) {
233         return type->AsETSFunctionType();
234     }
235     if (type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) {
236         auto checker = relation->GetChecker()->AsETSChecker();
237         return type->AsETSObjectType()->GetFunctionalInterfaceInvokeType()->MethodToArrow(checker);
238     }
239     return nullptr;
240 }
241 
Identical(TypeRelation * relation,Type * other)242 void ETSFunctionType::Identical(TypeRelation *relation, Type *other)
243 {
244     AssertNoMethodsInFunctionRelation(this, other);
245 
246     ETSFunctionType *const otherFnType = CoerceToArrowType(relation, other);
247     if (otherFnType == nullptr) {
248         relation->Result(false);
249         return;
250     }
251 
252     relation->Result(SignatureIsSupertypeOf(relation, this->ArrowSignature(), otherFnType->ArrowSignature()) &&
253                      SignatureIsSupertypeOf(relation, otherFnType->ArrowSignature(), this->ArrowSignature()));
254 }
255 
AssignmentSource(TypeRelation * relation,Type * target)256 bool ETSFunctionType::AssignmentSource(TypeRelation *relation, Type *target)
257 {
258     AssertNoMethodsInFunctionRelation(this, target);
259 
260     // this should be defined by the dynamic type itself
261     if (target->IsETSDynamicType()) {
262         ES2PANDA_ASSERT(relation->GetNode() != nullptr);
263         if (relation->GetNode()->IsArrowFunctionExpression()) {
264             ES2PANDA_ASSERT(callSignatures_.size() == 1 && ArrowSignature()->HasSignatureFlag(SignatureFlags::CALL));
265             return relation->Result(true);
266         }
267         return relation->Result(false);
268     }
269 
270     return relation->IsSupertypeOf(target, this);
271 }
272 
IsSupertypeOf(TypeRelation * relation,Type * source)273 void ETSFunctionType::IsSupertypeOf(TypeRelation *relation, Type *source)
274 {
275     AssertNoMethodsInFunctionRelation(this, source);
276 
277     ETSFunctionType *const sourceFnType = CoerceToArrowType(relation, source);
278     if (sourceFnType == nullptr) {
279         relation->Result(false);
280         return;
281     }
282 
283     relation->Result(SignatureIsSupertypeOf(relation, this->ArrowSignature(), sourceFnType->ArrowSignature()));
284 }
285 
AssignmentTarget(TypeRelation * relation,Type * source)286 void ETSFunctionType::AssignmentTarget(TypeRelation *relation, Type *source)
287 {
288     AssertNoMethodsInFunctionRelation(this, source);
289 
290     relation->IsSupertypeOf(this, source);
291 }
292 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)293 Type *ETSFunctionType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
294 {
295     auto checker = relation->GetChecker()->AsETSChecker();
296     if (IsETSArrowType()) {
297         return allocator->New<ETSFunctionType>(checker, ArrowSignature());
298     }
299 
300     auto signatures = ArenaVector<Signature *>(allocator->Adapter());
301     for (auto *const signature : callSignatures_) {
302         signatures.emplace_back(signature->Copy(allocator, relation, globalTypes));
303     }
304     return allocator->New<ETSFunctionType>(checker, name_, std::move(signatures));
305 }
306 
Substitute(TypeRelation * relation,const Substitution * substitution)307 ETSFunctionType *ETSFunctionType::Substitute(TypeRelation *relation, const Substitution *substitution)
308 {
309     if (substitution != nullptr && !substitution->empty()) {
310         auto *const checker = relation->GetChecker()->AsETSChecker();
311         auto *const allocator = checker->ProgramAllocator();
312 
313         auto signatures = ArenaVector<Signature *>(allocator->Adapter());
314         bool anyChange = false;
315 
316         for (auto *const signature : callSignatures_) {
317             auto *newSignature = signature->Substitute(relation, substitution);
318             anyChange |= newSignature != signature;
319             signatures.emplace_back(newSignature);
320         }
321 
322         if (anyChange) {
323             if (IsETSArrowType()) {
324                 return allocator->New<ETSFunctionType>(checker, signatures[0]);
325             }
326             return allocator->New<ETSFunctionType>(checker, name_, std::move(signatures));
327         }
328     }
329 
330     return this;
331 }
332 
Cast(TypeRelation * relation,Type * target)333 void ETSFunctionType::Cast(TypeRelation *relation, Type *target)
334 {
335     AssertNoMethodsInFunctionRelation(this, target);
336 
337     if (target->IsETSObjectType() && target->AsETSObjectType()->IsGlobalETSObjectType()) {
338         relation->Result(true);
339         return;
340     }
341 }
342 
CastTarget(TypeRelation * relation,Type * source)343 void ETSFunctionType::CastTarget(TypeRelation *relation, Type *source)
344 {
345     AssertNoMethodsInFunctionRelation(this, source);
346 
347     if (relation->IsSupertypeOf(this, source)) {
348         relation->RemoveFlags(TypeRelationFlag::UNCHECKED_CAST);
349         return;
350     }
351     if (relation->InCastingContext() && relation->IsSupertypeOf(source, this)) {
352         relation->RemoveFlags(TypeRelationFlag::UNCHECKED_CAST);
353         return;
354     }
355     relation->Result(false);
356 }
357 
IsSubtypeOf(TypeRelation * relation,Type * target)358 void ETSFunctionType::IsSubtypeOf(TypeRelation *relation, Type *target)
359 {
360     AssertNoMethodsInFunctionRelation(this, target);
361 
362     ETSChecker *checker = relation->GetChecker()->AsETSChecker();
363 
364     // fastpath
365     if (relation->IsSupertypeOf(target, checker->GlobalBuiltinFunctionType())) {
366         relation->Result(true);
367         return;
368     }
369 
370     // fastpath, as IsSupertypeOf has already failed
371     if (target->IsETSFunctionType()) {
372         return;
373     }
374 
375     relation->IsSupertypeOf(target, ArrowToFunctionalInterface(checker));
376 }
377 
ToAssemblerType(std::stringstream & ss) const378 void ETSFunctionType::ToAssemblerType([[maybe_unused]] std::stringstream &ss) const
379 {
380     ss << assemblerName_;
381 }
382 
383 // #22952: some function types are still in AST
FunctionAssemblyTypeFromArity(uint32_t arity)384 static std::string FunctionAssemblyTypeFromArity(uint32_t arity)
385 {
386     return "std.core.Function" + std::to_string(arity);
387 }
388 
ToDebugInfoType(std::stringstream & ss) const389 void ETSFunctionType::ToDebugInfoType([[maybe_unused]] std::stringstream &ss) const
390 {
391     ES2PANDA_ASSERT(IsETSArrowType());
392     ss << FunctionAssemblyTypeFromArity(ArrowSignature()->MinArgCount());
393 }
394 
CheckVarianceRecursively(TypeRelation * relation,VarianceFlag varianceFlag)395 void ETSFunctionType::CheckVarianceRecursively(TypeRelation *relation, VarianceFlag varianceFlag)
396 {
397     // For function, param is `in` and returntype is `out`,(in)=>out
398     for (auto *sig : callSignatures_) {
399         if (sig->HasFunction() && sig->Function()->ReturnTypeAnnotation() != nullptr) {
400             relation->SetNode(sig->Function()->ReturnTypeAnnotation());
401         }
402         relation->CheckVarianceRecursively(sig->ReturnType(),
403                                            relation->TransferVariant(varianceFlag, VarianceFlag::COVARIANT));
404 
405         if (sig->HasRestParameter()) {
406             if (sig->HasFunction()) {
407                 relation->SetNode(sig->Function()->Params().at(sig->Params().size()));
408             }
409             relation->CheckVarianceRecursively(sig->RestVar()->TsType(),
410                                                relation->TransferVariant(varianceFlag, VarianceFlag::COVARIANT));
411         }
412         for (auto *typeParam : sig->Params()) {
413             relation->SetNode(
414                 typeParam->Declaration()->AsParameterDecl()->Node()->AsETSParameterExpression()->TypeAnnotation());
415             relation->CheckVarianceRecursively(typeParam->TsType(),
416                                                relation->TransferVariant(varianceFlag, VarianceFlag::CONTRAVARIANT));
417         }
418     }
419 }
420 
421 }  // namespace ark::es2panda::checker
422