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
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
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"
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
)
41 PathProbeCandidate::PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
,
43 EnumItemCandidate enum_field
)
44 : type (type
), ty (ty
), locus (locus
), item (enum_field
)
47 PathProbeCandidate::PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
,
49 ImplItemCandidate impl
)
50 : type (type
), ty (ty
), locus (locus
), item (impl
)
53 PathProbeCandidate::PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
,
55 TraitItemCandidate trait
)
56 : type (type
), ty (ty
), locus (locus
), item (trait
)
60 PathProbeCandidate::as_string () const
62 return "PathProbe candidate TODO - as_string";
66 PathProbeCandidate::is_enum_candidate () const
68 return type
== ENUM_VARIANT
;
72 PathProbeCandidate::is_impl_candidate () const
74 return type
== IMPL_CONST
|| type
== IMPL_TYPE_ALIAS
|| type
== IMPL_FUNC
;
78 PathProbeCandidate::is_trait_candidate () const
80 return type
== TRAIT_ITEM_CONST
|| type
== TRAIT_TYPE_ALIAS
81 || type
== TRAIT_FUNC
;
85 PathProbeCandidate::is_full_trait_item_candidate () const
87 return is_trait_candidate () && item
.trait
.impl
== nullptr;
91 PathProbeCandidate::get_error ()
93 return PathProbeCandidate (ERROR
, nullptr, UNDEF_LOCATION
,
94 ImplItemCandidate
{nullptr, nullptr});
98 PathProbeCandidate::is_error () const
100 return type
== ERROR
;
104 PathProbeCandidate::get_defid () const
109 return item
.enum_field
.variant
->get_defid ();
113 case IMPL_TYPE_ALIAS
:
115 return item
.impl
.impl_item
->get_impl_mappings ().get_defid ();
118 case TRAIT_ITEM_CONST
:
119 case TRAIT_TYPE_ALIAS
:
121 return item
.trait
.item_ref
->get_mappings ().get_defid ();
126 return UNKNOWN_DEFID
;
129 return UNKNOWN_DEFID
;
133 PathProbeCandidate::operator< (const PathProbeCandidate
&c
) const
135 return get_defid () < c
.get_defid ();
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
);
157 if (receiver
->get_kind () == TyTy::TypeKind::ADT
)
159 const TyTy::ADTType
*adt
160 = static_cast<const TyTy::ADTType
*> (receiver
);
162 probe
.process_enum_item_for_candiates (adt
);
165 probe
.process_impl_items_for_candidates ();
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
)
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
)
200 probe
.process_predicate_for_candidates (predicate
,
201 ignore_mandatory_trait_items
);
204 return probe
.candidates
;
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
);
218 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&alias
,
220 PathProbeCandidate candidate
{
221 PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS
, ty
,
222 alias
.get_locus (), impl_item_candidate
};
223 candidates
.insert (std::move (candidate
));
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
);
238 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&constant
,
240 PathProbeCandidate candidate
{
241 PathProbeCandidate::CandidateType::IMPL_CONST
, ty
,
242 constant
.get_locus (), impl_item_candidate
};
243 candidates
.insert (std::move (candidate
));
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
);
258 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&function
,
260 PathProbeCandidate candidate
{PathProbeCandidate::CandidateType::IMPL_FUNC
,
261 ty
, function
.get_locus (),
262 impl_item_candidate
};
263 candidates
.insert (std::move (candidate
));
268 PathProbeType::process_enum_item_for_candiates (const TyTy::ADTType
*adt
)
270 if (specific_trait_id
!= UNKNOWN_DEFID
)
274 if (!adt
->lookup_variant (search
.as_string (), &v
))
277 PathProbeCandidate::EnumItemCandidate enum_item_candidate
{adt
, v
};
278 PathProbeCandidate candidate
{PathProbeCandidate::CandidateType::ENUM_VARIANT
,
280 mappings
->lookup_location (adt
->get_ty_ref ()),
281 enum_item_candidate
};
282 candidates
.insert (std::move (candidate
));
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
);
296 PathProbeType::process_impl_item_candidate (HirId id
, HIR::ImplItem
*item
,
297 HIR::ImplBlock
*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
))
305 if (!receiver
->can_eq (impl_block_ty
, false))
307 if (!impl_block_ty
->can_eq (receiver
, false))
311 // lets visit the impl_item
312 item
->accept_vis (*this);
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
))
324 bool trait_item_needs_implementation
= !trait_item_ref
->is_optional ();
325 if (ignore_mandatory_trait_items
&& trait_item_needs_implementation
)
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
;
334 case TraitItemReference::TraitItemType::CONST
:
335 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST
;
337 case TraitItemReference::TraitItemType::TYPE
:
338 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS
;
341 case TraitItemReference::TraitItemType::ERROR
:
347 const TyTy::TypeBoundPredicate
p (*trait_ref
, BoundPolarity::RegularBound
,
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
,
358 PathProbeCandidate candidate
{candidate_type
, trait_item_tyty
,
359 trait_item_ref
->get_locus (),
360 trait_item_candidate
};
361 candidates
.insert (std::move (candidate
));
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 ())
375 if (ignore_mandatory_trait_items
&& item
.needs_implementation ())
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
;
385 case TraitItemReference::TraitItemType::CONST
:
386 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST
;
388 case TraitItemReference::TraitItemType::TYPE
:
389 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS
;
392 case TraitItemReference::TraitItemType::ERROR
:
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
,
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
)
417 std::map
<DefId
, std::pair
<const TraitReference
*, HIR::ImplBlock
*>> mapper
;
420 mapper
.insert ({ref
.first
->get_mappings ().get_defid (), ref
});
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
});
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
;
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
;
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 ())
475 TraitReference
*resolved
476 = TraitResolver::Lookup (*(impl
->get_trait_ref ().get ()));
477 if (!trait_reference
->is_equal (*resolved
))
480 process_impl_item_candidate (id
, item
, impl
);
485 } // namespace Resolver