Daily bump.
[official-gcc.git] / gcc / rust / typecheck / rust-hir-path-probe.cc
blob9a8b60d4a354a1422e83875f5459c372aba6d6d2
1 // Copyright (C) 2020-2025 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
8 // version.
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.
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 #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"
25 namespace Rust {
26 namespace Resolver {
28 // PathProbeCandidate
30 PathProbeCandidate::Candidate::Candidate (EnumItemCandidate enum_field)
31 : enum_field (enum_field)
34 PathProbeCandidate::Candidate::Candidate (ImplItemCandidate impl) : impl (impl)
37 PathProbeCandidate::Candidate::Candidate (TraitItemCandidate trait)
38 : trait (trait)
41 PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty,
42 location_t locus,
43 EnumItemCandidate enum_field)
44 : type (type), ty (ty), locus (locus), item (enum_field)
47 PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty,
48 location_t locus,
49 ImplItemCandidate impl)
50 : type (type), ty (ty), locus (locus), item (impl)
53 PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty,
54 location_t locus,
55 TraitItemCandidate trait)
56 : type (type), ty (ty), locus (locus), item (trait)
59 std::string
60 PathProbeCandidate::as_string () const
62 return "PathProbe candidate TODO - as_string";
65 bool
66 PathProbeCandidate::is_enum_candidate () const
68 return type == ENUM_VARIANT;
71 bool
72 PathProbeCandidate::is_impl_candidate () const
74 return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC;
77 bool
78 PathProbeCandidate::is_trait_candidate () const
80 return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS
81 || type == TRAIT_FUNC;
84 bool
85 PathProbeCandidate::is_full_trait_item_candidate () const
87 return is_trait_candidate () && item.trait.impl == nullptr;
90 PathProbeCandidate
91 PathProbeCandidate::get_error ()
93 return PathProbeCandidate (ERROR, nullptr, UNDEF_LOCATION,
94 ImplItemCandidate{nullptr, nullptr});
97 bool
98 PathProbeCandidate::is_error () const
100 return type == ERROR;
103 DefId
104 PathProbeCandidate::get_defid () const
106 switch (type)
108 case ENUM_VARIANT:
109 return item.enum_field.variant->get_defid ();
110 break;
112 case IMPL_CONST:
113 case IMPL_TYPE_ALIAS:
114 case IMPL_FUNC:
115 return item.impl.impl_item->get_impl_mappings ().get_defid ();
116 break;
118 case TRAIT_ITEM_CONST:
119 case TRAIT_TYPE_ALIAS:
120 case TRAIT_FUNC:
121 return item.trait.item_ref->get_mappings ().get_defid ();
122 break;
124 case ERROR:
125 default:
126 return UNKNOWN_DEFID;
129 return UNKNOWN_DEFID;
132 bool
133 PathProbeCandidate::operator< (const PathProbeCandidate &c) const
135 return get_defid () < c.get_defid ();
138 // PathProbeType
140 PathProbeType::PathProbeType (const TyTy::BaseType *receiver,
141 const HIR::PathIdentSegment &query,
142 DefId specific_trait_id)
143 : TypeCheckBase (), receiver (receiver), search (query),
144 current_impl (nullptr), specific_trait_id (specific_trait_id)
147 std::set<PathProbeCandidate>
148 PathProbeType::Probe (const 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)
154 PathProbeType probe (receiver, segment_name, specific_trait_id);
155 if (probe_impls)
157 if (receiver->get_kind () == TyTy::TypeKind::ADT)
159 const TyTy::ADTType *adt
160 = static_cast<const TyTy::ADTType *> (receiver);
161 if (adt->is_enum ())
162 probe.process_enum_item_for_candiates (adt);
165 probe.process_impl_items_for_candidates ();
168 if (!probe_bounds)
169 return probe.candidates;
171 if (!probe.is_reciever_generic ())
173 std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds
174 = TypeBoundsProbe::Probe (receiver);
175 for (auto &candidate : probed_bounds)
177 const TraitReference *trait_ref = candidate.first;
178 if (specific_trait_id != UNKNOWN_DEFID)
180 if (trait_ref->get_mappings ().get_defid () != specific_trait_id)
181 continue;
184 HIR::ImplBlock *impl = candidate.second;
185 probe.process_associated_trait_for_candidates (
186 trait_ref, impl, ignore_mandatory_trait_items);
190 for (const TyTy::TypeBoundPredicate &predicate :
191 receiver->get_specified_bounds ())
193 const TraitReference *trait_ref = predicate.get ();
194 if (specific_trait_id != UNKNOWN_DEFID)
196 if (trait_ref->get_mappings ().get_defid () != specific_trait_id)
197 continue;
200 probe.process_predicate_for_candidates (predicate,
201 ignore_mandatory_trait_items);
204 return probe.candidates;
207 void
208 PathProbeType::visit (HIR::TypeAlias &alias)
210 Identifier name = alias.get_new_type_name ();
211 if (search.as_string ().compare (name.as_string ()) == 0)
213 HirId tyid = alias.get_mappings ().get_hirid ();
214 TyTy::BaseType *ty = nullptr;
215 bool ok = query_type (tyid, &ty);
216 rust_assert (ok);
218 PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias,
219 current_impl};
220 PathProbeCandidate candidate{
221 PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty,
222 alias.get_locus (), impl_item_candidate};
223 candidates.insert (std::move (candidate));
227 void
228 PathProbeType::visit (HIR::ConstantItem &constant)
230 Identifier name = constant.get_identifier ();
231 if (search.as_string ().compare (name.as_string ()) == 0)
233 HirId tyid = constant.get_mappings ().get_hirid ();
234 TyTy::BaseType *ty = nullptr;
235 bool ok = query_type (tyid, &ty);
236 rust_assert (ok);
238 PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant,
239 current_impl};
240 PathProbeCandidate candidate{
241 PathProbeCandidate::CandidateType::IMPL_CONST, ty,
242 constant.get_locus (), impl_item_candidate};
243 candidates.insert (std::move (candidate));
247 void
248 PathProbeType::visit (HIR::Function &function)
250 Identifier name = function.get_function_name ();
251 if (search.as_string ().compare (name.as_string ()) == 0)
253 HirId tyid = function.get_mappings ().get_hirid ();
254 TyTy::BaseType *ty = nullptr;
255 bool ok = query_type (tyid, &ty);
256 rust_assert (ok);
258 PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function,
259 current_impl};
260 PathProbeCandidate candidate{PathProbeCandidate::CandidateType::IMPL_FUNC,
261 ty, function.get_locus (),
262 impl_item_candidate};
263 candidates.insert (std::move (candidate));
267 void
268 PathProbeType::process_enum_item_for_candiates (const TyTy::ADTType *adt)
270 if (specific_trait_id != UNKNOWN_DEFID)
271 return;
273 TyTy::VariantDef *v;
274 if (!adt->lookup_variant (search.as_string (), &v))
275 return;
277 PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v};
278 PathProbeCandidate candidate{PathProbeCandidate::CandidateType::ENUM_VARIANT,
279 receiver->clone (),
280 mappings->lookup_location (adt->get_ty_ref ()),
281 enum_item_candidate};
282 candidates.insert (std::move (candidate));
285 void
286 PathProbeType::process_impl_items_for_candidates ()
288 mappings->iterate_impl_items (
289 [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
290 process_impl_item_candidate (id, item, impl);
291 return true;
295 void
296 PathProbeType::process_impl_item_candidate (HirId id, HIR::ImplItem *item,
297 HIR::ImplBlock *impl)
299 current_impl = impl;
300 HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid ();
301 TyTy::BaseType *impl_block_ty = nullptr;
302 if (!query_type (impl_ty_id, &impl_block_ty))
303 return;
305 if (!receiver->can_eq (impl_block_ty, false))
307 if (!impl_block_ty->can_eq (receiver, false))
308 return;
311 // lets visit the impl_item
312 item->accept_vis (*this);
315 void
316 PathProbeType::process_associated_trait_for_candidates (
317 const TraitReference *trait_ref, HIR::ImplBlock *impl,
318 bool ignore_mandatory_trait_items)
320 const TraitItemReference *trait_item_ref = nullptr;
321 if (!trait_ref->lookup_trait_item (search.as_string (), &trait_item_ref))
322 return;
324 bool trait_item_needs_implementation = !trait_item_ref->is_optional ();
325 if (ignore_mandatory_trait_items && trait_item_needs_implementation)
326 return;
328 PathProbeCandidate::CandidateType candidate_type;
329 switch (trait_item_ref->get_trait_item_type ())
331 case TraitItemReference::TraitItemType::FN:
332 candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
333 break;
334 case TraitItemReference::TraitItemType::CONST:
335 candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
336 break;
337 case TraitItemReference::TraitItemType::TYPE:
338 candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
339 break;
341 case TraitItemReference::TraitItemType::ERROR:
342 default:
343 rust_unreachable ();
344 break;
347 const TyTy::TypeBoundPredicate p (*trait_ref, BoundPolarity::RegularBound,
348 UNDEF_LOCATION);
349 TyTy::TypeBoundPredicateItem item (&p, trait_item_ref);
351 TyTy::BaseType *trait_item_tyty = item.get_raw_item ()->get_tyty ();
352 if (receiver->get_kind () != TyTy::DYNAMIC)
353 trait_item_tyty = item.get_tyty_for_receiver (receiver);
355 PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
356 trait_item_ref,
357 impl};
358 PathProbeCandidate candidate{candidate_type, trait_item_tyty,
359 trait_item_ref->get_locus (),
360 trait_item_candidate};
361 candidates.insert (std::move (candidate));
364 void
365 PathProbeType::process_predicate_for_candidates (
366 const TyTy::TypeBoundPredicate &predicate, bool ignore_mandatory_trait_items)
368 const TraitReference *trait_ref = predicate.get ();
370 TyTy::TypeBoundPredicateItem item
371 = predicate.lookup_associated_item (search.as_string ());
372 if (item.is_error ())
373 return;
375 if (ignore_mandatory_trait_items && item.needs_implementation ())
376 return;
378 const TraitItemReference *trait_item_ref = item.get_raw_item ();
379 PathProbeCandidate::CandidateType candidate_type;
380 switch (trait_item_ref->get_trait_item_type ())
382 case TraitItemReference::TraitItemType::FN:
383 candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
384 break;
385 case TraitItemReference::TraitItemType::CONST:
386 candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
387 break;
388 case TraitItemReference::TraitItemType::TYPE:
389 candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
390 break;
392 case TraitItemReference::TraitItemType::ERROR:
393 default:
394 rust_unreachable ();
395 break;
398 TyTy::BaseType *trait_item_tyty = item.get_raw_item ()->get_tyty ();
399 if (receiver->get_kind () != TyTy::DYNAMIC)
400 trait_item_tyty = item.get_tyty_for_receiver (receiver);
402 PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
403 trait_item_ref,
404 nullptr};
405 PathProbeCandidate candidate{candidate_type, trait_item_tyty,
406 trait_item_ref->get_locus (),
407 trait_item_candidate};
408 candidates.insert (std::move (candidate));
411 std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>>
412 PathProbeType::union_bounds (
413 const std::vector<std::pair</*const*/ TraitReference *, HIR::ImplBlock *>> a,
414 const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b)
415 const
417 std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper;
418 for (auto &ref : a)
420 mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
422 for (auto &ref : b)
424 mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
427 std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_set;
428 for (auto it = mapper.begin (); it != mapper.end (); it++)
430 union_set.push_back ({it->second.first, it->second.second});
432 return union_set;
435 bool
436 PathProbeType::is_reciever_generic () const
438 const TyTy::BaseType *root = receiver->get_root ();
439 bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
440 bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
441 return receiver_is_type_param || receiver_is_dyn;
444 // PathProbImplTrait
446 PathProbeImplTrait::PathProbeImplTrait (const TyTy::BaseType *receiver,
447 const HIR::PathIdentSegment &query,
448 const TraitReference *trait_reference)
449 : PathProbeType (receiver, query, UNKNOWN_DEFID),
450 trait_reference (trait_reference)
453 std::set<PathProbeCandidate>
454 PathProbeImplTrait::Probe (const TyTy::BaseType *receiver,
455 const HIR::PathIdentSegment &segment_name,
456 const TraitReference *trait_reference)
458 PathProbeImplTrait probe (receiver, segment_name, trait_reference);
459 // iterate all impls for this trait and receiver
460 // then search for possible candidates using base class behaviours
461 probe.process_trait_impl_items_for_candidates ();
462 return probe.candidates;
465 void
466 PathProbeImplTrait::process_trait_impl_items_for_candidates ()
468 mappings->iterate_impl_items (
469 [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
470 // just need to check if this is an impl block for this trait the next
471 // function checks the receiver
472 if (!impl->has_trait_ref ())
473 return true;
475 TraitReference *resolved
476 = TraitResolver::Lookup (*(impl->get_trait_ref ().get ()));
477 if (!trait_reference->is_equal (*resolved))
478 return true;
480 process_impl_item_candidate (id, item, impl);
481 return true;
485 } // namespace Resolver
486 } // namespace Rust