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 "tsAsExpression.h" 17 18#include <binder/scope.h> 19#include <typescript/checker.h> 20#include <ir/expressions/identifier.h> 21#include <ir/expressions/literal.h> 22#include <ir/expressions/memberExpression.h> 23#include <ir/expressions/unaryExpression.h> 24#include <ir/typeNode.h> 25 26namespace panda::es2panda::ir { 27 28void TSAsExpression::Iterate(const NodeTraverser &cb) const 29{ 30 cb(expression_); 31 cb(typeAnnotation_); 32} 33 34void TSAsExpression::Dump(ir::AstDumper *dumper) const 35{ 36 dumper->Add({{"type", "TSAsExpression"}, {"expression", expression_}, {"typeAnnotation", typeAnnotation_}}); 37} 38 39void TSAsExpression::Compile(compiler::PandaGen *pg) const 40{ 41 expression_->Compile(pg); 42} 43 44static bool IsValidConstAssertionArgument(checker::Checker *checker, const ir::AstNode *arg) 45{ 46 switch (arg->Type()) { 47 case ir::AstNodeType::NUMBER_LITERAL: 48 case ir::AstNodeType::STRING_LITERAL: 49 case ir::AstNodeType::BIGINT_LITERAL: 50 case ir::AstNodeType::BOOLEAN_LITERAL: 51 case ir::AstNodeType::ARRAY_EXPRESSION: 52 case ir::AstNodeType::OBJECT_EXPRESSION: 53 case ir::AstNodeType::TEMPLATE_LITERAL: { 54 return true; 55 } 56 case ir::AstNodeType::UNARY_EXPRESSION: { 57 const ir::UnaryExpression *unaryExpr = arg->AsUnaryExpression(); 58 lexer::TokenType op = unaryExpr->OperatorType(); 59 const ir::Expression *unaryArg = unaryExpr->Argument(); 60 return (op == lexer::TokenType::PUNCTUATOR_MINUS && unaryArg->IsLiteral() && 61 (unaryArg->AsLiteral()->IsNumberLiteral() || unaryArg->AsLiteral()->IsBigIntLiteral())) || 62 (op == lexer::TokenType::PUNCTUATOR_PLUS && unaryArg->IsLiteral() && 63 unaryArg->AsLiteral()->IsNumberLiteral()); 64 } 65 case ir::AstNodeType::MEMBER_EXPRESSION: { 66 const ir::MemberExpression *memberExpr = arg->AsMemberExpression(); 67 if (memberExpr->Object()->IsIdentifier()) { 68 binder::ScopeFindResult result = checker->Scope()->Find(memberExpr->Object()->AsIdentifier()->Name()); 69 constexpr auto enumLiteralType = checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL; 70 if (result.variable && result.variable->TsType()->HasTypeFlag(checker::TypeFlag::ENUM_LITERAL) && 71 result.variable->TsType()->AsEnumLiteralType()->Kind() == enumLiteralType) { 72 return true; 73 } 74 } 75 return false; 76 } 77 default: 78 return false; 79 } 80} 81 82checker::Type *TSAsExpression::Check(checker::Checker *checker) const 83{ 84 if (isConst_) { 85 auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_CONST_CONTEXT); 86 checker::Type *exprType = expression_->Check(checker); 87 88 if (!IsValidConstAssertionArgument(checker, expression_)) { 89 checker->ThrowTypeError( 90 "A 'const' assertions can only be applied to references to enum members, or string, number, " 91 "boolean, array, or object literals.", 92 expression_->Start()); 93 } 94 95 return exprType; 96 } 97 98 auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::NO_OPTS); 99 100 typeAnnotation_->Check(checker); 101 checker::Type *exprType = checker->GetBaseTypeOfLiteralType(expression_->Check(checker)); 102 checker::Type *targetType = typeAnnotation_->AsTypeNode()->GetType(checker); 103 104 checker->IsTypeComparableTo( 105 targetType, exprType, 106 {"Conversion of type '", exprType, "' to type '", targetType, 107 "' may be a mistake because neither type sufficiently overlaps with the other. If this was ", 108 "intentional, convert the expression to 'unknown' first."}, 109 Start()); 110 111 return targetType; 112} 113 114void TSAsExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder) 115{ 116 expression_ = std::get<ir::AstNode *>(cb(expression_))->AsExpression(); 117 typeAnnotation_ = std::get<ir::AstNode *>(cb(typeAnnotation_))->AsExpression(); 118} 119 120} // namespace panda::es2panda::ir 121