1 // Copyright (C) 2020-2023 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-type-check-item.h"
21 #include "rust-hir-trait-resolve.h"
28 PathProbeCandidate::Candidate::Candidate (EnumItemCandidate enum_field
)
29 : enum_field (enum_field
)
32 PathProbeCandidate::Candidate::Candidate (ImplItemCandidate impl
) : impl (impl
)
35 PathProbeCandidate::Candidate::Candidate (TraitItemCandidate trait
)
39 PathProbeCandidate::PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
,
41 EnumItemCandidate enum_field
)
42 : type (type
), ty (ty
), locus (locus
), item (enum_field
)
45 PathProbeCandidate::PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
,
46 Location locus
, ImplItemCandidate impl
)
47 : type (type
), ty (ty
), locus (locus
), item (impl
)
50 PathProbeCandidate::PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
,
52 TraitItemCandidate trait
)
53 : type (type
), ty (ty
), locus (locus
), item (trait
)
57 PathProbeCandidate::as_string () const
59 return "PathProbe candidate TODO - as_string";
63 PathProbeCandidate::is_enum_candidate () const
65 return type
== ENUM_VARIANT
;
69 PathProbeCandidate::is_impl_candidate () const
71 return type
== IMPL_CONST
|| type
== IMPL_TYPE_ALIAS
|| type
== IMPL_FUNC
;
75 PathProbeCandidate::is_trait_candidate () const
77 return type
== TRAIT_ITEM_CONST
|| type
== TRAIT_TYPE_ALIAS
78 || type
== TRAIT_FUNC
;
82 PathProbeCandidate::is_full_trait_item_candidate () const
84 return is_trait_candidate () && item
.trait
.impl
== nullptr;
88 PathProbeCandidate::get_error ()
90 return PathProbeCandidate (ERROR
, nullptr, Location (),
91 ImplItemCandidate
{nullptr, nullptr});
95 PathProbeCandidate::is_error () const
101 PathProbeCandidate::get_defid () const
106 return item
.enum_field
.variant
->get_defid ();
110 case IMPL_TYPE_ALIAS
:
112 return item
.impl
.impl_item
->get_impl_mappings ().get_defid ();
115 case TRAIT_ITEM_CONST
:
116 case TRAIT_TYPE_ALIAS
:
118 return item
.trait
.item_ref
->get_mappings ().get_defid ();
123 return UNKNOWN_DEFID
;
126 return UNKNOWN_DEFID
;
130 PathProbeCandidate::operator< (const PathProbeCandidate
&c
) const
132 return get_defid () < c
.get_defid ();
137 PathProbeType::PathProbeType (const TyTy::BaseType
*receiver
,
138 const HIR::PathIdentSegment
&query
,
139 DefId specific_trait_id
)
140 : TypeCheckBase (), receiver (receiver
), search (query
),
141 current_impl (nullptr), specific_trait_id (specific_trait_id
)
144 std::set
<PathProbeCandidate
>
145 PathProbeType::Probe (const TyTy::BaseType
*receiver
,
146 const HIR::PathIdentSegment
&segment_name
,
147 bool probe_impls
, bool probe_bounds
,
148 bool ignore_mandatory_trait_items
,
149 DefId specific_trait_id
)
151 PathProbeType
probe (receiver
, segment_name
, specific_trait_id
);
154 if (receiver
->get_kind () == TyTy::TypeKind::ADT
)
156 const TyTy::ADTType
*adt
157 = static_cast<const TyTy::ADTType
*> (receiver
);
159 probe
.process_enum_item_for_candiates (adt
);
162 probe
.process_impl_items_for_candidates ();
166 return probe
.candidates
;
168 if (!probe
.is_reciever_generic ())
170 std::vector
<std::pair
<TraitReference
*, HIR::ImplBlock
*>> probed_bounds
171 = TypeBoundsProbe::Probe (receiver
);
172 for (auto &candidate
: probed_bounds
)
174 const TraitReference
*trait_ref
= candidate
.first
;
175 if (specific_trait_id
!= UNKNOWN_DEFID
)
177 if (trait_ref
->get_mappings ().get_defid () != specific_trait_id
)
181 HIR::ImplBlock
*impl
= candidate
.second
;
182 probe
.process_associated_trait_for_candidates (
183 trait_ref
, impl
, ignore_mandatory_trait_items
);
187 for (const TyTy::TypeBoundPredicate
&predicate
:
188 receiver
->get_specified_bounds ())
190 const TraitReference
*trait_ref
= predicate
.get ();
191 if (specific_trait_id
!= UNKNOWN_DEFID
)
193 if (trait_ref
->get_mappings ().get_defid () != specific_trait_id
)
197 probe
.process_predicate_for_candidates (predicate
,
198 ignore_mandatory_trait_items
);
201 return probe
.candidates
;
205 PathProbeType::visit (HIR::TypeAlias
&alias
)
207 Identifier name
= alias
.get_new_type_name ();
208 if (search
.as_string ().compare (name
) == 0)
210 HirId tyid
= alias
.get_mappings ().get_hirid ();
211 TyTy::BaseType
*ty
= nullptr;
212 bool ok
= query_type (tyid
, &ty
);
215 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&alias
,
217 PathProbeCandidate candidate
{
218 PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS
, ty
,
219 alias
.get_locus (), impl_item_candidate
};
220 candidates
.insert (std::move (candidate
));
225 PathProbeType::visit (HIR::ConstantItem
&constant
)
227 Identifier name
= constant
.get_identifier ();
228 if (search
.as_string ().compare (name
) == 0)
230 HirId tyid
= constant
.get_mappings ().get_hirid ();
231 TyTy::BaseType
*ty
= nullptr;
232 bool ok
= query_type (tyid
, &ty
);
235 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&constant
,
237 PathProbeCandidate candidate
{
238 PathProbeCandidate::CandidateType::IMPL_CONST
, ty
,
239 constant
.get_locus (), impl_item_candidate
};
240 candidates
.insert (std::move (candidate
));
245 PathProbeType::visit (HIR::Function
&function
)
247 Identifier name
= function
.get_function_name ();
248 if (search
.as_string ().compare (name
) == 0)
250 HirId tyid
= function
.get_mappings ().get_hirid ();
251 TyTy::BaseType
*ty
= nullptr;
252 bool ok
= query_type (tyid
, &ty
);
255 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&function
,
257 PathProbeCandidate candidate
{PathProbeCandidate::CandidateType::IMPL_FUNC
,
258 ty
, function
.get_locus (),
259 impl_item_candidate
};
260 candidates
.insert (std::move (candidate
));
265 PathProbeType::process_enum_item_for_candiates (const TyTy::ADTType
*adt
)
267 if (specific_trait_id
!= UNKNOWN_DEFID
)
271 if (!adt
->lookup_variant (search
.as_string (), &v
))
274 PathProbeCandidate::EnumItemCandidate enum_item_candidate
{adt
, v
};
275 PathProbeCandidate candidate
{PathProbeCandidate::CandidateType::ENUM_VARIANT
,
277 mappings
->lookup_location (adt
->get_ty_ref ()),
278 enum_item_candidate
};
279 candidates
.insert (std::move (candidate
));
283 PathProbeType::process_impl_items_for_candidates ()
285 mappings
->iterate_impl_items (
286 [&] (HirId id
, HIR::ImplItem
*item
, HIR::ImplBlock
*impl
) mutable -> bool {
287 process_impl_item_candidate (id
, item
, impl
);
293 PathProbeType::process_impl_item_candidate (HirId id
, HIR::ImplItem
*item
,
294 HIR::ImplBlock
*impl
)
297 HirId impl_ty_id
= impl
->get_type ()->get_mappings ().get_hirid ();
298 TyTy::BaseType
*impl_block_ty
= nullptr;
299 if (!query_type (impl_ty_id
, &impl_block_ty
))
302 if (!receiver
->can_eq (impl_block_ty
, false))
304 if (!impl_block_ty
->can_eq (receiver
, false))
308 // lets visit the impl_item
309 item
->accept_vis (*this);
313 PathProbeType::process_associated_trait_for_candidates (
314 const TraitReference
*trait_ref
, HIR::ImplBlock
*impl
,
315 bool ignore_mandatory_trait_items
)
317 const TraitItemReference
*trait_item_ref
= nullptr;
318 if (!trait_ref
->lookup_trait_item (search
.as_string (), &trait_item_ref
))
321 bool trait_item_needs_implementation
= !trait_item_ref
->is_optional ();
322 if (ignore_mandatory_trait_items
&& trait_item_needs_implementation
)
325 PathProbeCandidate::CandidateType candidate_type
;
326 switch (trait_item_ref
->get_trait_item_type ())
328 case TraitItemReference::TraitItemType::FN
:
329 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_FUNC
;
331 case TraitItemReference::TraitItemType::CONST
:
332 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST
;
334 case TraitItemReference::TraitItemType::TYPE
:
335 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS
;
338 case TraitItemReference::TraitItemType::ERROR
:
344 TyTy::BaseType
*trait_item_tyty
= trait_item_ref
->get_tyty ();
346 // we can substitute the Self with the receiver here
347 if (trait_item_tyty
->get_kind () == TyTy::TypeKind::FNDEF
)
349 TyTy::FnType
*fn
= static_cast<TyTy::FnType
*> (trait_item_tyty
);
350 TyTy::SubstitutionParamMapping
*param
= nullptr;
351 for (auto ¶m_mapping
: fn
->get_substs ())
353 const HIR::TypeParam
&type_param
= param_mapping
.get_generic_param ();
354 if (type_param
.get_type_representation ().compare ("Self") == 0)
356 param
= ¶m_mapping
;
360 rust_assert (param
!= nullptr);
362 std::vector
<TyTy::SubstitutionArg
> mappings
;
363 mappings
.push_back (TyTy::SubstitutionArg (param
, receiver
->clone ()));
365 Location locus
; // FIXME
366 TyTy::SubstitutionArgumentMappings
args (std::move (mappings
), {}, locus
);
367 trait_item_tyty
= SubstMapperInternal::Resolve (trait_item_tyty
, args
);
370 PathProbeCandidate::TraitItemCandidate trait_item_candidate
{trait_ref
,
374 PathProbeCandidate candidate
{candidate_type
, trait_item_tyty
,
375 trait_item_ref
->get_locus (),
376 trait_item_candidate
};
377 candidates
.insert (std::move (candidate
));
381 PathProbeType::process_predicate_for_candidates (
382 const TyTy::TypeBoundPredicate
&predicate
, bool ignore_mandatory_trait_items
)
384 const TraitReference
*trait_ref
= predicate
.get ();
386 TyTy::TypeBoundPredicateItem item
387 = predicate
.lookup_associated_item (search
.as_string ());
388 if (item
.is_error ())
391 if (ignore_mandatory_trait_items
&& item
.needs_implementation ())
394 const TraitItemReference
*trait_item_ref
= item
.get_raw_item ();
395 PathProbeCandidate::CandidateType candidate_type
;
396 switch (trait_item_ref
->get_trait_item_type ())
398 case TraitItemReference::TraitItemType::FN
:
399 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_FUNC
;
401 case TraitItemReference::TraitItemType::CONST
:
402 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST
;
404 case TraitItemReference::TraitItemType::TYPE
:
405 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS
;
408 case TraitItemReference::TraitItemType::ERROR
:
414 TyTy::BaseType
*trait_item_tyty
= item
.get_tyty_for_receiver (receiver
);
415 PathProbeCandidate::TraitItemCandidate trait_item_candidate
{trait_ref
,
418 PathProbeCandidate candidate
{candidate_type
, trait_item_tyty
,
419 trait_item_ref
->get_locus (),
420 trait_item_candidate
};
421 candidates
.insert (std::move (candidate
));
424 std::vector
<std::pair
<const TraitReference
*, HIR::ImplBlock
*>>
425 PathProbeType::union_bounds (
426 const std::vector
<std::pair
</*const*/ TraitReference
*, HIR::ImplBlock
*>> a
,
427 const std::vector
<std::pair
<const TraitReference
*, HIR::ImplBlock
*>> b
)
430 std::map
<DefId
, std::pair
<const TraitReference
*, HIR::ImplBlock
*>> mapper
;
433 mapper
.insert ({ref
.first
->get_mappings ().get_defid (), ref
});
437 mapper
.insert ({ref
.first
->get_mappings ().get_defid (), ref
});
440 std::vector
<std::pair
<const TraitReference
*, HIR::ImplBlock
*>> union_set
;
441 for (auto it
= mapper
.begin (); it
!= mapper
.end (); it
++)
443 union_set
.push_back ({it
->second
.first
, it
->second
.second
});
449 PathProbeType::is_reciever_generic () const
451 const TyTy::BaseType
*root
= receiver
->get_root ();
452 bool receiver_is_type_param
= root
->get_kind () == TyTy::TypeKind::PARAM
;
453 bool receiver_is_dyn
= root
->get_kind () == TyTy::TypeKind::DYNAMIC
;
454 return receiver_is_type_param
|| receiver_is_dyn
;
459 PathProbeImplTrait::PathProbeImplTrait (const TyTy::BaseType
*receiver
,
460 const HIR::PathIdentSegment
&query
,
461 const TraitReference
*trait_reference
)
462 : PathProbeType (receiver
, query
, UNKNOWN_DEFID
),
463 trait_reference (trait_reference
)
466 std::set
<PathProbeCandidate
>
467 PathProbeImplTrait::Probe (const TyTy::BaseType
*receiver
,
468 const HIR::PathIdentSegment
&segment_name
,
469 const TraitReference
*trait_reference
)
471 PathProbeImplTrait
probe (receiver
, segment_name
, trait_reference
);
472 // iterate all impls for this trait and receiver
473 // then search for possible candidates using base class behaviours
474 probe
.process_trait_impl_items_for_candidates ();
475 return probe
.candidates
;
479 PathProbeImplTrait::process_trait_impl_items_for_candidates ()
481 mappings
->iterate_impl_items (
482 [&] (HirId id
, HIR::ImplItem
*item
, HIR::ImplBlock
*impl
) mutable -> bool {
483 // just need to check if this is an impl block for this trait the next
484 // function checks the receiver
485 if (!impl
->has_trait_ref ())
488 TraitReference
*resolved
489 = TraitResolver::Lookup (*(impl
->get_trait_ref ().get ()));
490 if (!trait_reference
->is_equal (*resolved
))
493 process_impl_item_candidate (id
, item
, impl
);
498 } // namespace Resolver