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 "arrowFunctionExpression.h"
17
18#include "compiler/core/pandagen.h"
19#include "compiler/core/ETSGen.h"
20#include "checker/ETSchecker.h"
21#include "checker/ets/typeRelationContext.h"
22#include "checker/TSchecker.h"
23#include "ir/astDump.h"
24#include "ir/srcDump.h"
25#include "ir/base/scriptFunction.h"
26#include "ir/ets/etsTypeReference.h"
27#include "ir/ets/etsTypeReferencePart.h"
28#include "ir/expressions/identifier.h"
29#include "ir/statements/variableDeclarator.h"
30
31namespace ark::es2panda::ir {
32void ArrowFunctionExpression::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName)
33{
34    if (auto *transformedNode = cb(func_); func_ != transformedNode) {
35        func_->SetTransformedNode(transformationName, transformedNode);
36        func_ = transformedNode->AsScriptFunction();
37    }
38}
39
40void ArrowFunctionExpression::Iterate(const NodeTraverser &cb) const
41{
42    cb(func_);
43}
44
45void ArrowFunctionExpression::Dump(ir::AstDumper *dumper) const
46{
47    dumper->Add({{"type", "ArrowFunctionExpression"}, {"function", func_}});
48}
49
50void ArrowFunctionExpression::Dump(ir::SrcDumper *dumper) const
51{
52    dumper->Add("(");
53    if (func_->IsScriptFunction() && func_->AsScriptFunction()->IsAsyncFunc()) {
54        dumper->Add("async ");
55    }
56    func_->Dump(dumper);
57    dumper->Add(")");
58}
59
60void ArrowFunctionExpression::Compile(compiler::PandaGen *pg) const
61{
62    pg->GetAstCompiler()->Compile(this);
63}
64
65void ArrowFunctionExpression::Compile(compiler::ETSGen *etsg) const
66{
67    etsg->GetAstCompiler()->Compile(this);
68}
69
70checker::Type *ArrowFunctionExpression::Check(checker::TSChecker *checker)
71{
72    return checker->GetAnalyzer()->Check(this);
73}
74
75checker::Type *ArrowFunctionExpression::Check(checker::ETSChecker *checker)
76{
77    return checker->GetAnalyzer()->Check(this);
78}
79
80ArrowFunctionExpression::ArrowFunctionExpression(ArrowFunctionExpression const &other, ArenaAllocator *const allocator)
81    : Expression(static_cast<Expression const &>(other))
82{
83    func_ = other.func_->Clone(allocator, this)->AsScriptFunction();
84}
85
86ArrowFunctionExpression *ArrowFunctionExpression::Clone(ArenaAllocator *const allocator, AstNode *const parent)
87{
88    if (auto *const clone = allocator->New<ArrowFunctionExpression>(*this, allocator); clone != nullptr) {
89        if (parent != nullptr) {
90            clone->SetParent(parent);
91        }
92        return clone;
93    }
94
95    throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
96}
97
98ir::TypeNode *ArrowFunctionExpression::CreateReturnNodeFromType(checker::ETSChecker *checker, checker::Type *returnType)
99{
100    /*
101    Construct a synthetic Node with the correct ts_type_.
102    */
103    ASSERT(returnType != nullptr);
104    auto *ident = checker->AllocNode<ir::Identifier>(util::StringView(""), checker->Allocator());
105    auto *const part = checker->AllocNode<ir::ETSTypeReferencePart>(ident);
106    auto *returnNode = checker->AllocNode<ir::ETSTypeReference>(part);
107    returnNode->SetTsType(returnType);
108    return returnNode;
109}
110
111ir::TypeNode *ArrowFunctionExpression::CreateTypeAnnotation(checker::ETSChecker *checker)
112{
113    ir::TypeNode *returnNode = nullptr;
114    /*
115    There are two scenarios for lambda type inference: defined or undefined return type.
116    example code:
117    ```
118    enum Color { Red, Blue}
119    // has Return Type Color
120    let x  = () : Color => {return Color.Red}
121    // No Return Type Color
122    let y  = () => {return Color.Red}
123    ```
124    */
125    if (Function()->ReturnTypeAnnotation() == nullptr) {
126        /*
127        When lambda expression does not declare a return type, we need to construct the
128        declaration node of lambda according to the Function()->Signature()->ReturnType().
129        */
130        returnNode = CreateReturnNodeFromType(checker, Function()->Signature()->ReturnType());
131    } else {
132        returnNode = Function()->ReturnTypeAnnotation()->Clone(checker->Allocator(), nullptr);
133        returnNode->SetTsType(Function()->ReturnTypeAnnotation()->TsType());
134    }
135
136    ArenaVector<ir::Expression *> params {checker->Allocator()->Adapter()};
137    checker->CopyParams(Function()->Params(), params);
138
139    auto signature = ir::FunctionSignature(nullptr, std::move(params), returnNode);
140    auto *funcType = checker->AllocNode<ir::ETSFunctionType>(std::move(signature), ir::ScriptFunctionFlags::NONE);
141    return funcType;
142}
143
144bool ArrowFunctionExpression::IsVarFromSubscope(const varbinder::Variable *var) const
145{
146    // The parameter scope's and the function scope's common ancestor lives outside the function, so we have to check
147    // them separetely.
148    return Function()->Scope()->IsSuperscopeOf(var->GetScope()) ||
149           Function()->Scope()->ParamScope()->IsSuperscopeOf(var->GetScope());
150}
151
152}  // namespace ark::es2panda::ir
153