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