13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "variableDeclarator.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <compiler/base/lreference.h>
193af6ab5fSopenharmony_ci#include <compiler/core/pandagen.h>
203af6ab5fSopenharmony_ci#include <ir/astDump.h>
213af6ab5fSopenharmony_ci#include <ir/expression.h>
223af6ab5fSopenharmony_ci#include <ir/typeNode.h>
233af6ab5fSopenharmony_ci#include <ir/statements/variableDeclaration.h>
243af6ab5fSopenharmony_ci#include <ir/expressions/arrayExpression.h>
253af6ab5fSopenharmony_ci#include <ir/expressions/identifier.h>
263af6ab5fSopenharmony_ci#include <ir/expressions/objectExpression.h>
273af6ab5fSopenharmony_ci#include <typescript/checker.h>
283af6ab5fSopenharmony_ci#include <typescript/core/destructuringContext.h>
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_cinamespace panda::es2panda::ir {
313af6ab5fSopenharmony_ci
323af6ab5fSopenharmony_civoid VariableDeclarator::Iterate(const NodeTraverser &cb) const
333af6ab5fSopenharmony_ci{
343af6ab5fSopenharmony_ci    cb(id_);
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ci    if (init_) {
373af6ab5fSopenharmony_ci        cb(init_);
383af6ab5fSopenharmony_ci    }
393af6ab5fSopenharmony_ci}
403af6ab5fSopenharmony_ci
413af6ab5fSopenharmony_civoid VariableDeclarator::Dump(ir::AstDumper *dumper) const
423af6ab5fSopenharmony_ci{
433af6ab5fSopenharmony_ci    dumper->Add({{"type", "VariableDeclarator"},
443af6ab5fSopenharmony_ci                 {"id", id_},
453af6ab5fSopenharmony_ci                 {"definite", AstDumper::Optional(definite_)},
463af6ab5fSopenharmony_ci                 {"init", AstDumper::Nullable(init_)}});
473af6ab5fSopenharmony_ci}
483af6ab5fSopenharmony_ci
493af6ab5fSopenharmony_civoid VariableDeclarator::Compile(compiler::PandaGen *pg) const
503af6ab5fSopenharmony_ci{
513af6ab5fSopenharmony_ci    const ir::VariableDeclaration *decl = parent_->AsVariableDeclaration();
523af6ab5fSopenharmony_ci    if (decl->Declare()) {
533af6ab5fSopenharmony_ci        return;
543af6ab5fSopenharmony_ci    }
553af6ab5fSopenharmony_ci
563af6ab5fSopenharmony_ci    compiler::LReference lref = compiler::LReference::CreateLRef(pg, id_, true);
573af6ab5fSopenharmony_ci
583af6ab5fSopenharmony_ci    if (init_) {
593af6ab5fSopenharmony_ci        init_->Compile(pg);
603af6ab5fSopenharmony_ci    } else {
613af6ab5fSopenharmony_ci        if (decl->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) {
623af6ab5fSopenharmony_ci            return;
633af6ab5fSopenharmony_ci        }
643af6ab5fSopenharmony_ci        if (decl->Kind() == ir::VariableDeclaration::VariableDeclarationKind::LET && !decl->Parent()->IsCatchClause()) {
653af6ab5fSopenharmony_ci            pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
663af6ab5fSopenharmony_ci        }
673af6ab5fSopenharmony_ci    }
683af6ab5fSopenharmony_ci
693af6ab5fSopenharmony_ci    lref.SetValue();
703af6ab5fSopenharmony_ci}
713af6ab5fSopenharmony_ci
723af6ab5fSopenharmony_cistatic void CheckSimpleVariableDeclaration(checker::Checker *checker, const ir::VariableDeclarator *declarator)
733af6ab5fSopenharmony_ci{
743af6ab5fSopenharmony_ci    CHECK_NOT_NULL(declarator);
753af6ab5fSopenharmony_ci    binder::Variable *bindingVar = declarator->Id()->AsIdentifier()->Variable();
763af6ab5fSopenharmony_ci    CHECK_NOT_NULL(bindingVar);
773af6ab5fSopenharmony_ci    checker::Type *previousType = bindingVar->TsType();
783af6ab5fSopenharmony_ci    const ir::Expression *typeAnnotation = declarator->Id()->AsIdentifier()->TypeAnnotation();
793af6ab5fSopenharmony_ci    const ir::Expression *initializer = declarator->Init();
803af6ab5fSopenharmony_ci    bool isConst = declarator->Parent()->AsVariableDeclaration()->Kind() ==
813af6ab5fSopenharmony_ci                   ir::VariableDeclaration::VariableDeclarationKind::CONST;
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    if (isConst) {
843af6ab5fSopenharmony_ci        checker->AddStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
853af6ab5fSopenharmony_ci    }
863af6ab5fSopenharmony_ci
873af6ab5fSopenharmony_ci    if (typeAnnotation) {
883af6ab5fSopenharmony_ci        typeAnnotation->Check(checker);
893af6ab5fSopenharmony_ci    }
903af6ab5fSopenharmony_ci
913af6ab5fSopenharmony_ci    if (typeAnnotation && initializer) {
923af6ab5fSopenharmony_ci        checker::Type *annotationType = typeAnnotation->AsTypeNode()->GetType(checker);
933af6ab5fSopenharmony_ci        checker->ElaborateElementwise(annotationType, initializer, declarator->Id()->Start());
943af6ab5fSopenharmony_ci        bindingVar->SetTsType(annotationType);
953af6ab5fSopenharmony_ci    } else if (typeAnnotation) {
963af6ab5fSopenharmony_ci        bindingVar->SetTsType(typeAnnotation->AsTypeNode()->GetType(checker));
973af6ab5fSopenharmony_ci    } else if (initializer) {
983af6ab5fSopenharmony_ci        checker::Type *initializerType = checker->CheckTypeCached(initializer);
993af6ab5fSopenharmony_ci
1003af6ab5fSopenharmony_ci        if (!isConst) {
1013af6ab5fSopenharmony_ci            initializerType = checker->GetBaseTypeOfLiteralType(initializerType);
1023af6ab5fSopenharmony_ci        }
1033af6ab5fSopenharmony_ci
1043af6ab5fSopenharmony_ci        bindingVar->SetTsType(initializerType);
1053af6ab5fSopenharmony_ci    } else {
1063af6ab5fSopenharmony_ci        checker->ThrowTypeError({"Variable ", declarator->Id()->AsIdentifier()->Name(), " implicitly has an any type."},
1073af6ab5fSopenharmony_ci                                declarator->Id()->Start());
1083af6ab5fSopenharmony_ci    }
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_ci    if (previousType) {
1113af6ab5fSopenharmony_ci        checker->IsTypeIdenticalTo(bindingVar->TsType(), previousType,
1123af6ab5fSopenharmony_ci                                   {"Subsequent variable declaration must have the same type. Variable '",
1133af6ab5fSopenharmony_ci                                    bindingVar->Name(), "' must be of type '", previousType, "', but here has type '",
1143af6ab5fSopenharmony_ci                                    bindingVar->TsType(), "'."},
1153af6ab5fSopenharmony_ci                                   declarator->Id()->Start());
1163af6ab5fSopenharmony_ci    }
1173af6ab5fSopenharmony_ci
1183af6ab5fSopenharmony_ci    checker->RemoveStatus(checker::CheckerStatus::IN_CONST_CONTEXT);
1193af6ab5fSopenharmony_ci}
1203af6ab5fSopenharmony_ci
1213af6ab5fSopenharmony_cichecker::Type *VariableDeclarator::Check(checker::Checker *checker) const
1223af6ab5fSopenharmony_ci{
1233af6ab5fSopenharmony_ci    auto found = checker->NodeCache().find(this);
1243af6ab5fSopenharmony_ci    if (found != checker->NodeCache().end()) {
1253af6ab5fSopenharmony_ci        return nullptr;
1263af6ab5fSopenharmony_ci    }
1273af6ab5fSopenharmony_ci
1283af6ab5fSopenharmony_ci    if (id_->IsIdentifier()) {
1293af6ab5fSopenharmony_ci        CheckSimpleVariableDeclaration(checker, this);
1303af6ab5fSopenharmony_ci        checker->NodeCache().insert({this, nullptr});
1313af6ab5fSopenharmony_ci        return nullptr;
1323af6ab5fSopenharmony_ci    }
1333af6ab5fSopenharmony_ci
1343af6ab5fSopenharmony_ci    if (id_->IsArrayPattern()) {
1353af6ab5fSopenharmony_ci        auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
1363af6ab5fSopenharmony_ci        checker::ArrayDestructuringContext(checker, id_, false, id_->AsArrayPattern()->TypeAnnotation() == nullptr,
1373af6ab5fSopenharmony_ci                                           id_->AsArrayPattern()->TypeAnnotation(), init_)
1383af6ab5fSopenharmony_ci            .Start();
1393af6ab5fSopenharmony_ci
1403af6ab5fSopenharmony_ci        checker->NodeCache().insert({this, nullptr});
1413af6ab5fSopenharmony_ci        return nullptr;
1423af6ab5fSopenharmony_ci    }
1433af6ab5fSopenharmony_ci
1443af6ab5fSopenharmony_ci    ASSERT(id_->IsObjectPattern());
1453af6ab5fSopenharmony_ci    auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
1463af6ab5fSopenharmony_ci    checker::ObjectDestructuringContext(checker, id_, false, id_->AsObjectPattern()->TypeAnnotation() == nullptr,
1473af6ab5fSopenharmony_ci                                        id_->AsObjectPattern()->TypeAnnotation(), init_)
1483af6ab5fSopenharmony_ci        .Start();
1493af6ab5fSopenharmony_ci
1503af6ab5fSopenharmony_ci    checker->NodeCache().insert({this, nullptr});
1513af6ab5fSopenharmony_ci    return nullptr;
1523af6ab5fSopenharmony_ci}
1533af6ab5fSopenharmony_ci
1543af6ab5fSopenharmony_civoid VariableDeclarator::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
1553af6ab5fSopenharmony_ci{
1563af6ab5fSopenharmony_ci    id_ = std::get<ir::AstNode *>(cb(id_))->AsExpression();
1573af6ab5fSopenharmony_ci
1583af6ab5fSopenharmony_ci    if (init_) {
1593af6ab5fSopenharmony_ci        init_ = std::get<ir::AstNode *>(cb(init_))->AsExpression();
1603af6ab5fSopenharmony_ci    }
1613af6ab5fSopenharmony_ci}
1623af6ab5fSopenharmony_ci
1633af6ab5fSopenharmony_ci}  // namespace panda::es2panda::ir
164