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