Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 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 : : #include "rust-diagnostics.h"
20 : : #include "rust-hir-map.h"
21 : : #include "rust-hir-path.h"
22 : : #include "rust-hir-type-check-expr.h"
23 : : #include "rust-hir-type-check-type.h"
24 : : #include "rust-hir-type-check-item.h"
25 : : #include "rust-hir-trait-resolve.h"
26 : : #include "rust-substitution-mapper.h"
27 : : #include "rust-hir-path-probe.h"
28 : : #include "rust-type-util.h"
29 : : #include "rust-hir-type-bounds.h"
30 : : #include "rust-hir-item.h"
31 : : #include "rust-session-manager.h"
32 : : #include "rust-immutable-name-resolution-context.h"
33 : :
34 : : namespace Rust {
35 : : namespace Resolver {
36 : :
37 : : void
38 : 114 : TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
39 : : {
40 : 114 : HIR::QualifiedPathType qual_path_type = expr.get_path_type ();
41 : 114 : TyTy::BaseType *root = TypeCheckType::Resolve (qual_path_type.get_type ());
42 : 114 : if (root->get_kind () == TyTy::TypeKind::ERROR)
43 : : return;
44 : :
45 : 114 : if (!qual_path_type.has_as_clause ())
46 : : {
47 : 34 : NodeId root_resolved_node_id = UNKNOWN_NODEID;
48 : 34 : resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root,
49 : : expr.get_mappings (), expr.get_locus ());
50 : 34 : return;
51 : : }
52 : :
53 : : // Resolve the trait now
54 : 80 : HIR::TypePath &trait_path_ref = qual_path_type.get_trait ();
55 : 80 : TraitReference *trait_ref = TraitResolver::Resolve (trait_path_ref);
56 : 80 : if (trait_ref->is_error ())
57 : : return;
58 : :
59 : : // does this type actually implement this type-bound?
60 : 80 : if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
61 : : return;
62 : :
63 : : // then we need to look at the next segment to create perform the correct
64 : : // projection type
65 : 80 : if (expr.get_segments ().empty ())
66 : : return;
67 : :
68 : : // get the predicate for the bound
69 : 80 : auto specified_bound
70 : 80 : = get_predicate_from_bound (trait_path_ref, qual_path_type.get_type ());
71 : 80 : if (specified_bound.is_error ())
72 : : return;
73 : :
74 : : // inherit the bound
75 : 160 : root->inherit_bounds ({specified_bound});
76 : :
77 : : // lookup the associated item from the specified bound
78 : 80 : HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
79 : 80 : HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
80 : 80 : TyTy::TypeBoundPredicateItem item
81 : 80 : = specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
82 : 80 : if (item.is_error ())
83 : : {
84 : 0 : rust_error_at (item_seg.get_locus (), "unknown associated item");
85 : 0 : return;
86 : : }
87 : :
88 : : // we try to look for the real impl item if possible
89 : 80 : HIR::ImplItem *impl_item = nullptr;
90 : :
91 : : // lookup the associated impl trait for this if we can (it might be generic)
92 : 80 : AssociatedImplTrait *associated_impl_trait
93 : 80 : = lookup_associated_impl_block (specified_bound, root);
94 : 80 : if (associated_impl_trait != nullptr)
95 : : {
96 : 54 : associated_impl_trait->setup_associated_types (root, specified_bound);
97 : :
98 : 76 : for (auto &i :
99 : 76 : associated_impl_trait->get_impl_block ()->get_impl_items ())
100 : : {
101 : 39 : bool found = i->get_impl_item_name ().compare (
102 : 39 : item_seg_identifier.as_string ())
103 : 39 : == 0;
104 : 39 : if (found)
105 : : {
106 : 17 : impl_item = i.get ();
107 : 17 : break;
108 : : }
109 : : }
110 : : }
111 : :
112 : 117 : NodeId root_resolved_node_id = UNKNOWN_NODEID;
113 : 54 : if (impl_item == nullptr)
114 : : {
115 : : // this may be valid as there could be a default trait implementation here
116 : : // and we dont need to worry if the trait item is actually implemented or
117 : : // not because this will have already been validated as part of the trait
118 : : // impl block
119 : 63 : infered = item.get_tyty_for_receiver (root);
120 : 63 : root_resolved_node_id
121 : 63 : = item.get_raw_item ()->get_mappings ().get_nodeid ();
122 : : }
123 : : else
124 : : {
125 : 17 : HirId impl_item_id = impl_item->get_impl_mappings ().get_hirid ();
126 : 17 : bool ok = query_type (impl_item_id, &infered);
127 : 17 : if (!ok)
128 : : {
129 : : // FIXME
130 : : // I think query_type should error if required here anyway
131 : : return;
132 : : }
133 : :
134 : 17 : root_resolved_node_id = impl_item->get_impl_mappings ().get_nodeid ();
135 : : }
136 : :
137 : : // turbo-fish segment path::<ty>
138 : 80 : if (item_seg.has_generic_args ())
139 : : {
140 : 0 : if (!infered->has_substitutions_defined ())
141 : : {
142 : 0 : rust_error_at (item_seg.get_locus (),
143 : : "substitutions not supported for %s",
144 : 0 : infered->as_string ().c_str ());
145 : 0 : infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
146 : 0 : return;
147 : : }
148 : 0 : std::vector<TyTy::Region> regions;
149 : :
150 : 0 : infered = SubstMapper::Resolve (infered, expr.get_locus (),
151 : 0 : &item_seg.get_generic_args (),
152 : 0 : context->regions_from_generic_args (
153 : 0 : item_seg.get_generic_args ()));
154 : 0 : }
155 : :
156 : : // continue on as a path-in-expression
157 : 80 : bool fully_resolved = expr.get_segments ().size () <= 1;
158 : 80 : if (fully_resolved)
159 : : {
160 : 80 : auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> (
161 : 80 : Resolver2_0::ImmutableNameResolutionContext::get ().resolver ());
162 : :
163 : 80 : nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
164 : 80 : Resolver2_0::Definition (root_resolved_node_id));
165 : 80 : return;
166 : : }
167 : :
168 : 0 : resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered,
169 : : expr.get_mappings (), expr.get_locus ());
170 : 194 : }
171 : :
172 : : void
173 : 47785 : TypeCheckExpr::visit (HIR::PathInExpression &expr)
174 : : {
175 : 47785 : NodeId resolved_node_id = UNKNOWN_NODEID;
176 : 47785 : if (expr.is_lang_item ())
177 : : {
178 : 139 : auto lookup
179 : 139 : = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ());
180 : 139 : auto hir_id = mappings.lookup_node_to_hir (lookup);
181 : :
182 : : // We can type resolve the path in expression easily as it is a lang
183 : : // item path, but we still need to setup the various generics and
184 : : // substitutions
185 : :
186 : : // FIXME: We probably need to check *if* the type needs substitutions
187 : : // or not
188 : 139 : if (LangItem::IsEnumVariant (expr.get_lang_item ()))
189 : : {
190 : 106 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
191 : 106 : = mappings.lookup_hir_enumitem (*hir_id);
192 : 212 : bool enum_item_ok = enum_item_lookup.first != nullptr
193 : 106 : && enum_item_lookup.second != nullptr;
194 : 0 : rust_assert (enum_item_ok);
195 : :
196 : 106 : HirId variant_id
197 : 106 : = enum_item_lookup.second->get_mappings ().get_hirid ();
198 : :
199 : 106 : HIR::EnumItem *enum_item = enum_item_lookup.second;
200 : 106 : resolved_node_id = enum_item->get_mappings ().get_nodeid ();
201 : :
202 : : // insert the id of the variant we are resolved to
203 : 106 : context->insert_variant_definition (expr.get_mappings ().get_hirid (),
204 : : variant_id);
205 : :
206 : 106 : query_type (variant_id, &infered);
207 : 106 : infered = SubstMapper::InferSubst (infered, expr.get_locus ());
208 : : }
209 : : else
210 : : {
211 : 33 : TyTy::BaseType *resolved = nullptr;
212 : 33 : context->lookup_type (*hir_id, &resolved);
213 : :
214 : 33 : rust_assert (resolved);
215 : :
216 : 33 : query_type (*hir_id, &infered);
217 : :
218 : 33 : infered = SubstMapper::InferSubst (resolved, expr.get_locus ());
219 : : }
220 : :
221 : : // FIXME: also we probably need to insert resolved types in the name
222 : : // resolver here
223 : : }
224 : : else
225 : : {
226 : 47646 : size_t offset = -1;
227 : 47646 : TyTy::BaseType *tyseg
228 : 47646 : = resolve_root_path (expr, &offset, &resolved_node_id);
229 : 47646 : if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
230 : 44024 : return;
231 : :
232 : 47635 : bool fully_resolved = offset == expr.get_segments ().size ();
233 : 47635 : if (fully_resolved)
234 : : {
235 : 44013 : infered = tyseg;
236 : 44013 : return;
237 : : }
238 : :
239 : 3622 : resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg,
240 : : expr.get_mappings (), expr.get_locus ());
241 : : }
242 : : }
243 : :
244 : : TyTy::BaseType *
245 : 47646 : TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
246 : : NodeId *root_resolved_node_id)
247 : : {
248 : 47646 : TyTy::BaseType *root_tyty = nullptr;
249 : 47646 : *offset = 0;
250 : 100645 : for (size_t i = 0; i < expr.get_num_segments (); i++)
251 : : {
252 : 56631 : HIR::PathExprSegment &seg = expr.get_segments ().at (i);
253 : :
254 : 56631 : bool have_more_segments = (expr.get_num_segments () - 1 != i);
255 : 56631 : bool is_root = *offset == 0;
256 : 56631 : NodeId ast_node_id = seg.get_mappings ().get_nodeid ();
257 : :
258 : 56631 : auto &nr_ctx
259 : 56631 : = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
260 : :
261 : : // lookup the reference_node_id
262 : 56631 : NodeId ref_node_id;
263 : 56631 : if (auto res = nr_ctx.lookup (ast_node_id))
264 : : {
265 : 53007 : ref_node_id = *res;
266 : : }
267 : : else
268 : : {
269 : 3624 : if (root_tyty != nullptr && *offset > 0)
270 : : {
271 : : // then we can let the impl path probe take over now
272 : 3624 : return root_tyty;
273 : : }
274 : :
275 : 2 : rust_error_at (seg.get_locus (),
276 : : "failed to type resolve root segment");
277 : 2 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
278 : : }
279 : :
280 : : // node back to HIR
281 : 53007 : tl::optional<HirId> hid = mappings.lookup_node_to_hir (ref_node_id);
282 : 53007 : if (!hid.has_value ())
283 : : {
284 : 0 : rust_error_at (seg.get_locus (), "456 reverse lookup failure");
285 : 0 : rust_debug_loc (seg.get_locus (),
286 : : "failure with [%s] mappings [%s] ref_node_id [%u]",
287 : 0 : seg.as_string ().c_str (),
288 : 0 : seg.get_mappings ().as_string ().c_str (),
289 : : ref_node_id);
290 : :
291 : 0 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
292 : : }
293 : 53007 : auto ref = hid.value ();
294 : :
295 : 53007 : auto seg_is_module = mappings.lookup_module (ref).has_value ();
296 : 53007 : auto seg_is_crate = mappings.is_local_hirid_crate (ref);
297 : 53007 : auto seg_is_pattern = mappings.lookup_hir_pattern (ref).has_value ();
298 : 53007 : auto seg_is_self = is_root && !have_more_segments
299 : 93111 : && seg.get_segment ().as_string () == "self";
300 : 53007 : if (seg_is_module || seg_is_crate)
301 : : {
302 : : // A::B::C::this_is_a_module::D::E::F
303 : : // ^^^^^^^^^^^^^^^^
304 : : // Currently handling this.
305 : 3615 : if (have_more_segments)
306 : : {
307 : 3614 : (*offset)++;
308 : 3614 : continue;
309 : : }
310 : :
311 : : // In the case of :
312 : : // A::B::C::this_is_a_module
313 : : // ^^^^^^^^^^^^^^^^
314 : : // This is an error, we are not expecting a module.
315 : 1 : rust_error_at (seg.get_locus (), "expected value");
316 : 1 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
317 : : }
318 : :
319 : 49392 : TyTy::BaseType *lookup = nullptr;
320 : 49392 : if (!query_type (ref, &lookup))
321 : : {
322 : 3 : if (is_root || root_tyty == nullptr)
323 : : {
324 : 6 : rust_error_at (expr.get_locus (), ErrorCode::E0425,
325 : : "cannot find value %qs in this scope",
326 : 6 : expr.as_simple_path ().as_string ().c_str ());
327 : :
328 : 3 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
329 : : }
330 : : return root_tyty;
331 : : }
332 : :
333 : : // is it an enum item?
334 : 49389 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
335 : 49389 : = mappings.lookup_hir_enumitem (ref);
336 : 100629 : bool is_enum_item = enum_item_lookup.first != nullptr
337 : 49389 : && enum_item_lookup.second != nullptr;
338 : 1851 : if (is_enum_item)
339 : : {
340 : 1851 : HirId expr_id = expr.get_mappings ().get_hirid ();
341 : 1851 : HirId variant_id
342 : 1851 : = enum_item_lookup.second->get_mappings ().get_hirid ();
343 : 1851 : context->insert_variant_definition (expr_id, variant_id);
344 : : }
345 : :
346 : : // if we have a previous segment type
347 : 49389 : if (root_tyty != nullptr)
348 : : {
349 : : // if this next segment needs substitution we must apply the
350 : : // previous type arguments
351 : : //
352 : : // such as: GenericStruct::<_>::new(123, 456)
353 : 1749 : if (lookup->needs_generic_substitutions ())
354 : : {
355 : 212 : if (!root_tyty->needs_generic_substitutions ())
356 : : {
357 : 212 : auto used_args_in_prev_segment
358 : 212 : = GetUsedSubstArgs::From (root_tyty);
359 : 212 : lookup
360 : 212 : = SubstMapperInternal::Resolve (lookup,
361 : : used_args_in_prev_segment);
362 : 212 : }
363 : : }
364 : : }
365 : :
366 : : // turbo-fish segment path::<ty>
367 : 49389 : if (seg.has_generic_args ())
368 : : {
369 : 792 : lookup = SubstMapper::Resolve (lookup, expr.get_locus (),
370 : 792 : &seg.get_generic_args (),
371 : 792 : context->regions_from_generic_args (
372 : 792 : seg.get_generic_args ()));
373 : 792 : if (lookup->get_kind () == TyTy::TypeKind::ERROR)
374 : 4 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
375 : : }
376 : 48597 : else if (lookup->needs_generic_substitutions () && !seg_is_pattern
377 : 48597 : && !seg_is_self)
378 : : {
379 : 4678 : lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
380 : : }
381 : :
382 : 49385 : *root_resolved_node_id = ref_node_id;
383 : 49385 : *offset = *offset + 1;
384 : 49385 : root_tyty = lookup;
385 : : }
386 : :
387 : : return root_tyty;
388 : : }
389 : :
390 : : void
391 : 3656 : TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
392 : : std::vector<HIR::PathExprSegment> &segments,
393 : : size_t offset, TyTy::BaseType *tyseg,
394 : : const Analysis::NodeMapping &expr_mappings,
395 : : location_t expr_locus)
396 : : {
397 : 3656 : NodeId resolved_node_id = root_resolved_node_id;
398 : 3656 : TyTy::BaseType *prev_segment = tyseg;
399 : 3656 : bool receiver_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
400 : 3656 : bool receiver_is_dyn = prev_segment->get_kind () == TyTy::TypeKind::DYNAMIC;
401 : :
402 : 7310 : for (size_t i = offset; i < segments.size (); i++)
403 : : {
404 : 3656 : HIR::PathExprSegment &seg = segments.at (i);
405 : 3656 : bool probe_impls = !receiver_is_generic;
406 : :
407 : : // probe the path is done in two parts one where we search impls if no
408 : : // candidate is found then we search extensions from traits
409 : 3656 : auto candidates
410 : 3656 : = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
411 : : false /*probe_bounds*/,
412 : 3656 : true /*ignore_mandatory_trait_items*/);
413 : 3656 : if (candidates.size () == 0)
414 : : {
415 : 515 : candidates
416 : 515 : = PathProbeType::Probe (prev_segment, seg.get_segment (), false,
417 : : true /*probe_bounds*/,
418 : 515 : false /*ignore_mandatory_trait_items*/);
419 : :
420 : 515 : if (candidates.size () == 0)
421 : : {
422 : 0 : rust_error_at (
423 : : seg.get_locus (),
424 : : "failed to resolve path segment using an impl Probe");
425 : 0 : return;
426 : : }
427 : : }
428 : :
429 : 3656 : if (candidates.size () > 1)
430 : : {
431 : 1 : ReportMultipleCandidateError::Report (candidates, seg.get_segment (),
432 : : seg.get_locus ());
433 : 1 : return;
434 : : }
435 : :
436 : 3655 : auto &candidate = *candidates.begin ();
437 : 3655 : prev_segment = tyseg;
438 : 3655 : tyseg = candidate.ty;
439 : :
440 : 3655 : HIR::ImplBlock *associated_impl_block = nullptr;
441 : 3655 : if (candidate.is_enum_candidate ())
442 : : {
443 : 2273 : const TyTy::VariantDef *variant = candidate.item.enum_field.variant;
444 : :
445 : 2273 : HirId variant_id = variant->get_id ();
446 : 2273 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
447 : 2273 : = mappings.lookup_hir_enumitem (variant_id);
448 : 4546 : bool enum_item_ok = enum_item_lookup.first != nullptr
449 : 2273 : && enum_item_lookup.second != nullptr;
450 : 0 : rust_assert (enum_item_ok);
451 : :
452 : 2273 : HIR::EnumItem *enum_item = enum_item_lookup.second;
453 : 2273 : resolved_node_id = enum_item->get_mappings ().get_nodeid ();
454 : :
455 : : // insert the id of the variant we are resolved to
456 : 2273 : context->insert_variant_definition (expr_mappings.get_hirid (),
457 : : variant_id);
458 : : }
459 : 1382 : else if (candidate.is_impl_candidate ())
460 : : {
461 : 867 : resolved_node_id
462 : 867 : = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
463 : :
464 : 867 : associated_impl_block = candidate.item.impl.parent;
465 : : }
466 : : else
467 : : {
468 : 515 : resolved_node_id
469 : 515 : = candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
470 : :
471 : : // lookup the associated-impl-trait
472 : 515 : HIR::ImplBlock *impl = candidate.item.trait.impl;
473 : 515 : if (impl != nullptr)
474 : : {
475 : : // get the associated impl block
476 : : associated_impl_block = impl;
477 : : }
478 : : }
479 : :
480 : 3655 : if (associated_impl_block != nullptr && !receiver_is_dyn)
481 : : {
482 : : // associated types
483 : 911 : HirId impl_block_id
484 : 911 : = associated_impl_block->get_mappings ().get_hirid ();
485 : :
486 : 911 : AssociatedImplTrait *associated = nullptr;
487 : 911 : bool found_impl_trait
488 : 911 : = context->lookup_associated_trait_impl (impl_block_id,
489 : : &associated);
490 : :
491 : 911 : auto mappings = TyTy::SubstitutionArgumentMappings::error ();
492 : 911 : TyTy::BaseType *impl_block_ty
493 : 911 : = TypeCheckItem::ResolveImplBlockSelfWithInference (
494 : : *associated_impl_block, seg.get_locus (), &mappings);
495 : :
496 : : // we need to apply the arguments to the segment type so they get
497 : : // unified properly
498 : 911 : if (!mappings.is_error ())
499 : 144 : tyseg = SubstMapperInternal::Resolve (tyseg, mappings);
500 : :
501 : 1822 : prev_segment = unify_site (seg.get_mappings ().get_hirid (),
502 : 911 : TyTy::TyWithLocation (prev_segment),
503 : 911 : TyTy::TyWithLocation (impl_block_ty),
504 : : seg.get_locus ());
505 : 911 : bool ok = prev_segment->get_kind () != TyTy::TypeKind::ERROR;
506 : 911 : if (!ok)
507 : 1 : return;
508 : :
509 : 910 : if (found_impl_trait)
510 : : {
511 : : // we need to setup with apropriate bounds
512 : 165 : HIR::TypePath &bound_path
513 : 165 : = associated->get_impl_block ()->get_trait_ref ();
514 : 165 : const auto &trait_ref = *TraitResolver::Resolve (bound_path);
515 : 165 : rust_assert (!trait_ref.is_error ());
516 : :
517 : 165 : const auto &predicate
518 : 165 : = impl_block_ty->lookup_predicate (trait_ref.get_defid ());
519 : 165 : if (!predicate.is_error ())
520 : 150 : impl_block_ty
521 : 150 : = associated->setup_associated_types (prev_segment, predicate,
522 : : nullptr, false);
523 : 165 : }
524 : 911 : }
525 : :
526 : 3654 : if (seg.has_generic_args ())
527 : : {
528 : 46 : rust_debug_loc (seg.get_locus (), "applying segment generics: %s",
529 : 46 : tyseg->as_string ().c_str ());
530 : 46 : tyseg
531 : 46 : = SubstMapper::Resolve (tyseg, expr_locus, &seg.get_generic_args (),
532 : 46 : context->regions_from_generic_args (
533 : 46 : seg.get_generic_args ()));
534 : 46 : if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
535 : : return;
536 : : }
537 : 3608 : else if (tyseg->needs_generic_substitutions () && !receiver_is_generic)
538 : : {
539 : 415 : location_t locus = seg.get_locus ();
540 : 415 : tyseg = SubstMapper::InferSubst (tyseg, locus);
541 : 415 : if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
542 : : return;
543 : : }
544 : 3656 : }
545 : :
546 : 3654 : rust_assert (resolved_node_id != UNKNOWN_NODEID);
547 : :
548 : 3654 : auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> (
549 : 3654 : Resolver2_0::ImmutableNameResolutionContext::get ().resolver ());
550 : :
551 : 3654 : nr_ctx.map_usage (Resolver2_0::Usage (expr_mappings.get_nodeid ()),
552 : 3654 : Resolver2_0::Definition (resolved_node_id));
553 : :
554 : 3654 : infered = tyseg;
555 : : }
556 : :
557 : : } // namespace Resolver
558 : : } // namespace Rust
|