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 25 namespace ark::es2panda::parser { 26 class Program; 27 } // namespace ark::es2panda::parser 28 29 namespace ark::es2panda::ir { 30 class AstNode; 31 class Expression; 32 class BlockStatement; 33 enum class AstNodeType; 34 } // namespace ark::es2panda::ir 35 36 namespace ark::es2panda::varbinder { 37 class VarBinder; 38 class Decl; 39 class EnumVariable; 40 class FunctionDecl; 41 class LocalVariable; 42 class Scope; 43 class Variable; 44 } // namespace ark::es2panda::varbinder 45 46 namespace ark::es2panda::checker { 47 class ETSChecker; 48 class InterfaceType; 49 class GlobalTypesHolder; 50 51 using StringLiteralPool = std::unordered_map<util::StringView, Type *>; 52 using NumberLiteralPool = std::unordered_map<double, Type *>; 53 using FunctionParamsResolveResult = std::variant<std::vector<varbinder::LocalVariable *> &, bool>; 54 using InterfacePropertyMap = 55 std::unordered_map<util::StringView, std::pair<varbinder::LocalVariable *, InterfaceType *>>; 56 using TypeOrNode = std::variant<Type *, ir::AstNode *>; 57 using IndexInfoTypePair = std::pair<Type *, Type *>; 58 using PropertyMap = std::unordered_map<util::StringView, varbinder::LocalVariable *>; 59 using ArgRange = std::pair<uint32_t, uint32_t>; 60 61 class Checker { 62 public: 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 AsETSChecker()149 [[nodiscard]] ETSChecker *AsETSChecker() 150 { 151 ASSERT(IsETSChecker()); 152 return reinterpret_cast<ETSChecker *>(this); 153 } 154 AsETSChecker() const155 [[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 ErrorLogger()201 util::ErrorLogger *ErrorLogger() 202 { 203 return &errorLogger_; 204 } 205 206 // NOTE: required only for evaluate. 207 void Initialize(varbinder::VarBinder *varbinder); 208 209 protected: 210 parser::Program *Program() const; 211 void SetProgram(parser::Program *program); 212 213 private: 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 234 class NamedTypeStackElement { 235 public: NamedTypeStackElement(Checker *checker, Type *element)236 explicit NamedTypeStackElement(Checker *checker, Type *element) : checker_(checker), element_(element) 237 { 238 checker_->namedTypeStack_.insert(element); 239 } 240 ~NamedTypeStackElement()241 ~NamedTypeStackElement() 242 { 243 checker_->namedTypeStack_.erase(element_); 244 } 245 NO_COPY_SEMANTIC(NamedTypeStackElement); 246 NO_MOVE_SEMANTIC(NamedTypeStackElement); 247 248 private: 249 Checker *checker_; 250 Type *element_; 251 }; 252 253 class TypeStackElement { 254 public: TypeStackElement(Checker *checker, void *element, std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos)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 TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos)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 HasTypeError()274 bool HasTypeError() 275 { 276 hasErrorChecker_ = true; 277 return element_ == nullptr; 278 } 279 ~TypeStackElement()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 291 private: 292 Checker *checker_; 293 void *element_; 294 bool hasErrorChecker_; 295 }; 296 297 class ScopeContext { 298 public: ScopeContext(Checker *checker, varbinder::Scope *newScope)299 explicit ScopeContext(Checker *checker, varbinder::Scope *newScope) 300 : checker_(checker), prevScope_(checker_->scope_) 301 { 302 checker_->scope_ = newScope; 303 } 304 ~ScopeContext()305 ~ScopeContext() 306 { 307 checker_->scope_ = prevScope_; 308 } 309 310 NO_COPY_SEMANTIC(ScopeContext); 311 NO_MOVE_SEMANTIC(ScopeContext); 312 313 private: 314 Checker *checker_; 315 varbinder::Scope *prevScope_; 316 }; 317 318 class SavedCheckerContext { 319 public: SavedCheckerContext(Checker *checker, CheckerStatus newStatus)320 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) 321 : SavedCheckerContext(checker, newStatus, nullptr) 322 { 323 } 324 SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass)325 explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass) 326 : SavedCheckerContext(checker, newStatus, containingClass, nullptr) 327 { 328 } 329 SavedCheckerContext(Checker *checker, CheckerStatus newStatus, const ETSObjectType *containingClass, Signature *containingSignature)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 ~SavedCheckerContext()345 ~SavedCheckerContext() 346 { 347 checker_->context_ = prev_; 348 } 349 350 private: 351 Checker *checker_; 352 CheckerContext prev_; 353 }; 354 355 } // namespace ark::es2panda::checker 356 357 #endif /* CHECKER_H */ 358