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