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
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
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"
33 class TypeCheckContextItem
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;
68 TypeCheckContextItem ();
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
);
86 * Interned lifetime representation in TyTy
88 * On the HIR->TyTy boundary HIR::Lifetime is interned into this struct.
92 uint32_t interner_index
;
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 ()
108 WARN_UNUSED_RESULT
static constexpr Lifetime
anonymous_lifetime ()
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
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
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
,
188 bool lookup_associated_impl_mapping_for_self (HirId trait_id
,
189 const TyTy::BaseType
*self
,
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 ();
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
*>>
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
;
265 std::map
<HirId
, HirId
> variants
;
267 // unconstrained type-params check
268 std::map
<HirId
, bool> unconstrained
;
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
;
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
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
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;
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
;
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
393 /** The kind of scope that is being pushed. */
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.
402 TypeCheckContext
&ctx
;
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,
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 ();
461 static void Resolve (HIR::Crate
&crate
);
464 class TraitQueryGuard
467 TraitQueryGuard (DefId id
) : id (id
), ctx (*TypeCheckContext::get ())
469 ctx
.insert_trait_query (id
);
472 ~TraitQueryGuard () { ctx
.trait_query_completed (id
); }
476 TypeCheckContext
&ctx
;
479 } // namespace Resolver
482 #endif // RUST_HIR_TYPE_CHECK