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 "checker.h" 17 18#include "checker/types/type.h" 19#include "ir/expression.h" 20#include "ir/statements/blockStatement.h" 21#include "parser/program/program.h" 22#include "util/helpers.h" 23#include "varbinder/varbinder.h" 24#include "varbinder/scope.h" 25#include "varbinder/variable.h" 26#include "es2panda.h" 27#include "checker/types/globalTypesHolder.h" 28#include "checker/types/ts/unionType.h" 29#include "checker/types/signature.h" 30 31#include <cstdint> 32#include <initializer_list> 33#include <memory> 34 35namespace ark::es2panda::checker { 36Checker::Checker() 37 : allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true), 38 context_(this, CheckerStatus::NO_OPTS), 39 globalTypes_(allocator_.New<GlobalTypesHolder>(&allocator_)), 40 relation_(allocator_.New<TypeRelation>(this)) 41{ 42} 43 44void Checker::Initialize(varbinder::VarBinder *varbinder) 45{ 46 varbinder_ = varbinder; 47 scope_ = varbinder_->TopScope(); 48 program_ = varbinder_->Program(); 49} 50 51std::string Checker::FormatMsg(std::initializer_list<TypeErrorMessageElement> list) 52{ 53 std::stringstream ss; 54 55 for (const auto &it : list) { 56 if (std::holds_alternative<char *>(it)) { 57 ss << std::get<char *>(it); 58 } else if (std::holds_alternative<util::StringView>(it)) { 59 ss << std::get<util::StringView>(it); 60 } else if (std::holds_alternative<lexer::TokenType>(it)) { 61 ss << TokenToString(std::get<lexer::TokenType>(it)); 62 } else if (std::holds_alternative<const Type *>(it)) { 63 std::get<const Type *>(it)->ToString(ss); 64 } else if (std::holds_alternative<AsSrc>(it)) { 65 std::get<AsSrc>(it).GetType()->ToStringAsSrc(ss); 66 } else if (std::holds_alternative<size_t>(it)) { 67 ss << std::to_string(std::get<size_t>(it)); 68 } else if (std::holds_alternative<const Signature *>(it)) { 69 std::get<const Signature *>(it)->ToString(ss, nullptr, true); 70 } else { 71 UNREACHABLE(); 72 } 73 } 74 75 return ss.str(); 76} 77 78void Checker::ThrowTypeError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos) 79{ 80 ThrowTypeError(FormatMsg(list), pos); 81} 82 83void Checker::ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos) 84{ 85 lexer::LineIndex index(program_->SourceCode()); 86 lexer::SourceLocation loc = index.GetLocation(pos); 87 88 throw Error {ErrorType::TYPE, program_->SourceFilePath().Utf8(), message, loc.line, loc.col}; 89} 90 91void Checker::LogTypeError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos) 92{ 93 LogTypeError(FormatMsg(list), pos); 94} 95 96void Checker::LogTypeError(std::string_view message, const lexer::SourcePosition &pos) 97{ 98 lexer::LineIndex index(program_->SourceCode()); 99 lexer::SourceLocation loc = index.GetLocation(pos); 100 101 errorLogger_.WriteLog(Error {ErrorType::TYPE, program_->SourceFilePath().Utf8(), message, loc.line, loc.col}); 102} 103 104void Checker::Warning(const std::string_view message, const lexer::SourcePosition &pos) const 105{ 106 lexer::LineIndex index(program_->SourceCode()); 107 lexer::SourceLocation loc = index.GetLocation(pos); 108 109 // NOTE: This should go to stderr but currently the test system does not handle stderr messages 110 auto fileName = program_->SourceFilePath().Utf8(); 111 fileName = fileName.substr(fileName.find_last_of(ark::os::file::File::GetPathDelim()) + 1); 112 std::cout << "Warning: " << message << " [" << fileName << ":" << loc.line << ":" << loc.col << "]" << std::endl; 113} 114 115void Checker::ReportWarning(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos) 116{ 117 Warning(FormatMsg(list), pos); 118} 119 120bool Checker::IsAllTypesAssignableTo(Type *source, Type *target) 121{ 122 if (source->TypeFlags() == TypeFlag::UNION) { 123 auto &types = source->AsUnionType()->ConstituentTypes(); 124 125 return std::all_of(types.begin(), types.end(), 126 [this, target](auto *it) { return IsAllTypesAssignableTo(it, target); }); 127 } 128 129 return relation_->IsAssignableTo(source, target); 130} 131 132bool Checker::IsTypeIdenticalTo(Type *source, Type *target) 133{ 134 return relation_->IsIdenticalTo(source, target); 135} 136 137bool Checker::IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, 138 const lexer::SourcePosition &errPos) 139{ 140 if (!IsTypeIdenticalTo(source, target)) { 141 relation_->RaiseError(errMsg, errPos); 142 } 143 144 return true; 145} 146 147bool Checker::IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 148 const lexer::SourcePosition &errPos) 149{ 150 if (!IsTypeIdenticalTo(source, target)) { 151 relation_->RaiseError(list, errPos); 152 } 153 154 return true; 155} 156 157bool Checker::IsTypeAssignableTo(Type *source, Type *target) 158{ 159 return relation_->IsAssignableTo(source, target); 160} 161 162bool Checker::IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, 163 const lexer::SourcePosition &errPos) 164{ 165 if (!IsTypeAssignableTo(source, target)) { 166 relation_->RaiseError(errMsg, errPos); 167 } 168 169 return true; 170} 171 172bool Checker::IsTypeAssignableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 173 const lexer::SourcePosition &errPos) 174{ 175 if (!IsTypeAssignableTo(source, target)) { 176 relation_->RaiseError(list, errPos); 177 } 178 179 return true; 180} 181 182bool Checker::IsTypeComparableTo(Type *source, Type *target) 183{ 184 return relation_->IsComparableTo(source, target); 185} 186 187bool Checker::IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, 188 const lexer::SourcePosition &errPos) 189{ 190 if (!IsTypeComparableTo(source, target)) { 191 relation_->RaiseError(errMsg, errPos); 192 } 193 194 return true; 195} 196 197bool Checker::IsTypeComparableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 198 const lexer::SourcePosition &errPos) 199{ 200 if (!IsTypeComparableTo(source, target)) { 201 relation_->RaiseError(list, errPos); 202 } 203 204 return true; 205} 206 207bool Checker::AreTypesComparable(Type *source, Type *target) 208{ 209 return IsTypeComparableTo(source, target) || IsTypeComparableTo(target, source); 210} 211 212bool Checker::IsTypeEqualityComparableTo(Type *source, Type *target) 213{ 214 return IsTypeComparableTo(source, target); 215} 216 217parser::Program *Checker::Program() const 218{ 219 return program_; 220} 221 222void Checker::SetProgram(parser::Program *program) 223{ 224 program_ = program; 225} 226 227varbinder::VarBinder *Checker::VarBinder() const 228{ 229 return varbinder_; 230} 231 232void Checker::SetAnalyzer(SemanticAnalyzer *analyzer) 233{ 234 analyzer_ = analyzer; 235} 236 237checker::SemanticAnalyzer *Checker::GetAnalyzer() const 238{ 239 return analyzer_; 240} 241 242} // namespace ark::es2panda::checker 243