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 #ifndef RUST_HIR_PATH_PROBE_H
20 #define RUST_HIR_PATH_PROBE_H
22 #include "rust-hir-type-check-base.h"
23 #include "rust-hir-full.h"
24 #include "rust-tyty.h"
25 #include "rust-substitution-mapper.h"
26 #include "rust-hir-type-bounds.h"
31 struct PathProbeCandidate
48 struct EnumItemCandidate
50 const TyTy::ADTType
*parent
;
51 const TyTy::VariantDef
*variant
;
54 struct ImplItemCandidate
56 HIR::ImplItem
*impl_item
;
57 HIR::ImplBlock
*parent
;
60 struct TraitItemCandidate
62 const TraitReference
*trait_ref
;
63 const TraitItemReference
*item_ref
;
72 EnumItemCandidate enum_field
;
73 ImplItemCandidate impl
;
74 TraitItemCandidate trait
;
76 Candidate (EnumItemCandidate enum_field
) : enum_field (enum_field
) {}
77 Candidate (ImplItemCandidate impl
) : impl (impl
) {}
78 Candidate (TraitItemCandidate trait
) : trait (trait
) {}
81 PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
, Location locus
,
82 EnumItemCandidate enum_field
)
83 : type (type
), ty (ty
), item (enum_field
)
86 PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
, Location locus
,
87 ImplItemCandidate impl
)
88 : type (type
), ty (ty
), item (impl
)
91 PathProbeCandidate (CandidateType type
, TyTy::BaseType
*ty
, Location locus
,
92 TraitItemCandidate trait
)
93 : type (type
), ty (ty
), item (trait
)
96 std::string
as_string () const
98 return "PathProbe candidate TODO - as_string";
101 bool is_enum_candidate () const { return type
== ENUM_VARIANT
; }
103 bool is_impl_candidate () const
105 return type
== IMPL_CONST
|| type
== IMPL_TYPE_ALIAS
|| type
== IMPL_FUNC
;
108 bool is_trait_candidate () const
110 return type
== TRAIT_ITEM_CONST
|| type
== TRAIT_TYPE_ALIAS
111 || type
== TRAIT_FUNC
;
114 bool is_full_trait_item_candidate () const
116 return is_trait_candidate () && item
.trait
.impl
== nullptr;
119 static PathProbeCandidate
get_error ()
121 return PathProbeCandidate (ERROR
, nullptr, Location (),
122 ImplItemCandidate
{nullptr, nullptr});
125 bool is_error () const { return type
== ERROR
; }
128 class PathProbeType
: public TypeCheckBase
, public HIR::HIRImplVisitor
131 static std::vector
<PathProbeCandidate
>
132 Probe (const TyTy::BaseType
*receiver
,
133 const HIR::PathIdentSegment
&segment_name
, bool probe_impls
,
134 bool probe_bounds
, bool ignore_mandatory_trait_items
,
135 DefId specific_trait_id
= UNKNOWN_DEFID
)
137 PathProbeType
probe (receiver
, segment_name
, specific_trait_id
);
140 if (receiver
->get_kind () == TyTy::TypeKind::ADT
)
142 const TyTy::ADTType
*adt
143 = static_cast<const TyTy::ADTType
*> (receiver
);
145 probe
.process_enum_item_for_candiates (adt
);
148 probe
.process_impl_items_for_candidates ();
152 return probe
.candidates
;
154 if (!probe
.is_reciever_generic ())
156 std::vector
<std::pair
<TraitReference
*, HIR::ImplBlock
*>> probed_bounds
157 = TypeBoundsProbe::Probe (receiver
);
158 for (auto &candidate
: probed_bounds
)
160 const TraitReference
*trait_ref
= candidate
.first
;
161 if (specific_trait_id
!= UNKNOWN_DEFID
)
163 if (trait_ref
->get_mappings ().get_defid ()
164 != specific_trait_id
)
168 HIR::ImplBlock
*impl
= candidate
.second
;
169 probe
.process_associated_trait_for_candidates (
170 trait_ref
, impl
, ignore_mandatory_trait_items
);
174 for (const TyTy::TypeBoundPredicate
&predicate
:
175 receiver
->get_specified_bounds ())
177 const TraitReference
*trait_ref
= predicate
.get ();
178 if (specific_trait_id
!= UNKNOWN_DEFID
)
180 if (trait_ref
->get_mappings ().get_defid () != specific_trait_id
)
184 probe
.process_predicate_for_candidates (predicate
,
185 ignore_mandatory_trait_items
);
188 return probe
.candidates
;
191 void visit (HIR::TypeAlias
&alias
) override
193 Identifier name
= alias
.get_new_type_name ();
194 if (search
.as_string ().compare (name
) == 0)
196 HirId tyid
= alias
.get_mappings ().get_hirid ();
197 TyTy::BaseType
*ty
= nullptr;
198 bool ok
= context
->lookup_type (tyid
, &ty
);
201 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&alias
,
203 PathProbeCandidate candidate
{
204 PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS
, ty
,
205 alias
.get_locus (), impl_item_candidate
};
206 candidates
.push_back (std::move (candidate
));
210 void visit (HIR::ConstantItem
&constant
) override
212 Identifier name
= constant
.get_identifier ();
213 if (search
.as_string ().compare (name
) == 0)
215 HirId tyid
= constant
.get_mappings ().get_hirid ();
216 TyTy::BaseType
*ty
= nullptr;
217 bool ok
= context
->lookup_type (tyid
, &ty
);
220 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&constant
,
222 PathProbeCandidate candidate
{
223 PathProbeCandidate::CandidateType::IMPL_CONST
, ty
,
224 constant
.get_locus (), impl_item_candidate
};
225 candidates
.push_back (std::move (candidate
));
229 void visit (HIR::Function
&function
) override
231 Identifier name
= function
.get_function_name ();
232 if (search
.as_string ().compare (name
) == 0)
234 HirId tyid
= function
.get_mappings ().get_hirid ();
235 TyTy::BaseType
*ty
= nullptr;
236 bool ok
= context
->lookup_type (tyid
, &ty
);
239 PathProbeCandidate::ImplItemCandidate impl_item_candidate
{&function
,
241 PathProbeCandidate candidate
{
242 PathProbeCandidate::CandidateType::IMPL_FUNC
, ty
,
243 function
.get_locus (), impl_item_candidate
};
244 candidates
.push_back (std::move (candidate
));
249 void process_enum_item_for_candiates (const TyTy::ADTType
*adt
)
251 if (specific_trait_id
!= UNKNOWN_DEFID
)
255 if (!adt
->lookup_variant (search
.as_string (), &v
))
258 PathProbeCandidate::EnumItemCandidate enum_item_candidate
{adt
, v
};
259 PathProbeCandidate candidate
{
260 PathProbeCandidate::CandidateType::ENUM_VARIANT
, receiver
->clone (),
261 mappings
->lookup_location (adt
->get_ty_ref ()), enum_item_candidate
};
262 candidates
.push_back (std::move (candidate
));
265 void process_impl_items_for_candidates ()
267 mappings
->iterate_impl_items ([&] (HirId id
, HIR::ImplItem
*item
,
268 HIR::ImplBlock
*impl
) mutable -> bool {
269 process_impl_item_candidate (id
, item
, impl
);
274 void process_impl_item_candidate (HirId id
, HIR::ImplItem
*item
,
275 HIR::ImplBlock
*impl
)
278 HirId impl_ty_id
= impl
->get_type ()->get_mappings ().get_hirid ();
279 TyTy::BaseType
*impl_block_ty
= nullptr;
280 if (!context
->lookup_type (impl_ty_id
, &impl_block_ty
))
283 if (!receiver
->can_eq (impl_block_ty
, false))
285 if (!impl_block_ty
->can_eq (receiver
, false))
289 // lets visit the impl_item
290 item
->accept_vis (*this);
294 process_associated_trait_for_candidates (const TraitReference
*trait_ref
,
295 HIR::ImplBlock
*impl
,
296 bool ignore_mandatory_trait_items
)
298 const TraitItemReference
*trait_item_ref
= nullptr;
299 if (!trait_ref
->lookup_trait_item (search
.as_string (), &trait_item_ref
))
302 bool trait_item_needs_implementation
= !trait_item_ref
->is_optional ();
303 if (ignore_mandatory_trait_items
&& trait_item_needs_implementation
)
306 PathProbeCandidate::CandidateType candidate_type
;
307 switch (trait_item_ref
->get_trait_item_type ())
309 case TraitItemReference::TraitItemType::FN
:
310 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_FUNC
;
312 case TraitItemReference::TraitItemType::CONST
:
313 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST
;
315 case TraitItemReference::TraitItemType::TYPE
:
316 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS
;
319 case TraitItemReference::TraitItemType::ERROR
:
325 TyTy::BaseType
*trait_item_tyty
= trait_item_ref
->get_tyty ();
327 // we can substitute the Self with the receiver here
328 if (trait_item_tyty
->get_kind () == TyTy::TypeKind::FNDEF
)
330 TyTy::FnType
*fn
= static_cast<TyTy::FnType
*> (trait_item_tyty
);
331 TyTy::SubstitutionParamMapping
*param
= nullptr;
332 for (auto ¶m_mapping
: fn
->get_substs ())
334 const HIR::TypeParam
&type_param
335 = param_mapping
.get_generic_param ();
336 if (type_param
.get_type_representation ().compare ("Self") == 0)
338 param
= ¶m_mapping
;
342 rust_assert (param
!= nullptr);
344 std::vector
<TyTy::SubstitutionArg
> mappings
;
345 mappings
.push_back (TyTy::SubstitutionArg (param
, receiver
->clone ()));
347 Location locus
; // FIXME
348 TyTy::SubstitutionArgumentMappings
args (std::move (mappings
), locus
);
349 trait_item_tyty
= SubstMapperInternal::Resolve (trait_item_tyty
, args
);
352 PathProbeCandidate::TraitItemCandidate trait_item_candidate
{trait_ref
,
356 PathProbeCandidate candidate
{candidate_type
, trait_item_tyty
,
357 trait_ref
->get_locus (), trait_item_candidate
};
358 candidates
.push_back (std::move (candidate
));
362 process_predicate_for_candidates (const TyTy::TypeBoundPredicate
&predicate
,
363 bool ignore_mandatory_trait_items
)
365 const TraitReference
*trait_ref
= predicate
.get ();
367 TyTy::TypeBoundPredicateItem item
368 = predicate
.lookup_associated_item (search
.as_string ());
369 if (item
.is_error ())
372 if (ignore_mandatory_trait_items
&& item
.needs_implementation ())
375 const TraitItemReference
*trait_item_ref
= item
.get_raw_item ();
376 PathProbeCandidate::CandidateType candidate_type
;
377 switch (trait_item_ref
->get_trait_item_type ())
379 case TraitItemReference::TraitItemType::FN
:
380 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_FUNC
;
382 case TraitItemReference::TraitItemType::CONST
:
383 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST
;
385 case TraitItemReference::TraitItemType::TYPE
:
386 candidate_type
= PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS
;
389 case TraitItemReference::TraitItemType::ERROR
:
395 TyTy::BaseType
*trait_item_tyty
= item
.get_tyty_for_receiver (receiver
);
396 PathProbeCandidate::TraitItemCandidate trait_item_candidate
{trait_ref
,
399 PathProbeCandidate candidate
{candidate_type
, trait_item_tyty
,
400 trait_item_ref
->get_locus (),
401 trait_item_candidate
};
402 candidates
.push_back (std::move (candidate
));
406 PathProbeType (const TyTy::BaseType
*receiver
,
407 const HIR::PathIdentSegment
&query
, DefId specific_trait_id
)
408 : TypeCheckBase (), receiver (receiver
), search (query
),
409 current_impl (nullptr), specific_trait_id (specific_trait_id
)
412 std::vector
<std::pair
<const TraitReference
*, HIR::ImplBlock
*>>
414 const std::vector
<std::pair
</*const*/ TraitReference
*, HIR::ImplBlock
*>>
416 const std::vector
<std::pair
<const TraitReference
*, HIR::ImplBlock
*>> b
)
419 std::map
<DefId
, std::pair
<const TraitReference
*, HIR::ImplBlock
*>> mapper
;
422 mapper
.insert ({ref
.first
->get_mappings ().get_defid (), ref
});
426 mapper
.insert ({ref
.first
->get_mappings ().get_defid (), ref
});
429 std::vector
<std::pair
<const TraitReference
*, HIR::ImplBlock
*>> union_set
;
430 for (auto it
= mapper
.begin (); it
!= mapper
.end (); it
++)
432 union_set
.push_back ({it
->second
.first
, it
->second
.second
});
437 bool is_reciever_generic () const
439 const TyTy::BaseType
*root
= receiver
->get_root ();
440 bool receiver_is_type_param
= root
->get_kind () == TyTy::TypeKind::PARAM
;
441 bool receiver_is_dyn
= root
->get_kind () == TyTy::TypeKind::DYNAMIC
;
442 return receiver_is_type_param
|| receiver_is_dyn
;
445 const TyTy::BaseType
*receiver
;
446 const HIR::PathIdentSegment
&search
;
447 std::vector
<PathProbeCandidate
> candidates
;
448 HIR::ImplBlock
*current_impl
;
449 DefId specific_trait_id
;
452 class ReportMultipleCandidateError
: private TypeCheckBase
,
453 private HIR::HIRImplVisitor
456 static void Report (std::vector
<PathProbeCandidate
> &candidates
,
457 const HIR::PathIdentSegment
&query
, Location query_locus
)
459 RichLocation
r (query_locus
);
460 ReportMultipleCandidateError
visitor (r
);
461 for (auto &c
: candidates
)
465 case PathProbeCandidate::CandidateType::ERROR
:
466 case PathProbeCandidate::CandidateType::ENUM_VARIANT
:
470 case PathProbeCandidate::CandidateType::IMPL_CONST
:
471 case PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS
:
472 case PathProbeCandidate::CandidateType::IMPL_FUNC
:
473 c
.item
.impl
.impl_item
->accept_vis (visitor
);
476 case PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST
:
477 case PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS
:
478 case PathProbeCandidate::CandidateType::TRAIT_FUNC
:
479 r
.add_range (c
.item
.trait
.item_ref
->get_locus ());
484 rust_error_at (r
, "multiple applicable items in scope for: %s",
485 query
.as_string ().c_str ());
488 void visit (HIR::TypeAlias
&alias
) override
490 r
.add_range (alias
.get_locus ());
493 void visit (HIR::ConstantItem
&constant
) override
495 r
.add_range (constant
.get_locus ());
498 void visit (HIR::Function
&function
) override
500 r
.add_range (function
.get_locus ());
504 ReportMultipleCandidateError (RichLocation
&r
) : TypeCheckBase (), r (r
) {}
509 class PathProbeImplTrait
: public PathProbeType
512 static std::vector
<PathProbeCandidate
>
513 Probe (const TyTy::BaseType
*receiver
,
514 const HIR::PathIdentSegment
&segment_name
,
515 const TraitReference
*trait_reference
)
517 PathProbeImplTrait
probe (receiver
, segment_name
, trait_reference
);
518 // iterate all impls for this trait and receiver
519 // then search for possible candidates using base class behaviours
520 probe
.process_trait_impl_items_for_candidates ();
521 return probe
.candidates
;
525 void process_trait_impl_items_for_candidates ();
527 PathProbeImplTrait (const TyTy::BaseType
*receiver
,
528 const HIR::PathIdentSegment
&query
,
529 const TraitReference
*trait_reference
)
530 : PathProbeType (receiver
, query
, UNKNOWN_DEFID
),
531 trait_reference (trait_reference
)
534 const TraitReference
*trait_reference
;
537 } // namespace Resolver
540 #endif // RUST_HIR_PATH_PROBE_H