• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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