libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / typecheck / rust-hir-type-check.h
blobc85a83955b9c88c152c8de036449910b17866824
1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
5 // GCC is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3, or (at your option) any later
8 // version.
10 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 // for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with GCC; see the file COPYING3. If not see
17 // <http://www.gnu.org/licenses/>.
19 #ifndef RUST_HIR_TYPE_CHECK
20 #define RUST_HIR_TYPE_CHECK
22 #include "rust-hir-map.h"
23 #include "rust-tyty.h"
24 #include "rust-hir-trait-reference.h"
25 #include "rust-autoderef.h"
26 #include "rust-tyty-region.h"
27 #include "rust-tyty-variance-analysis.h"
28 #include "rust-system.h"
30 namespace Rust {
31 namespace Resolver {
33 class TypeCheckContextItem
35 public:
36 enum ItemType
38 ITEM,
39 IMPL_ITEM,
40 TRAIT_ITEM,
41 ERROR
44 TypeCheckContextItem (HIR::Function *item);
45 TypeCheckContextItem (HIR::ImplBlock *impl_block, HIR::Function *item);
46 TypeCheckContextItem (HIR::TraitItemFunc *trait_item);
47 TypeCheckContextItem (const TypeCheckContextItem &other);
49 TypeCheckContextItem &operator= (const TypeCheckContextItem &other);
51 static TypeCheckContextItem get_error ();
53 bool is_error () const;
55 ItemType get_type () const;
57 HIR::Function *get_item ();
59 std::pair<HIR::ImplBlock *, HIR::Function *> &get_impl_item ();
61 HIR::TraitItemFunc *get_trait_item ();
63 TyTy::FnType *get_context_type ();
65 DefId get_defid () const;
67 private:
68 TypeCheckContextItem ();
70 union Item
72 HIR::Function *item;
73 std::pair<HIR::ImplBlock *, HIR::Function *> impl_item;
74 HIR::TraitItemFunc *trait_item;
76 Item (HIR::Function *item);
77 Item (HIR::ImplBlock *impl_block, HIR::Function *item);
78 Item (HIR::TraitItemFunc *trait_item);
81 ItemType type;
82 Item item;
85 /**
86 * Interned lifetime representation in TyTy
88 * On the HIR->TyTy boundary HIR::Lifetime is interned into this struct.
90 class Lifetime
92 uint32_t interner_index;
94 public:
95 explicit constexpr Lifetime (uint32_t interner_index)
96 : interner_index (interner_index)
99 Lifetime () = default;
101 WARN_UNUSED_RESULT bool is_static () const { return interner_index == 0; }
103 WARN_UNUSED_RESULT static constexpr Lifetime static_lifetime ()
105 return Lifetime (0);
108 WARN_UNUSED_RESULT static constexpr Lifetime anonymous_lifetime ()
110 return Lifetime (1);
113 static constexpr uint32_t FIRST_NAMED_LIFETIME = 2;
115 friend bool operator== (const Lifetime &lhs, const Lifetime &rhs)
117 return lhs.interner_index == rhs.interner_index;
120 friend bool operator!= (const Lifetime &lhs, const Lifetime &rhs)
122 return !(lhs == rhs);
125 WARN_UNUSED_RESULT Lifetime next () { return Lifetime (interner_index++); }
128 class TypeCheckContext
130 public:
131 static TypeCheckContext *get ();
133 ~TypeCheckContext ();
135 bool lookup_builtin (NodeId id, TyTy::BaseType **type);
136 bool lookup_builtin (std::string name, TyTy::BaseType **type);
137 void insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type);
139 void insert_type (const Analysis::NodeMapping &mappings,
140 TyTy::BaseType *type);
141 void insert_implicit_type (TyTy::BaseType *type);
142 bool lookup_type (HirId id, TyTy::BaseType **type) const;
143 void clear_type (TyTy::BaseType *ty);
145 void insert_implicit_type (HirId id, TyTy::BaseType *type);
147 void insert_type_by_node_id (NodeId ref, HirId id);
148 bool lookup_type_by_node_id (NodeId ref, HirId *id);
150 bool have_function_context () const;
151 TyTy::BaseType *peek_return_type ();
152 TypeCheckContextItem peek_context ();
153 void push_return_type (TypeCheckContextItem item,
154 TyTy::BaseType *return_type);
155 void pop_return_type ();
156 void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb);
158 bool have_loop_context () const;
159 void push_new_loop_context (HirId id, location_t locus);
160 void push_new_while_loop_context (HirId id);
161 TyTy::BaseType *peek_loop_context ();
162 TyTy::BaseType *pop_loop_context ();
164 void swap_head_loop_context (TyTy::BaseType *val);
166 void insert_trait_reference (DefId id, TraitReference &&ref);
167 bool lookup_trait_reference (DefId id, TraitReference **ref);
169 void insert_receiver (HirId id, TyTy::BaseType *t);
170 bool lookup_receiver (HirId id, TyTy::BaseType **ref);
172 void insert_associated_trait_impl (HirId id,
173 AssociatedImplTrait &&associated);
174 bool lookup_associated_trait_impl (HirId id,
175 AssociatedImplTrait **associated);
177 void insert_associated_type_mapping (HirId id, HirId mapping);
178 void clear_associated_type_mapping (HirId id);
180 // lookup any associated type mappings, the out parameter of mapping is
181 // allowed to be nullptr which allows this interface to do a simple does exist
182 // check
183 bool lookup_associated_type_mapping (HirId id, HirId *mapping);
185 void insert_associated_impl_mapping (HirId trait_id,
186 const TyTy::BaseType *impl_type,
187 HirId impl_id);
188 bool lookup_associated_impl_mapping_for_self (HirId trait_id,
189 const TyTy::BaseType *self,
190 HirId *mapping);
192 void insert_autoderef_mappings (HirId id,
193 std::vector<Adjustment> &&adjustments);
194 bool lookup_autoderef_mappings (HirId id,
195 std::vector<Adjustment> **adjustments);
197 void insert_cast_autoderef_mappings (HirId id,
198 std::vector<Adjustment> &&adjustments);
199 bool lookup_cast_autoderef_mappings (HirId id,
200 std::vector<Adjustment> **adjustments);
202 void insert_variant_definition (HirId id, HirId variant);
203 bool lookup_variant_definition (HirId id, HirId *variant);
205 void insert_operator_overload (HirId id, TyTy::FnType *call_site);
206 bool lookup_operator_overload (HirId id, TyTy::FnType **call);
208 void insert_unconstrained_check_marker (HirId id, bool status);
209 bool have_checked_for_unconstrained (HirId id, bool *result);
211 void insert_resolved_predicate (HirId id, TyTy::TypeBoundPredicate predicate);
212 bool lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result);
214 void insert_query (HirId id);
215 void query_completed (HirId id);
216 bool query_in_progress (HirId id) const;
218 void insert_trait_query (DefId id);
219 void trait_query_completed (DefId id);
220 bool trait_query_in_progress (DefId id) const;
222 Lifetime intern_lifetime (const HIR::Lifetime &name);
223 WARN_UNUSED_RESULT tl::optional<Lifetime>
224 lookup_lifetime (const HIR::Lifetime &lifetime) const;
226 WARN_UNUSED_RESULT tl::optional<TyTy::Region>
227 lookup_and_resolve_lifetime (const HIR::Lifetime &lifetime) const;
229 void intern_and_insert_lifetime (const HIR::Lifetime &lifetime);
231 WARN_UNUSED_RESULT std::vector<TyTy::Region>
232 regions_from_generic_args (const HIR::GenericArgs &args) const;
234 void compute_inference_variables (bool error);
236 TyTy::VarianceAnalysis::CrateCtx &get_variance_analysis_ctx ();
238 private:
239 TypeCheckContext ();
241 std::map<NodeId, HirId> node_id_refs;
242 std::map<HirId, TyTy::BaseType *> resolved;
243 std::vector<std::unique_ptr<TyTy::BaseType>> builtins;
244 std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>>
245 return_type_stack;
246 std::vector<TyTy::BaseType *> loop_type_stack;
247 std::map<DefId, TraitReference> trait_context;
248 std::map<HirId, TyTy::BaseType *> receiver_context;
249 std::map<HirId, AssociatedImplTrait> associated_impl_traits;
251 // trait-id -> list of < self-tyty:impl-id>
252 std::map<HirId, std::vector<std::pair<const TyTy::BaseType *, HirId>>>
253 associated_traits_to_impls;
255 std::map<HirId, HirId> associated_type_mappings;
257 // adjustment mappings
258 std::map<HirId, std::vector<Adjustment>> autoderef_mappings;
259 std::map<HirId, std::vector<Adjustment>> cast_autoderef_mappings;
261 // operator overloads
262 std::map<HirId, TyTy::FnType *> operator_overloads;
264 // variants
265 std::map<HirId, HirId> variants;
267 // unconstrained type-params check
268 std::map<HirId, bool> unconstrained;
270 // predicates
271 std::map<HirId, TyTy::TypeBoundPredicate> predicates;
273 // query context lookups
274 std::set<HirId> querys_in_progress;
275 std::set<DefId> trait_queries_in_progress;
277 // variance analysis
278 TyTy::VarianceAnalysis::CrateCtx variance_analysis_ctx;
280 /** Used to resolve (interned) lifetime names to their bounding scope. */
281 class LifetimeResolver
284 * The level of nested scopes, where the lifetime was declared.
286 * Index 0 is used for `impl` blocks and is skipped if not explicitly
287 * requested.
288 * Index 1 for the top-level of declarations of items.
289 * Index >1 is used for late-bound lifetimes.
291 using ScopeIndex = size_t;
293 static constexpr ScopeIndex IMPL_SCOPE = 0;
294 static constexpr ScopeIndex ITEM_SCOPE = 1;
297 * A reference to a lifetime binder.
299 * This is used to resolve lifetimes to their scope.
301 struct LifetimeBinderRef
303 uint32_t scope; //> Depth of the scope where the lifetime was declared.
304 uint32_t index; //> Index of the lifetime in the scope.
308 * A stack of the number of lifetimes declared in each scope.
310 * Used to pop the correct number of lifetimes when leaving a scope.
312 std::stack<uint32_t> binder_size_stack;
315 * Merged stack of all lifetimes declared in all scopes.
317 * Use `binder_size_stack` to determine the number of lifetimes in each
318 * scope.
320 std::vector<std::pair<Lifetime, LifetimeBinderRef>> lifetime_lookup;
323 * Whether the current scope is a function body.
325 * In function header, lifetimes are resolved as early-bound, in the body as
326 * named. This is because the header can be also used in call position.
328 bool is_body = false;
330 /** Return the number of the current scope. */
331 WARN_UNUSED_RESULT uint32_t get_current_scope () const
333 return binder_size_stack.size () - 1;
336 public:
337 /** Add new declaration of a lifetime. */
338 void insert_mapping (Lifetime placeholder)
340 lifetime_lookup.push_back (
341 {placeholder, {get_current_scope (), binder_size_stack.top ()++}});
344 WARN_UNUSED_RESULT tl::optional<TyTy::Region>
345 resolve (const Lifetime &placeholder) const;
347 /** Only to be used by the guard. */
348 void push_binder () { binder_size_stack.push (0); }
349 /** Only to be used by the guard. */
350 void pop_binder () { binder_size_stack.pop (); }
353 * Switch from resolving a function header to a function body.
355 void switch_to_fn_body () { this->is_body = true; }
357 size_t get_num_bound_regions () const { return binder_size_stack.top (); }
360 // lifetime resolving
361 std::unordered_map<std::string, Lifetime> lifetime_name_interner;
362 Lifetime next_lifetime_index = Lifetime (Lifetime::FIRST_NAMED_LIFETIME);
365 * Stack of lifetime resolvers.
367 * Due to the contruction of the type checker, it is possible to start
368 * resolution of a new type in the middle of resolving another type. This
369 * stack isolates the conexts in such cases.
371 std::stack<LifetimeResolver> lifetime_resolver_stack;
373 public:
374 WARN_UNUSED_RESULT LifetimeResolver &get_lifetime_resolver ()
376 rust_assert (!lifetime_resolver_stack.empty ());
377 return lifetime_resolver_stack.top ();
380 WARN_UNUSED_RESULT const LifetimeResolver &get_lifetime_resolver () const
382 rust_assert (!lifetime_resolver_stack.empty ());
383 return lifetime_resolver_stack.top ();
387 * A guard that pushes a new lifetime resolver on the stack and pops it
388 * when it goes out of scope.
390 class LifetimeResolverGuard
392 public:
393 /** The kind of scope that is being pushed. */
394 enum ScopeKind
396 IMPL_BLOCK_RESOLVER, //> A new `impl` block scope.
397 RESOLVER, //> A new scope for a function body.
398 BINDER, //> A new scope for late-bound lifetimes.
401 private:
402 TypeCheckContext &ctx;
403 ScopeKind kind;
405 public:
406 LifetimeResolverGuard (TypeCheckContext &ctx, ScopeKind kind)
407 : ctx (ctx), kind (kind)
409 if (kind == IMPL_BLOCK_RESOLVER)
411 ctx.lifetime_resolver_stack.push (LifetimeResolver ());
414 if (kind == RESOLVER)
416 ctx.lifetime_resolver_stack.push (LifetimeResolver ());
417 // Skip the `impl` block scope.
418 ctx.lifetime_resolver_stack.top ().push_binder ();
420 rust_assert (!ctx.lifetime_resolver_stack.empty ());
421 ctx.lifetime_resolver_stack.top ().push_binder ();
424 ~LifetimeResolverGuard ()
426 rust_assert (!ctx.lifetime_resolver_stack.empty ());
427 ctx.lifetime_resolver_stack.top ().pop_binder ();
428 if (kind == RESOLVER)
430 ctx.lifetime_resolver_stack.pop ();
435 /** Start new late bound lifetime scope. */
436 WARN_UNUSED_RESULT LifetimeResolverGuard push_lifetime_binder ()
438 return LifetimeResolverGuard (*this, LifetimeResolverGuard::BINDER);
441 /** Start new function body scope. */
442 WARN_UNUSED_RESULT LifetimeResolverGuard
443 push_clean_lifetime_resolver (bool is_impl_block = false)
445 return LifetimeResolverGuard (*this,
446 is_impl_block
447 ? LifetimeResolverGuard::IMPL_BLOCK_RESOLVER
448 : LifetimeResolverGuard::RESOLVER);
451 /** Switch from resolving a function header to a function body. */
452 void switch_to_fn_body ()
454 this->lifetime_resolver_stack.top ().switch_to_fn_body ();
458 class TypeResolution
460 public:
461 static void Resolve (HIR::Crate &crate);
464 class TraitQueryGuard
466 public:
467 TraitQueryGuard (DefId id) : id (id), ctx (*TypeCheckContext::get ())
469 ctx.insert_trait_query (id);
472 ~TraitQueryGuard () { ctx.trait_query_completed (id); }
474 private:
475 DefId id;
476 TypeCheckContext &ctx;
479 } // namespace Resolver
480 } // namespace Rust
482 #endif // RUST_HIR_TYPE_CHECK