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