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_COMPILER_CHECKER_TYPES_TYPE_RELATION_H 17 #define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H 18 19 #include "lexer/token/sourceLocation.h" 20 #include "lexer/token/tokenType.h" 21 #include "util/ustring.h" 22 #include "util/enumbitops.h" 23 24 namespace ark::es2panda::ir { 25 class Expression; 26 } // namespace ark::es2panda::ir 27 28 namespace ark::es2panda::checker { 29 class Signature; 30 class IndexInfo; 31 class Type; 32 class Checker; 33 34 using ENUMBITOPS_OPERATORS; 35 36 enum class TypeRelationFlag : uint32_t { 37 NONE = 0U, 38 NARROWING = 1U << 0U, 39 WIDENING = 1U << 1U, 40 BOXING = 1U << 2U, 41 UNBOXING = 1U << 3U, 42 CAPTURE = 1U << 4U, 43 STRING = 1U << 5U, 44 VALUE_SET = 1U << 6U, 45 UNCHECKED = 1U << 7U, 46 NO_THROW = 1U << 8U, 47 SELF_REFERENCE = 1U << 9U, 48 NO_RETURN_TYPE_CHECK = 1U << 10U, 49 DIRECT_RETURN = 1U << 11U, 50 NO_WIDENING = 1U << 12U, 51 NO_BOXING = 1U << 13U, 52 NO_UNBOXING = 1U << 14U, 53 ONLY_CHECK_WIDENING = 1U << 15U, 54 ONLY_CHECK_BOXING_UNBOXING = 1U << 16U, 55 IN_ASSIGNMENT_CONTEXT = 1U << 17U, 56 IN_CASTING_CONTEXT = 1U << 18U, 57 UNCHECKED_CAST = 1U << 19U, 58 IGNORE_TYPE_PARAMETERS = 1U << 20U, 59 CHECK_PROXY = 1U << 21U, 60 NO_CHECK_TRAILING_LAMBDA = 1U << 23U, 61 NO_THROW_GENERIC_TYPEALIAS = 1U << 24U, 62 OVERRIDING_CONTEXT = 1U << 25U, 63 IGNORE_REST_PARAM = 1U << 26U, 64 STRING_TO_CHAR = 1U << 27U, 65 66 ASSIGNMENT_CONTEXT = WIDENING | BOXING | UNBOXING, 67 CASTING_CONTEXT = NARROWING | WIDENING | BOXING | UNBOXING | UNCHECKED_CAST, 68 }; 69 70 enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS, ERROR }; 71 72 enum class RelationType { COMPARABLE, ASSIGNABLE, IDENTICAL, UNCHECKED_CASTABLE, SUPERTYPE }; 73 74 } // namespace ark::es2panda::checker 75 76 template <> 77 struct enumbitops::IsAllowedType<ark::es2panda::checker::TypeRelationFlag> : std::true_type { 78 }; 79 80 namespace ark::es2panda::checker { 81 82 class RelationKey { 83 public: 84 uint64_t sourceId; 85 uint64_t targetId; 86 }; 87 88 class RelationKeyHasher { 89 public: 90 size_t operator()(const RelationKey &key) const noexcept 91 { 92 return static_cast<size_t>(key.sourceId ^ key.targetId); 93 } 94 }; 95 96 class RelationKeyComparator { 97 public: 98 bool operator()(const RelationKey &lhs, const RelationKey &rhs) const 99 { 100 return lhs.sourceId == rhs.sourceId && lhs.targetId == rhs.targetId; 101 } 102 }; 103 104 class RelationEntry { 105 public: 106 RelationResult result; 107 RelationType type; 108 }; 109 110 using RelationMap = std::unordered_map<RelationKey, RelationEntry, RelationKeyHasher, RelationKeyComparator>; 111 112 class RelationHolder { 113 public: 114 RelationMap cached; 115 RelationType type {}; 116 }; 117 118 class AsSrc { 119 public: 120 explicit AsSrc(const Type *type) : type_(const_cast<Type *>(type)) {} 121 122 const Type *GetType() const 123 { 124 return type_; 125 } 126 127 private: 128 Type *type_; 129 }; 130 131 using TypeErrorMessageElement = 132 std::variant<const Type *, AsSrc, char *, util::StringView, lexer::TokenType, size_t, const Signature *>; 133 134 class TypeRelation { 135 public: 136 explicit TypeRelation(Checker *checker) 137 : checker_(checker), result_(RelationResult::FALSE), instantiationRecursionMap_(Allocator()->Adapter()) 138 { 139 } 140 141 bool IsTrue() const 142 { 143 return result_ == RelationResult::TRUE; 144 } 145 146 bool IsError() const 147 { 148 return result_ == RelationResult::ERROR; 149 } 150 151 bool ApplyNarrowing() const 152 { 153 return (flags_ & TypeRelationFlag::NARROWING) != 0; 154 } 155 156 bool ApplyWidening() const 157 { 158 return (flags_ & TypeRelationFlag::WIDENING) != 0; 159 } 160 161 bool ApplyBoxing() const 162 { 163 return (flags_ & TypeRelationFlag::BOXING) != 0; 164 } 165 166 bool ApplyUnboxing() const 167 { 168 return (flags_ & TypeRelationFlag::UNBOXING) != 0; 169 } 170 171 bool ApplyStringToChar() const 172 { 173 return (flags_ & TypeRelationFlag::STRING_TO_CHAR) != 0; 174 } 175 176 bool NoReturnTypeCheck() const 177 { 178 return (flags_ & TypeRelationFlag::NO_RETURN_TYPE_CHECK) != 0; 179 } 180 181 bool DirectReturn() const 182 { 183 return (flags_ & TypeRelationFlag::DIRECT_RETURN) != 0; 184 } 185 186 bool InAssignmentContext() const 187 { 188 return (flags_ & TypeRelationFlag::IN_ASSIGNMENT_CONTEXT) != 0; 189 } 190 191 bool OnlyCheckWidening() const 192 { 193 return (flags_ & TypeRelationFlag::ONLY_CHECK_WIDENING) != 0; 194 } 195 196 bool OnlyCheckBoxingUnboxing() const 197 { 198 return (flags_ & TypeRelationFlag::ONLY_CHECK_BOXING_UNBOXING) != 0; 199 } 200 201 bool IgnoreTypeParameters() const 202 { 203 return (flags_ & TypeRelationFlag::IGNORE_TYPE_PARAMETERS) != 0; 204 } 205 206 [[nodiscard]] bool InCastingContext() const noexcept 207 { 208 return (flags_ & TypeRelationFlag::IN_CASTING_CONTEXT) != 0; 209 } 210 211 [[nodiscard]] bool UncheckedCast() const noexcept 212 { 213 return (flags_ & TypeRelationFlag::UNCHECKED_CAST) != 0; 214 } 215 216 [[nodiscard]] bool NoThrow() const noexcept 217 { 218 return (flags_ & TypeRelationFlag::NO_THROW) != 0; 219 } 220 221 [[nodiscard]] bool NoThrowGenericTypeAlias() const noexcept 222 { 223 return (flags_ & TypeRelationFlag::NO_THROW_GENERIC_TYPEALIAS) != 0; 224 } 225 226 [[nodiscard]] bool IsOverridingCheck() const noexcept 227 { 228 return (flags_ & TypeRelationFlag::OVERRIDING_CONTEXT) != 0; 229 } 230 231 [[nodiscard]] TypeRelationFlag GetTypeRelationFlags() const noexcept 232 { 233 return flags_; 234 } 235 236 const Checker *GetChecker() const 237 { 238 return checker_; 239 } 240 241 ir::Expression *GetNode() const 242 { 243 return node_; 244 } 245 246 Checker *GetChecker() 247 { 248 return checker_; 249 } 250 251 void IncreaseTypeRecursionCount(Type *const type) 252 { 253 if (const auto foundType = instantiationRecursionMap_.find(type); 254 foundType != instantiationRecursionMap_.end()) { 255 foundType->second += 1; 256 return; 257 } 258 259 instantiationRecursionMap_.insert({type, 1}); 260 } 261 262 bool TypeInstantiationPossible(Type *const type) 263 { 264 // This limitation makes sure that no type can be instantiated in infinite recursion. When declaring generic 265 // classes with recursive types, so the generic class itself, we need to allow 2 depth of recursion, to make it 266 // possible to reference the correct types of it's members and methods. 2 is possibly enough, because if we 267 // chain expressions, every one of them will be rechecked separately, thus allowing another 2 recursion. 268 constexpr auto MAX_RECURSIVE_TYPE_INST = 2; 269 const auto foundType = instantiationRecursionMap_.find(type); 270 return foundType == instantiationRecursionMap_.end() ? true : (foundType->second < MAX_RECURSIVE_TYPE_INST); 271 } 272 273 void DecreaseTypeRecursionCount(Type *const type) 274 { 275 const auto foundType = instantiationRecursionMap_.find(type); 276 if (foundType == instantiationRecursionMap_.end()) { 277 return; 278 } 279 280 if (foundType->second > 1) { 281 foundType->second -= 1; 282 return; 283 } 284 285 instantiationRecursionMap_.erase(type); 286 } 287 288 // NOTE: special overloading to be used mainly in ETSCompiler where types and nodes are 'const'. 289 // Unfortunately now we cannot have only a single method with 'const Types *' because it affects 290 // a lot of non-const references... :((( 291 bool IsIdenticalTo(Type const *source, Type const *target) 292 { 293 return IsIdenticalTo(const_cast<Type *>(source), const_cast<Type *>(target)); 294 } 295 bool IsIdenticalTo(Type *source, Type *target); 296 bool IsIdenticalTo(IndexInfo *source, IndexInfo *target); 297 bool IsCompatibleTo(Signature *source, Signature *target); 298 bool IsAssignableTo(Type *source, Type *target); 299 bool IsComparableTo(Type *source, Type *target); 300 bool IsCastableTo(Type *const source, Type *const target); 301 bool IsSupertypeOf(Type const *super, Type const *sub) 302 { 303 return IsSupertypeOf(const_cast<Type *>(super), const_cast<Type *>(sub)); 304 } 305 bool IsSupertypeOf(Type *super, Type *sub); 306 void RaiseError(const std::string &errMsg, const lexer::SourcePosition &loc) const; 307 void RaiseError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &loc) const; 308 309 bool Result(bool res) 310 { 311 result_ = res ? RelationResult::TRUE : RelationResult::FALSE; 312 return res; 313 } 314 315 void Result(RelationResult res) 316 { 317 result_ = res; 318 } 319 320 void SetNode(ir::Expression *node) 321 { 322 node_ = node; 323 } 324 325 void SetFlags(TypeRelationFlag flags) 326 { 327 flags_ = flags; 328 } 329 330 void RemoveFlags(TypeRelationFlag flags) 331 { 332 flags_ &= ~flags; 333 } 334 335 ArenaAllocator *Allocator(); 336 337 friend class SavedTypeRelationFlagsContext; 338 339 private: 340 RelationResult CacheLookup(const Type *source, const Type *target, const RelationHolder &holder, 341 RelationType type) const; 342 343 Checker *checker_; 344 RelationResult result_ {}; 345 TypeRelationFlag flags_ {}; 346 ir::Expression *node_ {}; 347 ArenaMap<checker::Type *, int8_t> instantiationRecursionMap_; 348 }; 349 class SavedTypeRelationFlagsContext { 350 public: 351 explicit SavedTypeRelationFlagsContext(TypeRelation *relation, TypeRelationFlag newFlag) 352 : relation_(relation), prev_(relation->flags_) 353 { 354 relation_->flags_ = newFlag; 355 } 356 357 NO_COPY_SEMANTIC(SavedTypeRelationFlagsContext); 358 DEFAULT_MOVE_SEMANTIC(SavedTypeRelationFlagsContext); 359 360 ~SavedTypeRelationFlagsContext() 361 { 362 relation_->flags_ = prev_; 363 } 364 365 private: 366 TypeRelation *relation_; 367 TypeRelationFlag prev_; 368 }; 369 } // namespace ark::es2panda::checker 370 371 #endif /* TYPESCRIPT_TYPES_TYPE_RELATION_H */ 372