• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 - 2023 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 "etsFunctionType.h"
17 #include "checker/types/typeRelation.h"
18 #include "checker/ETSchecker.h"
19 #include "checker/ets/conversion.h"
20 #include "ir/base/scriptFunction.h"
21 #include "ir/expressions/identifier.h"
22 
23 namespace panda::es2panda::checker {
24 
FirstAbstractSignature()25 Signature *ETSFunctionType::FirstAbstractSignature()
26 {
27     for (auto *it : callSignatures_) {
28         if (it->HasSignatureFlag(SignatureFlags::ABSTRACT)) {
29             return it;
30         }
31     }
32 
33     return nullptr;
34 }
35 
ToString(std::stringstream & ss) const36 void ETSFunctionType::ToString(std::stringstream &ss) const
37 {
38     callSignatures_[0]->ToString(ss, nullptr);
39 }
40 
Identical(TypeRelation * relation,Type * other)41 void ETSFunctionType::Identical(TypeRelation *relation, Type *other)
42 {
43     if (!other->IsETSFunctionType()) {
44         return;
45     }
46 
47     if (callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE)) {
48         AssignmentTarget(relation, other);
49         return;
50     }
51 
52     callSignatures_[0]->Identical(relation, other->AsETSFunctionType()->CallSignatures()[0]);
53 }
54 
AssignmentSource(TypeRelation * relation,Type * target)55 bool ETSFunctionType::AssignmentSource(TypeRelation *relation, Type *target)
56 {
57     if (target->IsETSDynamicType()) {
58         ASSERT(relation->GetNode() != nullptr);
59         if (relation->GetNode()->IsArrowFunctionExpression()) {
60             ASSERT(callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::CALL));
61             relation->GetChecker()->AsETSChecker()->CreateLambdaObjectForLambdaReference(
62                 relation->GetNode()->AsArrowFunctionExpression(), callSignatures_[0]->Owner());
63             relation->Result(true);
64             return true;
65         }
66         relation->Result(false);
67         return false;
68     }
69 
70     relation->Result(false);
71     return false;
72 }
73 
ProcessSignatures(TypeRelation * relation,Signature * target,ETSFunctionType * sourceFuncType)74 static Signature *ProcessSignatures(TypeRelation *relation, Signature *target, ETSFunctionType *sourceFuncType)
75 {
76     Signature *match {};
77     for (auto *it : sourceFuncType->CallSignatures()) {
78         if (target->MinArgCount() != it->MinArgCount()) {
79             continue;
80         }
81 
82         if ((target->RestVar() != nullptr && it->RestVar() == nullptr) ||
83             (target->RestVar() == nullptr && it->RestVar() != nullptr)) {
84             continue;
85         }
86 
87         if (!it->GetSignatureInfo()->typeParams.empty()) {
88             auto *substitution = relation->GetChecker()->AsETSChecker()->NewSubstitution();
89             auto *instantiatedTypeParams = relation->GetChecker()->AsETSChecker()->NewInstantiatedTypeParamsSet();
90             bool res = true;
91             for (size_t ix = 0; ix < target->MinArgCount(); ix++) {
92                 res &= relation->GetChecker()->AsETSChecker()->EnhanceSubstitutionForType(
93                     it->GetSignatureInfo()->typeParams, it->GetSignatureInfo()->params[ix]->TsType(),
94                     target->GetSignatureInfo()->params[ix]->TsType(), substitution, instantiatedTypeParams);
95             }
96             if (target->RestVar() != nullptr) {
97                 res &= relation->GetChecker()->AsETSChecker()->EnhanceSubstitutionForType(
98                     it->GetSignatureInfo()->typeParams, it->RestVar()->TsType(), target->RestVar()->TsType(),
99                     substitution, instantiatedTypeParams);
100             }
101             if (!res) {
102                 continue;
103             }
104             it = it->Substitute(relation, substitution);
105         }
106 
107         size_t idx = 0;
108         for (; idx != target->MinArgCount(); idx++) {
109             if (!relation->IsIdenticalTo(target->Params()[idx]->TsType(), it->Params()[idx]->TsType())) {
110                 break;
111             }
112         }
113 
114         if (idx != target->MinArgCount()) {
115             continue;
116         }
117 
118         if (target->RestVar() != nullptr &&
119             !relation->IsIdenticalTo(target->RestVar()->TsType(), it->RestVar()->TsType())) {
120             continue;
121         }
122 
123         if (!relation->IsAssignableTo(target->ReturnType(), it->ReturnType())) {
124             continue;
125         }
126 
127         match = it;
128         break;
129     }
130     return match;
131 }
132 
AssignmentTarget(TypeRelation * relation,Type * source)133 void ETSFunctionType::AssignmentTarget(TypeRelation *relation, Type *source)
134 {
135     if (!source->IsETSFunctionType() &&
136         (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL))) {
137         return;
138     }
139 
140     ASSERT(callSignatures_.size() == 1 && callSignatures_[0]->HasSignatureFlag(SignatureFlags::TYPE));
141 
142     Signature *target = callSignatures_[0];
143     bool sourceIsFunctional = source->IsETSObjectType();
144     auto *sourceFuncType = sourceIsFunctional ? source->AsETSObjectType()->GetFunctionalInterfaceInvokeType()
145                                               : source->AsETSFunctionType();
146     Signature *match = ProcessSignatures(relation, target, sourceFuncType);
147 
148     if (match == nullptr) {
149         relation->Result(false);
150         return;
151     }
152 
153     if (!target->Function()->IsThrowing()) {
154         if (match->Function()->IsThrowing() || match->Function()->IsRethrowing()) {
155             relation->GetChecker()->ThrowTypeError(
156                 "Functions that can throw exceptions cannot be assigned to non throwing functions.",
157                 relation->GetNode()->Start());
158         }
159     }
160 
161     ASSERT(relation->GetNode() != nullptr);
162     if (!sourceIsFunctional) {
163         if (relation->GetNode()->IsArrowFunctionExpression()) {
164             relation->GetChecker()->AsETSChecker()->CreateLambdaObjectForLambdaReference(
165                 relation->GetNode()->AsArrowFunctionExpression(), callSignatures_[0]->Owner());
166         } else {
167             relation->GetChecker()->AsETSChecker()->CreateLambdaObjectForFunctionReference(relation->GetNode(), match,
168                                                                                            callSignatures_[0]->Owner());
169         }
170     }
171 
172     relation->Result(true);
173 }
174 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)175 Type *ETSFunctionType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
176                                    [[maybe_unused]] GlobalTypesHolder *globalTypes)
177 {
178     auto *copiedType = relation->GetChecker()->AsETSChecker()->CreateETSFunctionType(name_);
179 
180     for (auto *it : callSignatures_) {
181         copiedType->AddCallSignature(it->Copy(allocator, relation, globalTypes));
182     }
183 
184     return copiedType;
185 }
186 
Substitute(TypeRelation * relation,const Substitution * substitution)187 ETSFunctionType *ETSFunctionType::Substitute(TypeRelation *relation, const Substitution *substitution)
188 {
189     if (substitution == nullptr || substitution->empty()) {
190         return this;
191     }
192 
193     auto *checker = relation->GetChecker()->AsETSChecker();
194 
195     auto *copiedType = checker->CreateETSFunctionType(name_);
196     bool anyChange = false;
197 
198     for (auto *sig : callSignatures_) {
199         auto *newSig = sig->Substitute(relation, substitution);
200         copiedType->AddCallSignature(newSig);
201         if (newSig != sig) {
202             anyChange = true;
203         }
204     }
205 
206     return anyChange ? copiedType : this;
207 }
208 
CastFunctionParams(TypeRelation * relation,Type * target)209 checker::RelationResult ETSFunctionType::CastFunctionParams(TypeRelation *relation, Type *target)
210 {
211     auto *targetType = target->AsETSObjectType();
212     auto *body = targetType->GetDeclNode()->AsTSInterfaceDeclaration()->Body();
213     auto targetParams = body->AsTSInterfaceBody()->Body()[0]->AsMethodDefinition()->Function()->Params();
214     for (size_t i = 0; i < targetType->TypeArguments().size(); i++) {
215         relation->Result(RelationResult::FALSE);
216         callSignatures_[0]->Function()->Params()[i]->TsType()->Cast(
217             relation, targetParams[i]->AsETSParameterExpression()->Check(relation->GetChecker()->AsETSChecker()));
218         if (relation->IsTrue()) {
219             continue;
220         }
221         return RelationResult::FALSE;
222     }
223     return RelationResult::TRUE;
224 }
225 
Cast(TypeRelation * relation,Type * target)226 void ETSFunctionType::Cast(TypeRelation *relation, Type *target)
227 {
228     ASSERT(relation->GetNode()->IsArrowFunctionExpression());
229     if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
230         auto *targetType = target->AsETSObjectType();
231         auto *body = targetType->GetDeclNode()->AsTSInterfaceDeclaration()->Body()->AsTSInterfaceBody();
232         auto targetParams = body->AsTSInterfaceBody()->Body()[0]->AsMethodDefinition()->Function()->Params();
233         if (targetType->HasObjectFlag(ETSObjectFlags::FUNCTIONAL_INTERFACE) &&
234             targetParams.size() == callSignatures_[0]->Function()->Params().size()) {
235             relation->Result(CastFunctionParams(relation, target));
236         }
237         relation->Result(RelationResult::FALSE);
238         auto targetReturnType = body->Body()[0]->AsMethodDefinition()->Function()->ReturnTypeAnnotation();
239         callSignatures_[0]->ReturnType()->Cast(relation, targetReturnType->TsType());
240         if (relation->IsTrue()) {
241             relation->GetChecker()->AsETSChecker()->CreateLambdaObjectForLambdaReference(
242                 relation->GetNode()->AsArrowFunctionExpression(), targetType->AsETSObjectType());
243             return;
244         }
245     }
246     conversion::Forbidden(relation);
247 }
248 }  // namespace panda::es2panda::checker
249