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