Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
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.
9 :
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.
14 :
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/>.
18 :
19 : #ifndef RUST_HIR_TYPE_CHECK
20 : #define RUST_HIR_TYPE_CHECK
21 :
22 : #include "rust-hir-map.h"
23 : #include "rust-mapping-common.h"
24 : #include "rust-tyty.h"
25 : #include "rust-hir-impl-trait-context.h"
26 : #include "rust-hir-trait-reference.h"
27 : #include "rust-stacked-contexts.h"
28 : #include "rust-autoderef.h"
29 : #include "rust-tyty-region.h"
30 : #include "rust-tyty-variance-analysis.h"
31 : #include "rust-system.h"
32 :
33 : namespace Rust {
34 : namespace Resolver {
35 :
36 : class TypeCheckContextItem
37 : {
38 : public:
39 : enum ItemType
40 : {
41 : ITEM,
42 : IMPL_ITEM,
43 : TRAIT_ITEM,
44 : ERROR
45 : };
46 :
47 : TypeCheckContextItem (HIR::Function *item);
48 : TypeCheckContextItem (HIR::ImplBlock &impl_block, HIR::Function *item);
49 : TypeCheckContextItem (HIR::TraitItemFunc *trait_item);
50 : TypeCheckContextItem (const TypeCheckContextItem &other);
51 :
52 : TypeCheckContextItem &operator= (const TypeCheckContextItem &other);
53 :
54 : static TypeCheckContextItem get_error ();
55 :
56 : bool is_error () const;
57 :
58 : ItemType get_type () const;
59 :
60 : HIR::Function *get_item ();
61 :
62 : std::pair<HIR::ImplBlock *, HIR::Function *> &get_impl_item ();
63 :
64 : HIR::TraitItemFunc *get_trait_item ();
65 :
66 : TyTy::FnType *get_context_type ();
67 :
68 : DefId get_defid () const;
69 :
70 : private:
71 : TypeCheckContextItem ();
72 :
73 : union Item
74 : {
75 : HIR::Function *item;
76 : std::pair<HIR::ImplBlock *, HIR::Function *> impl_item;
77 : HIR::TraitItemFunc *trait_item;
78 :
79 : Item (HIR::Function *item);
80 : Item (HIR::ImplBlock *impl_block, HIR::Function *item);
81 : Item (HIR::TraitItemFunc *trait_item);
82 : };
83 :
84 : ItemType type;
85 : Item item;
86 : };
87 :
88 : class TypeCheckBlockContextItem
89 : {
90 : public:
91 : enum ItemType
92 : {
93 : IMPL_BLOCK,
94 : TRAIT
95 : };
96 :
97 : TypeCheckBlockContextItem (HIR::ImplBlock *block);
98 : TypeCheckBlockContextItem (HIR::Trait *trait);
99 :
100 : bool is_impl_block () const;
101 : bool is_trait_block () const;
102 :
103 : HIR::ImplBlock &get_impl_block ();
104 : HIR::Trait &get_trait ();
105 :
106 : private:
107 : union Item
108 : {
109 : HIR::ImplBlock *block;
110 : HIR::Trait *trait;
111 :
112 : Item (HIR::ImplBlock *block);
113 : Item (HIR::Trait *trait);
114 : };
115 : ItemType type;
116 : Item item;
117 : };
118 :
119 : /**
120 : * Interned lifetime representation in TyTy
121 : *
122 : * On the HIR->TyTy boundary HIR::Lifetime is interned into this struct.
123 : */
124 : class Lifetime
125 : {
126 : uint32_t interner_index;
127 :
128 : public:
129 110 : explicit constexpr Lifetime (uint32_t interner_index)
130 : : interner_index (interner_index)
131 : {}
132 :
133 : Lifetime () = default;
134 :
135 9889 : WARN_UNUSED_RESULT bool is_static () const { return interner_index == 0; }
136 :
137 : WARN_UNUSED_RESULT static constexpr Lifetime static_lifetime ()
138 : {
139 : return Lifetime (0);
140 : }
141 :
142 : WARN_UNUSED_RESULT static constexpr Lifetime anonymous_lifetime ()
143 : {
144 : return Lifetime (1);
145 : }
146 :
147 : static constexpr uint32_t FIRST_NAMED_LIFETIME = 2;
148 :
149 358 : friend bool operator== (const Lifetime &lhs, const Lifetime &rhs)
150 : {
151 358 : return lhs.interner_index == rhs.interner_index;
152 : }
153 :
154 : friend bool operator!= (const Lifetime &lhs, const Lifetime &rhs)
155 : {
156 : return !(lhs == rhs);
157 : }
158 :
159 110 : WARN_UNUSED_RESULT Lifetime next () { return Lifetime (interner_index++); }
160 : };
161 :
162 45 : struct DeferredOpOverload
163 : {
164 : HirId expr_id;
165 : LangItem::Kind lang_item_type;
166 : HIR::PathIdentSegment specified_segment;
167 : HIR::OperatorExprMeta op;
168 : TyTy::TyVar result_type;
169 :
170 15 : DeferredOpOverload (HirId expr_id, LangItem::Kind lang_item_type,
171 : HIR::PathIdentSegment specified_segment,
172 : HIR::OperatorExprMeta op, TyTy::TyVar result_type)
173 15 : : expr_id (expr_id), lang_item_type (lang_item_type),
174 15 : specified_segment (specified_segment), op (op), result_type (result_type)
175 15 : {}
176 :
177 45 : DeferredOpOverload (const struct DeferredOpOverload &other)
178 45 : : expr_id (other.expr_id), lang_item_type (other.lang_item_type),
179 45 : specified_segment (other.specified_segment), op (other.op),
180 45 : result_type (other.result_type)
181 45 : {}
182 :
183 0 : DeferredOpOverload &operator= (struct DeferredOpOverload const &other)
184 : {
185 0 : expr_id = other.expr_id;
186 0 : lang_item_type = other.lang_item_type;
187 0 : specified_segment = other.specified_segment;
188 0 : op = other.op;
189 0 : result_type = other.result_type;
190 :
191 0 : return *this;
192 : }
193 : };
194 :
195 : class TypeCheckContext
196 : {
197 : public:
198 : static TypeCheckContext *get ();
199 :
200 : ~TypeCheckContext ();
201 :
202 : bool lookup_builtin (NodeId id, TyTy::BaseType **type);
203 : bool lookup_builtin (std::string name, TyTy::BaseType **type);
204 : void insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type);
205 : const std::vector<std::unique_ptr<TyTy::BaseType>> &get_builtins () const;
206 :
207 : void insert_type (const Analysis::NodeMapping &mappings,
208 : TyTy::BaseType *type);
209 : bool lookup_type (HirId id, TyTy::BaseType **type) const;
210 : void clear_type (TyTy::BaseType *ty);
211 :
212 : void mark_function_body_pending (DefId id);
213 : void clear_function_body_pending (DefId id);
214 : bool function_body_pending (DefId id) const;
215 :
216 : void insert_implicit_type (HirId id, TyTy::BaseType *type);
217 :
218 : bool
219 : lookup_adt_substitution (DefId id,
220 : const TyTy::SubstitutionArgumentMappings &mappings,
221 : TyTy::ADTType **type) const;
222 : void
223 : insert_adt_substitution (DefId id,
224 : const TyTy::SubstitutionArgumentMappings &mappings,
225 : TyTy::ADTType *type);
226 :
227 : void insert_type_by_node_id (NodeId ref, HirId id);
228 : bool lookup_type_by_node_id (NodeId ref, HirId *id);
229 :
230 : bool have_function_context () const;
231 : TyTy::BaseType *peek_return_type ();
232 : TypeCheckContextItem peek_context ();
233 : void push_return_type (TypeCheckContextItem item,
234 : TyTy::BaseType *return_type);
235 : void pop_return_type ();
236 :
237 : void push_expected_type (TyTy::BaseType *expected);
238 : void pop_expected_type ();
239 : TyTy::BaseType *peek_expected_type () const;
240 :
241 : StackedContexts<TypeCheckBlockContextItem> &block_context ();
242 :
243 : void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb);
244 :
245 : bool have_loop_context () const;
246 : void push_new_loop_context (HirId id, location_t locus);
247 : void push_new_while_loop_context (HirId id);
248 : TyTy::BaseType *peek_loop_context ();
249 : TyTy::BaseType *pop_loop_context ();
250 :
251 : void swap_head_loop_context (TyTy::BaseType *val);
252 :
253 : bool
254 : find_matching_impl_trait_frame (const TraitReference &tref,
255 : TyTy::BaseType &self,
256 : struct ImplTraitContextFrame *find) const;
257 : bool have_impl_trait_context () const;
258 : void push_impl_trait_context (struct ImplTraitContextFrame frame);
259 : struct ImplTraitContextFrame pop_impl_trait_context ();
260 : struct ImplTraitContextFrame peek_impl_trait_context ();
261 :
262 : void insert_trait_reference (DefId id, TraitReference &&ref);
263 : bool lookup_trait_reference (DefId id, TraitReference **ref);
264 :
265 : bool insert_associated_trait_impl (HirId id,
266 : AssociatedImplTrait &&associated);
267 : bool lookup_associated_trait_impl (HirId id,
268 : AssociatedImplTrait **associated);
269 :
270 : void insert_associated_type_mapping (HirId id, HirId mapping);
271 : void clear_associated_type_mapping (HirId id);
272 :
273 : // lookup any associated type mappings, the out parameter of mapping is
274 : // allowed to be nullptr which allows this interface to do a simple does exist
275 : // check
276 : bool lookup_associated_type_mapping (HirId id, HirId *mapping);
277 :
278 : void insert_associated_impl_mapping (HirId trait_id,
279 : TyTy::BaseType *impl_type,
280 : HirId impl_id);
281 : bool lookup_associated_impl_mapping_for_self (HirId trait_id,
282 : TyTy::BaseType *self,
283 : HirId *mapping);
284 :
285 : void insert_autoderef_mappings (HirId id,
286 : std::vector<Adjustment> &&adjustments);
287 : bool lookup_autoderef_mappings (HirId id,
288 : std::vector<Adjustment> **adjustments);
289 :
290 : void insert_cast_autoderef_mappings (HirId id,
291 : std::vector<Adjustment> &&adjustments);
292 : bool lookup_cast_autoderef_mappings (HirId id,
293 : std::vector<Adjustment> **adjustments);
294 :
295 : void insert_variant_definition (HirId id, HirId variant);
296 : bool lookup_variant_definition (HirId id, HirId *variant);
297 :
298 : void insert_operator_overload (HirId id, TyTy::FnType *call_site);
299 : bool lookup_operator_overload (HirId id, TyTy::FnType **call);
300 :
301 : void insert_deferred_operator_overload (DeferredOpOverload deferred);
302 : bool lookup_deferred_operator_overload (HirId id,
303 : DeferredOpOverload *deferred);
304 :
305 : void iterate_deferred_operator_overloads (
306 : std::function<bool (HirId, DeferredOpOverload &)> cb);
307 :
308 : void insert_unconstrained_check_marker (HirId id, bool status);
309 : bool have_checked_for_unconstrained (HirId id, bool *result);
310 :
311 : void insert_resolved_predicate (HirId id,
312 : const TyTy::TypeBoundPredicate &predicate);
313 : bool lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result);
314 : std::vector<TyTy::TypeBoundPredicate>
315 : predicates_for_type (const TyTy::BaseType *receiver) const;
316 :
317 : void insert_query (HirId id);
318 : void query_completed (HirId id);
319 : bool query_in_progress (HirId id) const;
320 :
321 : void insert_trait_query (DefId id);
322 : void trait_query_completed (DefId id);
323 : bool trait_query_in_progress (DefId id) const;
324 :
325 : Lifetime intern_lifetime (const HIR::Lifetime &name);
326 : WARN_UNUSED_RESULT tl::optional<Lifetime>
327 : lookup_lifetime (const HIR::Lifetime &lifetime) const;
328 :
329 : WARN_UNUSED_RESULT tl::optional<TyTy::Region>
330 : lookup_and_resolve_lifetime (const HIR::Lifetime &lifetime) const;
331 :
332 : void intern_and_insert_lifetime (const HIR::Lifetime &lifetime);
333 :
334 : WARN_UNUSED_RESULT std::vector<TyTy::Region>
335 : regions_from_generic_args (const HIR::GenericArgs &args) const;
336 :
337 : void compute_inference_variables (bool emit_error);
338 :
339 : TyTy::VarianceAnalysis::CrateCtx &get_variance_analysis_ctx ();
340 :
341 1770 : void push_const_context (void) { const_context++; }
342 1769 : void pop_const_context (void)
343 : {
344 1769 : if (const_context > 0)
345 1769 : const_context--;
346 : }
347 2656 : bool const_context_p (void) { return (const_context > 0); }
348 :
349 : private:
350 : TypeCheckContext ();
351 :
352 : bool compute_infer_var (HirId id, TyTy::BaseType *ty, bool emit_error);
353 : bool compute_ambigious_op_overload (HirId id, DeferredOpOverload &op);
354 :
355 : std::map<NodeId, HirId> node_id_refs;
356 : std::map<HirId, TyTy::BaseType *> resolved;
357 : std::map<std::pair<DefId, std::vector<HirId>>, TyTy::ADTType *>
358 : adt_substitutions;
359 : std::set<DefId> function_bodies_pending;
360 : std::vector<std::unique_ptr<TyTy::BaseType>> builtins;
361 : std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>>
362 : return_type_stack;
363 : std::vector<TyTy::BaseType *> expected_type_stack;
364 : std::vector<TyTy::BaseType *> loop_type_stack;
365 : StackedContexts<TypeCheckBlockContextItem> block_stack;
366 : std::map<DefId, TraitReference> trait_context;
367 : std::map<HirId, AssociatedImplTrait> associated_impl_traits;
368 : std::vector<ImplTraitContextFrame> impl_trait_frame_stack;
369 :
370 : // trait-id -> list of < self-tyty:impl-id>
371 : std::map<HirId, std::vector<std::pair<TyTy::BaseType *, HirId>>>
372 : associated_traits_to_impls;
373 :
374 : std::map<HirId, HirId> associated_type_mappings;
375 :
376 : // adjustment mappings
377 : std::map<HirId, std::vector<Adjustment>> autoderef_mappings;
378 : std::map<HirId, std::vector<Adjustment>> cast_autoderef_mappings;
379 :
380 : // operator overloads
381 : std::map<HirId, TyTy::FnType *> operator_overloads;
382 :
383 : // variants
384 : std::map<HirId, HirId> variants;
385 :
386 : // unconstrained type-params check
387 : std::map<HirId, bool> unconstrained;
388 :
389 : // predicates
390 : std::map<HirId, TyTy::TypeBoundPredicate> predicates;
391 :
392 : // query context lookups
393 : std::set<HirId> querys_in_progress;
394 : std::set<DefId> trait_queries_in_progress;
395 :
396 : // deferred operator overload
397 : std::map<HirId, DeferredOpOverload> deferred_operator_overloads;
398 :
399 : // variance analysis
400 : TyTy::VarianceAnalysis::CrateCtx variance_analysis_ctx;
401 :
402 : unsigned int const_context = 0;
403 :
404 : /** Used to resolve (interned) lifetime names to their bounding scope. */
405 153031 : class LifetimeResolver
406 : {
407 : /**
408 : * The level of nested scopes, where the lifetime was declared.
409 : *
410 : * Index 0 is used for `impl` blocks and is skipped if not explicitly
411 : * requested.
412 : * Index 1 for the top-level of declarations of items.
413 : * Index >1 is used for late-bound lifetimes.
414 : */
415 : using ScopeIndex = size_t;
416 :
417 : static constexpr ScopeIndex IMPL_SCOPE = 0;
418 : static constexpr ScopeIndex ITEM_SCOPE = 1;
419 :
420 : /**
421 : * A reference to a lifetime binder.
422 : *
423 : * This is used to resolve lifetimes to their scope.
424 : */
425 : struct LifetimeBinderRef
426 : {
427 : uint32_t scope; //> Depth of the scope where the lifetime was declared.
428 : uint32_t index; //> Index of the lifetime in the scope.
429 : };
430 :
431 : /**
432 : * A stack of the number of lifetimes declared in each scope.
433 : *
434 : * Used to pop the correct number of lifetimes when leaving a scope.
435 : */
436 : std::stack<uint32_t> binder_size_stack;
437 :
438 : /**
439 : * Merged stack of all lifetimes declared in all scopes.
440 : *
441 : * Use `binder_size_stack` to determine the number of lifetimes in each
442 : * scope.
443 : */
444 : std::vector<std::pair<Lifetime, LifetimeBinderRef>> lifetime_lookup;
445 :
446 : /**
447 : * Whether the current scope is a function body.
448 : *
449 : * In function header, lifetimes are resolved as early-bound, in the body as
450 : * named. This is because the header can be also used in call position.
451 : */
452 : bool is_body = false;
453 :
454 : /** Return the number of the current scope. */
455 970 : WARN_UNUSED_RESULT uint32_t get_current_scope () const
456 : {
457 1910 : return binder_size_stack.size () - 1;
458 : }
459 :
460 : public:
461 : /** Add new declaration of a lifetime. */
462 940 : void insert_mapping (Lifetime placeholder)
463 : {
464 940 : lifetime_lookup.push_back (
465 940 : {placeholder, {get_current_scope (), binder_size_stack.top ()++}});
466 940 : }
467 :
468 : WARN_UNUSED_RESULT tl::optional<TyTy::Region>
469 : resolve (const Lifetime &placeholder) const;
470 :
471 : /** Only to be used by the guard. */
472 102272 : void push_binder () { binder_size_stack.push (0); }
473 : /** Only to be used by the guard. */
474 70593 : void pop_binder () { binder_size_stack.pop (); }
475 :
476 76302 : bool binder_empty () { return binder_size_stack.empty (); }
477 :
478 : /**
479 : * Switch from resolving a function header to a function body.
480 : */
481 7065 : void switch_to_fn_body () { this->is_body = true; }
482 :
483 23924 : size_t get_num_bound_regions () const { return binder_size_stack.top (); }
484 : };
485 :
486 : // lifetime resolving
487 : std::unordered_map<std::string, Lifetime> lifetime_name_interner;
488 : Lifetime next_lifetime_index = Lifetime (Lifetime::FIRST_NAMED_LIFETIME);
489 :
490 : /**
491 : * Stack of lifetime resolvers.
492 : *
493 : * Due to the contruction of the type checker, it is possible to start
494 : * resolution of a new type in the middle of resolving another type. This
495 : * stack isolates the conexts in such cases.
496 : */
497 : std::stack<LifetimeResolver> lifetime_resolver_stack;
498 :
499 : public:
500 24864 : WARN_UNUSED_RESULT LifetimeResolver &get_lifetime_resolver ()
501 : {
502 24864 : rust_assert (!lifetime_resolver_stack.empty ());
503 24864 : return lifetime_resolver_stack.top ();
504 : }
505 :
506 9889 : WARN_UNUSED_RESULT const LifetimeResolver &get_lifetime_resolver () const
507 : {
508 9889 : rust_assert (!lifetime_resolver_stack.empty ());
509 9889 : return lifetime_resolver_stack.top ();
510 : }
511 :
512 : /**
513 : * A guard that pushes a new lifetime resolver on the stack and pops it
514 : * when it goes out of scope.
515 : */
516 : class LifetimeResolverGuard
517 : {
518 : public:
519 : /** The kind of scope that is being pushed. */
520 : enum ScopeKind
521 : {
522 : IMPL_BLOCK_RESOLVER, //> A new `impl` block scope.
523 : RESOLVER, //> A new scope for a function body.
524 : BINDER, //> A new scope for late-bound lifetimes.
525 : };
526 :
527 : private:
528 : TypeCheckContext &ctx;
529 : ScopeKind kind;
530 :
531 : public:
532 76303 : LifetimeResolverGuard (TypeCheckContext &ctx, ScopeKind kind)
533 76303 : : ctx (ctx), kind (kind)
534 : {
535 76303 : if (kind == IMPL_BLOCK_RESOLVER)
536 : {
537 70078 : ctx.lifetime_resolver_stack.push (LifetimeResolver ());
538 : }
539 :
540 76303 : if (kind == RESOLVER)
541 : {
542 25969 : ctx.lifetime_resolver_stack.push (LifetimeResolver ());
543 : // Skip the `impl` block scope.
544 25969 : ctx.lifetime_resolver_stack.top ().push_binder ();
545 : }
546 76303 : rust_assert (!ctx.lifetime_resolver_stack.empty ());
547 76303 : ctx.lifetime_resolver_stack.top ().push_binder ();
548 76303 : }
549 :
550 76302 : ~LifetimeResolverGuard ()
551 : {
552 76302 : rust_assert (!ctx.lifetime_resolver_stack.empty ());
553 76302 : if (!ctx.lifetime_resolver_stack.top ().binder_empty ())
554 70593 : ctx.lifetime_resolver_stack.top ().pop_binder ();
555 76302 : if (kind == RESOLVER)
556 : {
557 25969 : ctx.lifetime_resolver_stack.pop ();
558 : }
559 76302 : }
560 : };
561 :
562 : /** Start new late bound lifetime scope. */
563 15278 : WARN_UNUSED_RESULT LifetimeResolverGuard push_lifetime_binder ()
564 : {
565 15278 : return LifetimeResolverGuard (*this, LifetimeResolverGuard::BINDER);
566 : }
567 :
568 : /** Start new function body scope. */
569 : WARN_UNUSED_RESULT LifetimeResolverGuard
570 61008 : push_clean_lifetime_resolver (bool is_impl_block = false)
571 : {
572 61008 : return LifetimeResolverGuard (*this,
573 : is_impl_block
574 : ? LifetimeResolverGuard::IMPL_BLOCK_RESOLVER
575 61008 : : LifetimeResolverGuard::RESOLVER);
576 : }
577 :
578 : /** Switch from resolving a function header to a function body. */
579 7065 : void switch_to_fn_body ()
580 : {
581 7065 : this->lifetime_resolver_stack.top ().switch_to_fn_body ();
582 : }
583 : };
584 :
585 : class TypeResolution
586 : {
587 : public:
588 : static void Resolve (HIR::Crate &crate);
589 : };
590 :
591 : class TraitQueryGuard
592 : {
593 : public:
594 4257 : TraitQueryGuard (DefId id) : id (id), ctx (*TypeCheckContext::get ())
595 : {
596 4257 : ctx.insert_trait_query (id);
597 4257 : }
598 :
599 4257 : ~TraitQueryGuard () { ctx.trait_query_completed (id); }
600 :
601 : private:
602 : DefId id;
603 : TypeCheckContext &ctx;
604 : };
605 :
606 : template <typename T> class ScopedPush
607 : {
608 : public:
609 2155835 : ScopedPush (std::vector<T> &stack, T value, bool enabled = true)
610 2155835 : : stack (stack), enabled (enabled)
611 : {
612 48675 : if (enabled)
613 2155835 : stack.push_back (value);
614 : }
615 :
616 2155835 : ~ScopedPush ()
617 : {
618 48675 : if (enabled)
619 2155835 : stack.pop_back ();
620 : }
621 :
622 3358706 : static bool contains (const std::vector<T> &stack, const T &value)
623 : {
624 6668695 : return std::find (stack.begin (), stack.end (), value) != stack.end ();
625 : }
626 :
627 : private:
628 : std::vector<T> &stack;
629 : bool enabled;
630 : };
631 :
632 : class ImplTraitFrameGuard
633 : {
634 : public:
635 13554 : ImplTraitFrameGuard (ImplTraitContextFrame frame)
636 13554 : : ctx (*TypeCheckContext::get ())
637 : {
638 13554 : ctx.push_impl_trait_context (frame);
639 13554 : }
640 :
641 13554 : ~ImplTraitFrameGuard () { ctx.pop_impl_trait_context (); }
642 :
643 : private:
644 : Resolver::TypeCheckContext &ctx;
645 : };
646 :
647 : } // namespace Resolver
648 : } // namespace Rust
649 :
650 : #endif // RUST_HIR_TYPE_CHECK
|