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 : #include "rust-hir-path-probe.h"
20 : #include "rust-hir-trait-resolve.h"
21 : #include "rust-type-util.h"
22 : #include "rust-hir-type-bounds.h"
23 : #include "rust-hir-full.h"
24 :
25 : namespace Rust {
26 : namespace Resolver {
27 :
28 : // PathProbeCandidate
29 :
30 3 : PathProbeCandidate::Candidate::Candidate (EnumItemCandidate enum_field)
31 3 : : enum_field (enum_field)
32 3 : {}
33 :
34 6379 : PathProbeCandidate::Candidate::Candidate (ImplItemCandidate impl) : impl (impl)
35 6379 : {}
36 :
37 2471 : PathProbeCandidate::Candidate::Candidate (TraitItemCandidate trait)
38 2471 : : trait (trait)
39 2471 : {}
40 :
41 3 : PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty,
42 : location_t locus,
43 3 : EnumItemCandidate enum_field)
44 3 : : type (type), ty (ty), locus (locus), item (enum_field)
45 3 : {}
46 :
47 6379 : PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty,
48 : location_t locus,
49 6379 : ImplItemCandidate impl)
50 6379 : : type (type), ty (ty), locus (locus), item (impl)
51 6379 : {}
52 :
53 2471 : PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty,
54 : location_t locus,
55 2471 : TraitItemCandidate trait)
56 2471 : : type (type), ty (ty), locus (locus), item (trait)
57 2471 : {}
58 :
59 : std::string
60 0 : PathProbeCandidate::as_string () const
61 : {
62 0 : return "PathProbe candidate TODO - as_string";
63 : }
64 :
65 : bool
66 1578 : PathProbeCandidate::is_enum_candidate () const
67 : {
68 1578 : return type == ENUM_VARIANT;
69 : }
70 :
71 : bool
72 11268 : PathProbeCandidate::is_impl_candidate () const
73 : {
74 11268 : return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC;
75 : }
76 :
77 : bool
78 0 : PathProbeCandidate::is_trait_candidate () const
79 : {
80 0 : return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS
81 0 : || type == TRAIT_FUNC;
82 : }
83 :
84 : bool
85 0 : PathProbeCandidate::is_full_trait_item_candidate () const
86 : {
87 0 : return is_trait_candidate () && item.trait.impl == nullptr;
88 : }
89 :
90 : PathProbeCandidate
91 0 : PathProbeCandidate::get_error ()
92 : {
93 0 : return PathProbeCandidate (ERROR, nullptr, UNDEF_LOCATION,
94 0 : ImplItemCandidate{nullptr, nullptr});
95 : }
96 :
97 : bool
98 0 : PathProbeCandidate::is_error () const
99 : {
100 0 : return type == ERROR;
101 : }
102 :
103 : DefId
104 5672 : PathProbeCandidate::get_defid () const
105 : {
106 5672 : switch (type)
107 : {
108 0 : case ENUM_VARIANT:
109 0 : return item.enum_field.variant->get_defid ();
110 4020 : break;
111 :
112 4020 : case IMPL_CONST:
113 4020 : case IMPL_TYPE_ALIAS:
114 4020 : case IMPL_FUNC:
115 4020 : return item.impl.impl_item->get_impl_mappings ().get_defid ();
116 1652 : break;
117 :
118 1652 : case TRAIT_ITEM_CONST:
119 1652 : case TRAIT_TYPE_ALIAS:
120 1652 : case TRAIT_FUNC:
121 1652 : return item.trait.item_ref->get_mappings ().get_defid ();
122 0 : break;
123 :
124 0 : case ERROR:
125 0 : default:
126 0 : return UNKNOWN_DEFID;
127 : }
128 :
129 : return UNKNOWN_DEFID;
130 : }
131 :
132 : bool
133 265 : PathProbeCandidate::operator< (const PathProbeCandidate &c) const
134 : {
135 265 : return get_defid () < c.get_defid ();
136 : }
137 :
138 : // PathProbeType
139 :
140 3401 : PathProbeType::PathProbeType (TyTy::BaseType *receiver,
141 : const HIR::PathIdentSegment &query,
142 3401 : DefId specific_trait_id)
143 3401 : : TypeCheckBase (), receiver (receiver), search (query),
144 3401 : current_impl (nullptr), specific_trait_id (specific_trait_id)
145 3401 : {}
146 :
147 : std::set<PathProbeCandidate>
148 2245 : PathProbeType::Probe (TyTy::BaseType *receiver,
149 : const HIR::PathIdentSegment &segment_name,
150 : bool probe_impls, bool probe_bounds,
151 : bool ignore_mandatory_trait_items,
152 : DefId specific_trait_id)
153 : {
154 2245 : PathProbeType probe (receiver, segment_name, specific_trait_id);
155 2245 : if (probe_impls)
156 : {
157 1347 : if (receiver->get_kind () == TyTy::TypeKind::ADT)
158 : {
159 619 : const TyTy::ADTType *adt
160 : = static_cast<const TyTy::ADTType *> (receiver);
161 619 : if (adt->is_enum ())
162 6 : probe.process_enum_item_for_candiates (adt);
163 : }
164 :
165 1347 : probe.process_impl_items_for_candidates ();
166 : }
167 :
168 2245 : if (!probe_bounds)
169 1580 : return probe.candidates;
170 :
171 665 : if (!probe.is_receiver_generic ())
172 : {
173 59 : std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds
174 59 : = TypeBoundsProbe::Probe (receiver);
175 203 : for (auto &candidate : probed_bounds)
176 : {
177 144 : const TraitReference *trait_ref = candidate.first;
178 144 : if (specific_trait_id != UNKNOWN_DEFID)
179 : {
180 0 : if (trait_ref->get_mappings ().get_defid () != specific_trait_id)
181 0 : continue;
182 : }
183 :
184 144 : HIR::ImplBlock *impl = candidate.second;
185 144 : probe.process_associated_trait_for_candidates (
186 : trait_ref, impl, ignore_mandatory_trait_items);
187 : }
188 59 : }
189 :
190 1497 : for (const TyTy::TypeBoundPredicate &predicate :
191 1497 : receiver->get_specified_bounds ())
192 : {
193 832 : const TraitReference *trait_ref = predicate.get ();
194 832 : if (specific_trait_id != UNKNOWN_DEFID)
195 : {
196 0 : if (trait_ref->get_mappings ().get_defid () != specific_trait_id)
197 0 : continue;
198 : }
199 :
200 832 : probe.process_predicate_for_candidates (predicate,
201 : ignore_mandatory_trait_items);
202 : }
203 :
204 665 : return probe.candidates;
205 2245 : }
206 :
207 : void
208 1253 : PathProbeType::visit (HIR::TypeAlias &alias)
209 : {
210 1253 : Identifier name = alias.get_new_type_name ();
211 2506 : if (search.to_string ().compare (name.as_string ()) == 0)
212 : {
213 14 : HirId tyid = alias.get_mappings ().get_hirid ();
214 14 : TyTy::BaseType *ty = nullptr;
215 14 : if (!query_type (tyid, &ty))
216 0 : return;
217 :
218 14 : PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias,
219 14 : current_impl};
220 14 : PathProbeCandidate candidate{
221 : PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty,
222 14 : alias.get_locus (), impl_item_candidate};
223 14 : candidates.insert (std::move (candidate));
224 : }
225 1253 : }
226 :
227 : void
228 92 : PathProbeType::visit (HIR::ConstantItem &constant)
229 : {
230 92 : Identifier name = constant.get_identifier ();
231 184 : if (search.to_string ().compare (name.as_string ()) == 0)
232 : {
233 52 : HirId tyid = constant.get_mappings ().get_hirid ();
234 52 : TyTy::BaseType *ty = nullptr;
235 52 : if (!query_type (tyid, &ty))
236 0 : return;
237 :
238 52 : PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant,
239 52 : current_impl};
240 52 : PathProbeCandidate candidate{
241 : PathProbeCandidate::CandidateType::IMPL_CONST, ty,
242 52 : constant.get_locus (), impl_item_candidate};
243 52 : candidates.insert (std::move (candidate));
244 : }
245 92 : }
246 :
247 : void
248 7632 : PathProbeType::visit (HIR::Function &function)
249 : {
250 7632 : Identifier name = function.get_function_name ();
251 15264 : if (search.to_string ().compare (name.as_string ()) == 0)
252 : {
253 1801 : HirId tyid = function.get_mappings ().get_hirid ();
254 1801 : TyTy::BaseType *ty = nullptr;
255 1801 : if (!query_type (tyid, &ty))
256 0 : return;
257 :
258 1801 : PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function,
259 1801 : current_impl};
260 1801 : PathProbeCandidate candidate{PathProbeCandidate::CandidateType::IMPL_FUNC,
261 : ty, function.get_locus (),
262 1801 : impl_item_candidate};
263 1801 : candidates.insert (std::move (candidate));
264 : }
265 7632 : }
266 :
267 : void
268 6 : PathProbeType::process_enum_item_for_candiates (const TyTy::ADTType *adt)
269 : {
270 6 : if (specific_trait_id != UNKNOWN_DEFID)
271 3 : return;
272 :
273 6 : TyTy::VariantDef *v;
274 12 : if (!adt->lookup_variant (search.to_string (), &v))
275 : return;
276 :
277 3 : PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v};
278 3 : PathProbeCandidate candidate{PathProbeCandidate::CandidateType::ENUM_VARIANT,
279 3 : receiver->clone (),
280 3 : mappings.lookup_location (adt->get_ty_ref ()),
281 3 : enum_item_candidate};
282 3 : candidates.insert (std::move (candidate));
283 : }
284 :
285 : void
286 1347 : PathProbeType::process_impl_items_for_candidates ()
287 : {
288 1347 : mappings.iterate_impl_items (
289 1347 : [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
290 47385 : process_impl_item_candidate (id, item, impl);
291 47385 : return true;
292 : });
293 1347 : }
294 :
295 : void
296 56618 : PathProbeType::process_impl_item_candidate (HirId id, HIR::ImplItem *item,
297 : HIR::ImplBlock *impl)
298 : {
299 56618 : current_impl = impl;
300 56618 : HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid ();
301 56618 : TyTy::BaseType *impl_block_ty = nullptr;
302 56618 : if (!query_type (impl_ty_id, &impl_block_ty))
303 47641 : return;
304 :
305 56618 : if (!types_compatable (TyTy::TyWithLocation (receiver),
306 56618 : TyTy::TyWithLocation (impl_block_ty),
307 : impl->get_locus (), false))
308 : return;
309 :
310 : // lets visit the impl_item
311 8977 : item->accept_vis (*this);
312 : }
313 :
314 : void
315 144 : PathProbeType::process_associated_trait_for_candidates (
316 : const TraitReference *trait_ref, HIR::ImplBlock *impl,
317 : bool ignore_mandatory_trait_items)
318 : {
319 144 : const TraitItemReference *trait_item_ref = nullptr;
320 288 : if (!trait_ref->lookup_trait_item (search.to_string (), &trait_item_ref))
321 71 : return;
322 :
323 73 : bool trait_item_needs_implementation = !trait_item_ref->is_optional ();
324 73 : if (ignore_mandatory_trait_items && trait_item_needs_implementation)
325 : return;
326 :
327 73 : PathProbeCandidate::CandidateType candidate_type;
328 73 : switch (trait_item_ref->get_trait_item_type ())
329 : {
330 : case TraitItemReference::TraitItemType::FN:
331 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
332 : break;
333 : case TraitItemReference::TraitItemType::CONST:
334 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
335 : break;
336 : case TraitItemReference::TraitItemType::TYPE:
337 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
338 : break;
339 :
340 0 : case TraitItemReference::TraitItemType::ERROR:
341 0 : default:
342 0 : rust_unreachable ();
343 73 : break;
344 : }
345 :
346 73 : const TyTy::TypeBoundPredicate p (*trait_ref, BoundPolarity::RegularBound,
347 73 : UNDEF_LOCATION);
348 146 : TyTy::TypeBoundPredicateItem item (p, trait_item_ref);
349 :
350 73 : TyTy::BaseType *trait_item_tyty = item.get_raw_item ()->get_tyty ();
351 73 : if (receiver->get_kind () != TyTy::DYNAMIC)
352 73 : trait_item_tyty = item.get_tyty_for_receiver (receiver);
353 :
354 73 : PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
355 : trait_item_ref,
356 73 : impl};
357 73 : PathProbeCandidate candidate{candidate_type, trait_item_tyty,
358 : trait_item_ref->get_locus (),
359 73 : trait_item_candidate};
360 73 : candidates.insert (std::move (candidate));
361 : }
362 :
363 : void
364 832 : PathProbeType::process_predicate_for_candidates (
365 : const TyTy::TypeBoundPredicate &predicate, bool ignore_mandatory_trait_items)
366 : {
367 832 : const TraitReference *trait_ref = predicate.get ();
368 :
369 832 : tl::optional<TyTy::TypeBoundPredicateItem> item
370 1664 : = predicate.lookup_associated_item (search.to_string ());
371 832 : if (!item.has_value ())
372 : return;
373 :
374 605 : if (ignore_mandatory_trait_items && item->needs_implementation ())
375 : return;
376 :
377 605 : const TraitItemReference *trait_item_ref = item->get_raw_item ();
378 605 : PathProbeCandidate::CandidateType candidate_type;
379 605 : switch (trait_item_ref->get_trait_item_type ())
380 : {
381 : case TraitItemReference::TraitItemType::FN:
382 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
383 : break;
384 : case TraitItemReference::TraitItemType::CONST:
385 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
386 : break;
387 : case TraitItemReference::TraitItemType::TYPE:
388 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
389 : break;
390 :
391 0 : case TraitItemReference::TraitItemType::ERROR:
392 0 : default:
393 0 : rust_unreachable ();
394 605 : break;
395 : }
396 :
397 605 : TyTy::BaseType *trait_item_tyty = item->get_raw_item ()->get_tyty ();
398 605 : if (receiver->get_kind () != TyTy::DYNAMIC)
399 232 : trait_item_tyty = item->get_tyty_for_receiver (receiver);
400 :
401 605 : PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
402 : trait_item_ref,
403 605 : nullptr};
404 605 : PathProbeCandidate candidate{candidate_type, trait_item_tyty,
405 : trait_item_ref->get_locus (),
406 605 : trait_item_candidate};
407 605 : candidates.insert (std::move (candidate));
408 832 : }
409 :
410 : std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>>
411 0 : PathProbeType::union_bounds (
412 : const std::vector<std::pair</*const*/ TraitReference *, HIR::ImplBlock *>> a,
413 : const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b)
414 : const
415 : {
416 0 : std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper;
417 0 : for (auto &ref : a)
418 : {
419 0 : mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
420 : }
421 0 : for (auto &ref : b)
422 : {
423 0 : mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
424 : }
425 :
426 0 : std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_set;
427 :
428 0 : for (auto it = mapper.begin (); it != mapper.end (); it++)
429 0 : union_set.emplace_back (it->second.first, it->second.second);
430 :
431 0 : return union_set;
432 0 : }
433 :
434 : bool
435 665 : PathProbeType::is_receiver_generic () const
436 : {
437 665 : const TyTy::BaseType *root = receiver->get_root ();
438 665 : bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
439 665 : bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
440 665 : return receiver_is_type_param || receiver_is_dyn;
441 : }
442 :
443 : // PathProbImplTrait
444 :
445 1156 : PathProbeImplTrait::PathProbeImplTrait (TyTy::BaseType *receiver,
446 : const HIR::PathIdentSegment &query,
447 1156 : const TraitReference *trait_reference)
448 : : PathProbeType (receiver, query, UNKNOWN_DEFID),
449 1156 : trait_reference (trait_reference)
450 1156 : {}
451 :
452 : std::set<PathProbeCandidate>
453 1156 : PathProbeImplTrait::Probe (TyTy::BaseType *receiver,
454 : const HIR::PathIdentSegment &segment_name,
455 : const TraitReference *trait_reference)
456 : {
457 1156 : PathProbeImplTrait probe (receiver, segment_name, trait_reference);
458 : // iterate all impls for this trait and receiver
459 : // then search for possible candidates using base class behaviours
460 1156 : probe.process_trait_impl_items_for_candidates ();
461 1156 : return probe.candidates;
462 1156 : }
463 :
464 : void
465 1156 : PathProbeImplTrait::process_trait_impl_items_for_candidates ()
466 : {
467 1156 : mappings.iterate_impl_items (
468 1156 : [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
469 : // just need to check if this is an impl block for this trait the next
470 : // function checks the receiver
471 30105 : if (!impl->has_trait_ref ())
472 : return true;
473 :
474 21600 : TraitReference *resolved = TraitResolver::Lookup (impl->get_trait_ref ());
475 21600 : if (!trait_reference->is_equal (*resolved))
476 : return true;
477 :
478 9233 : process_impl_item_candidate (id, item, impl);
479 9233 : return true;
480 : });
481 1156 : }
482 :
483 : } // namespace Resolver
484 : } // namespace Rust
|