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#ifndef ES2PANDA_CHECKER_CHECKER_H 17#define ES2PANDA_CHECKER_CHECKER_H 18 19#include "es2panda.h" 20 21#include "checker/checkerContext.h" 22#include "checker/SemanticAnalyzer.h" 23#include "util/errorLogger.h" 24 25namespace ark::es2panda::parser { 26class Program; 27} // namespace ark::es2panda::parser 28 29namespace ark::es2panda::ir { 30class AstNode; 31class Expression; 32class BlockStatement; 33enum class AstNodeType; 34} // namespace ark::es2panda::ir 35 36namespace ark::es2panda::varbinder { 37class VarBinder; 38class Decl; 39class EnumVariable; 40class FunctionDecl; 41class LocalVariable; 42class Scope; 43class Variable; 44} // namespace ark::es2panda::varbinder 45 46namespace ark::es2panda::checker { 47class ETSChecker; 48class InterfaceType; 49class GlobalTypesHolder; 50 51using StringLiteralPool = std::unordered_map<util::StringView, Type *>; 52using NumberLiteralPool = std::unordered_map<double, Type *>; 53using FunctionParamsResolveResult = std::variant<std::vector<varbinder::LocalVariable *> &, bool>; 54using InterfacePropertyMap = 55 std::unordered_map<util::StringView, std::pair<varbinder::LocalVariable *, InterfaceType *>>; 56using TypeOrNode = std::variant<Type *, ir::AstNode *>; 57using IndexInfoTypePair = std::pair<Type *, Type *>; 58using PropertyMap = std::unordered_map<util::StringView, varbinder::LocalVariable *>; 59using ArgRange = std::pair<uint32_t, uint32_t>; 60 61class Checker { 62public: 63 explicit Checker(); 64 virtual ~Checker() = default; 65 66 NO_COPY_SEMANTIC(Checker); 67 NO_MOVE_SEMANTIC(Checker); 68 69 [[nodiscard]] ArenaAllocator *Allocator() noexcept 70 { 71 return &allocator_; 72 } 73 74 [[nodiscard]] varbinder::Scope *Scope() const noexcept 75 { 76 return scope_; 77 } 78 79 [[nodiscard]] CheckerContext &Context() noexcept 80 { 81 return context_; 82 } 83 84 [[nodiscard]] bool HasStatus(CheckerStatus status) noexcept 85 { 86 return (context_.Status() & status) != 0; 87 } 88 89 void RemoveStatus(CheckerStatus status) noexcept 90 { 91 context_.Status() &= ~status; 92 } 93 94 void AddStatus(CheckerStatus status) noexcept 95 { 96 context_.Status() |= status; 97 } 98 99 [[nodiscard]] TypeRelation *Relation() const noexcept 100 { 101 return relation_; 102 } 103 104 [[nodiscard]] GlobalTypesHolder *GetGlobalTypesHolder() const noexcept 105 { 106 return globalTypes_; 107 } 108 109 [[nodiscard]] RelationHolder &IdenticalResults() noexcept 110 { 111 return identicalResults_; 112 } 113 114 [[nodiscard]] RelationHolder &AssignableResults() noexcept 115 { 116 return assignableResults_; 117 } 118 119 [[nodiscard]] RelationHolder &ComparableResults() noexcept 120 { 121 return comparableResults_; 122 } 123 124 [[nodiscard]] RelationHolder &UncheckedCastableResult() noexcept 125 { 126 return uncheckedCastableResults_; 127 } 128 129 [[nodiscard]] RelationHolder &SupertypeResults() noexcept 130 { 131 return supertypeResults_; 132 } 133 134 [[nodiscard]] std::unordered_set<const void *> &TypeStack() noexcept 135 { 136 return typeStack_; 137 } 138 139 [[nodiscard]] std::unordered_set<Type *> &NamedTypeStack() noexcept 140 { 141 return namedTypeStack_; 142 } 143 144 [[nodiscard]] virtual bool IsETSChecker() const noexcept 145 { 146 return false; 147 } 148 149 [[nodiscard]] ETSChecker *AsETSChecker() 150 { 151 ASSERT(IsETSChecker()); 152 return reinterpret_cast<ETSChecker *>(this); 153 } 154 155 [[nodiscard]] const ETSChecker *AsETSChecker() const 156 { 157 ASSERT(IsETSChecker()); 158 return reinterpret_cast<const ETSChecker *>(this); 159 } 160 161 virtual bool StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const CompilerOptions &options) = 0; 162 virtual Type *CheckTypeCached(ir::Expression *expr) = 0; 163 virtual Type *GetTypeOfVariable(varbinder::Variable *var) = 0; 164 virtual void ResolveStructuredTypeMembers(Type *type) = 0; 165 166 std::string FormatMsg(std::initializer_list<TypeErrorMessageElement> list); 167 [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); 168 [[noreturn]] void ThrowTypeError(std::initializer_list<TypeErrorMessageElement> list, 169 const lexer::SourcePosition &pos); 170 void LogTypeError(std::string_view message, const lexer::SourcePosition &pos); 171 void LogTypeError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos); 172 void Warning(std::string_view message, const lexer::SourcePosition &pos) const; 173 void ReportWarning(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos); 174 175 bool IsTypeIdenticalTo(Type *source, Type *target); 176 bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); 177 bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 178 const lexer::SourcePosition &errPos); 179 bool IsTypeAssignableTo(Type *source, Type *target); 180 bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); 181 bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 182 const lexer::SourcePosition &errPos); 183 bool IsTypeComparableTo(Type *source, Type *target); 184 bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); 185 bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list, 186 const lexer::SourcePosition &errPos); 187 bool AreTypesComparable(Type *source, Type *target); 188 bool IsTypeEqualityComparableTo(Type *source, Type *target); 189 bool IsAllTypesAssignableTo(Type *source, Type *target); 190 void SetAnalyzer(SemanticAnalyzer *analyzer); 191 checker::SemanticAnalyzer *GetAnalyzer() const; 192 193 friend class ScopeContext; 194 friend class TypeStackElement; 195 friend class NamedTypeStackElement; 196 friend class SavedCheckerContext; 197 friend class NamedTypeStackElement; 198 199 varbinder::VarBinder *VarBinder() const; 200 201 util::ErrorLogger *ErrorLogger() 202 { 203 return &errorLogger_; 204 } 205 206 // NOTE: required only for evaluate. 207 void Initialize(varbinder::VarBinder *varbinder); 208 209protected: 210 parser::Program *Program() const; 211 void SetProgram(parser::Program *program); 212 213private: 214 ArenaAllocator allocator_; 215 CheckerContext context_; 216 GlobalTypesHolder *globalTypes_; 217 TypeRelation *relation_; 218 SemanticAnalyzer *analyzer_ {}; 219 varbinder::VarBinder *varbinder_ {}; 220 parser::Program *program_ {}; 221 varbinder::Scope *scope_ {}; 222 util::ErrorLogger errorLogger_; 223 224 RelationHolder identicalResults_ {{}, RelationType::IDENTICAL}; 225 RelationHolder assignableResults_ {{}, RelationType::ASSIGNABLE}; 226 RelationHolder comparableResults_ {{}, RelationType::COMPARABLE}; 227 RelationHolder uncheckedCastableResults_ {{}, RelationType::UNCHECKED_CASTABLE}; 228 RelationHolder supertypeResults_ {{}, RelationType::SUPERTYPE}; 229 230 std::unordered_set<const void *> typeStack_; 231 std::unordered_set<Type *> namedTypeStack_; 232}; 233 234class NamedTypeStackElement { 235public: 236 explicit NamedTypeStackElement(Checker *checker, Type *element) : checker_(checker), element_(element) 237 { 238 checker_->namedTypeStack_.insert(element); 239 } 240 241 ~NamedTypeStackElement() 242 { 243 checker_->namedTypeStack_.erase(element_); 244 } 245 NO_COPY_SEMANTIC(NamedTypeStackElement); 246 NO_MOVE_SEMANTIC(NamedTypeStackElement); 247 248private: 249 Checker *checker_; 250 Type *element_; 251}; 252 253class TypeStackElement { 254public: 255 explicit TypeStackElement(Checker *checker, void *element, std::initializer_list<TypeErrorMessageElement> list, 256 const lexer::SourcePosition &pos) 257 : checker_(checker), element_(element), hasErrorChecker_(false) 258 { 259 if (!checker->typeStack_.insert(element).second) { 260 checker_->LogTypeError(list, pos); 261 element_ = nullptr; 262 } 263 } 264 265 explicit TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos) 266 : checker_(checker), element_(element), hasErrorChecker_(false) 267 { 268 if (!checker->typeStack_.insert(element).second) { 269 checker_->LogTypeError(err, pos); 270 element_ = nullptr; 271 } 272 } 273 274 bool HasTypeError() 275 { 276 hasErrorChecker_ = true; 277 return element_ == nullptr; 278 } 279 280 ~TypeStackElement() 281 { 282 ASSERT(hasErrorChecker_); 283 if (element_ != nullptr) { 284 checker_->typeStack_.erase(element_); 285 } 286 } 287 288 NO_COPY_SEMANTIC(TypeStackElement); 289 NO_MOVE_SEMANTIC(TypeStackElement); 290 291private: 292 Checker *checker_; 293 void *element_; 294 bool hasErrorChecker_; 295}; 296 297class ScopeContext { 298public: 299 explicit ScopeContext(Checker *checker, varbinder::Scope *newScope) 300 : checker_(checker), prevScope_(checker_->scope_) 301 { 302 checker_->scope_ = newScope; 303 } 304 305 ~ScopeContext() 306 { 307 checker_->scope_ = prevScope_; 308 } 309 310 NO_COPY_SEMANTIC(ScopeContext); 311 NO_MOVE_SEMANTIC(ScopeContext); 312 313private: 314 Checker *checker_; 315 varbinder::Scope *prevScope_; 316}; 317 318class SavedCheckerContext { 319public: 320 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) 321 : SavedCheckerContext(checker, newStatus, nullptr) 322 { 323 } 324 325 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass) 326 : SavedCheckerContext(checker, newStatus, containingClass, nullptr) 327 { 328 } 329 330 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass, 331 Signature *containingSignature) 332 : checker_(checker), prev_(checker->context_) 333 { 334 const bool inExternal = checker->HasStatus(CheckerStatus::IN_EXTERNAL); 335 checker_->context_ = CheckerContext(checker, newStatus, containingClass, containingSignature); 336 if (inExternal) { 337 // handled here instead of at call sites to make things more foolproof 338 checker_->context_.Status() |= CheckerStatus::IN_EXTERNAL; 339 } 340 } 341 342 NO_COPY_SEMANTIC(SavedCheckerContext); 343 DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); 344 345 ~SavedCheckerContext() 346 { 347 checker_->context_ = prev_; 348 } 349 350private: 351 Checker *checker_; 352 CheckerContext prev_; 353}; 354 355} // namespace ark::es2panda::checker 356 357#endif /* CHECKER_H */ 358