1/** 2 * Copyright (c) 2021 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 "variableDeclarator.h" 17 18#include <compiler/base/lreference.h> 19#include <compiler/core/pandagen.h> 20#include <ir/astDump.h> 21#include <ir/expression.h> 22#include <ir/typeNode.h> 23#include <ir/statements/variableDeclaration.h> 24#include <ir/expressions/arrayExpression.h> 25#include <ir/expressions/identifier.h> 26#include <ir/expressions/objectExpression.h> 27#include <typescript/checker.h> 28#include <typescript/core/destructuringContext.h> 29 30namespace panda::es2panda::ir { 31 32void VariableDeclarator::Iterate(const NodeTraverser &cb) const 33{ 34 cb(id_); 35 36 if (init_) { 37 cb(init_); 38 } 39} 40 41void VariableDeclarator::Dump(ir::AstDumper *dumper) const 42{ 43 dumper->Add({{"type", "VariableDeclarator"}, 44 {"id", id_}, 45 {"definite", AstDumper::Optional(definite_)}, 46 {"init", AstDumper::Nullable(init_)}}); 47} 48 49void VariableDeclarator::Compile(compiler::PandaGen *pg) const 50{ 51 const ir::VariableDeclaration *decl = parent_->AsVariableDeclaration(); 52 if (decl->Declare()) { 53 return; 54 } 55 56 compiler::LReference lref = compiler::LReference::CreateLRef(pg, id_, true); 57 58 if (init_) { 59 init_->Compile(pg); 60 } else { 61 if (decl->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) { 62 return; 63 } 64 if (decl->Kind() == ir::VariableDeclaration::VariableDeclarationKind::LET && !decl->Parent()->IsCatchClause()) { 65 pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); 66 } 67 } 68 69 lref.SetValue(); 70} 71 72static void CheckSimpleVariableDeclaration(checker::Checker *checker, const ir::VariableDeclarator *declarator) 73{ 74 CHECK_NOT_NULL(declarator); 75 binder::Variable *bindingVar = declarator->Id()->AsIdentifier()->Variable(); 76 CHECK_NOT_NULL(bindingVar); 77 checker::Type *previousType = bindingVar->TsType(); 78 const ir::Expression *typeAnnotation = declarator->Id()->AsIdentifier()->TypeAnnotation(); 79 const ir::Expression *initializer = declarator->Init(); 80 bool isConst = declarator->Parent()->AsVariableDeclaration()->Kind() == 81 ir::VariableDeclaration::VariableDeclarationKind::CONST; 82 83 if (isConst) { 84 checker->AddStatus(checker::CheckerStatus::IN_CONST_CONTEXT); 85 } 86 87 if (typeAnnotation) { 88 typeAnnotation->Check(checker); 89 } 90 91 if (typeAnnotation && initializer) { 92 checker::Type *annotationType = typeAnnotation->AsTypeNode()->GetType(checker); 93 checker->ElaborateElementwise(annotationType, initializer, declarator->Id()->Start()); 94 bindingVar->SetTsType(annotationType); 95 } else if (typeAnnotation) { 96 bindingVar->SetTsType(typeAnnotation->AsTypeNode()->GetType(checker)); 97 } else if (initializer) { 98 checker::Type *initializerType = checker->CheckTypeCached(initializer); 99 100 if (!isConst) { 101 initializerType = checker->GetBaseTypeOfLiteralType(initializerType); 102 } 103 104 bindingVar->SetTsType(initializerType); 105 } else { 106 checker->ThrowTypeError({"Variable ", declarator->Id()->AsIdentifier()->Name(), " implicitly has an any type."}, 107 declarator->Id()->Start()); 108 } 109 110 if (previousType) { 111 checker->IsTypeIdenticalTo(bindingVar->TsType(), previousType, 112 {"Subsequent variable declaration must have the same type. Variable '", 113 bindingVar->Name(), "' must be of type '", previousType, "', but here has type '", 114 bindingVar->TsType(), "'."}, 115 declarator->Id()->Start()); 116 } 117 118 checker->RemoveStatus(checker::CheckerStatus::IN_CONST_CONTEXT); 119} 120 121checker::Type *VariableDeclarator::Check(checker::Checker *checker) const 122{ 123 auto found = checker->NodeCache().find(this); 124 if (found != checker->NodeCache().end()) { 125 return nullptr; 126 } 127 128 if (id_->IsIdentifier()) { 129 CheckSimpleVariableDeclaration(checker, this); 130 checker->NodeCache().insert({this, nullptr}); 131 return nullptr; 132 } 133 134 if (id_->IsArrayPattern()) { 135 auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE); 136 checker::ArrayDestructuringContext(checker, id_, false, id_->AsArrayPattern()->TypeAnnotation() == nullptr, 137 id_->AsArrayPattern()->TypeAnnotation(), init_) 138 .Start(); 139 140 checker->NodeCache().insert({this, nullptr}); 141 return nullptr; 142 } 143 144 ASSERT(id_->IsObjectPattern()); 145 auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE); 146 checker::ObjectDestructuringContext(checker, id_, false, id_->AsObjectPattern()->TypeAnnotation() == nullptr, 147 id_->AsObjectPattern()->TypeAnnotation(), init_) 148 .Start(); 149 150 checker->NodeCache().insert({this, nullptr}); 151 return nullptr; 152} 153 154void VariableDeclarator::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder) 155{ 156 id_ = std::get<ir::AstNode *>(cb(id_))->AsExpression(); 157 158 if (init_) { 159 init_ = std::get<ir::AstNode *>(cb(init_))->AsExpression(); 160 } 161} 162 163} // namespace panda::es2panda::ir 164