Require target lra in gcc.dg/pr108095.c
[official-gcc.git] / gcc / rust / typecheck / rust-hir-path-probe.cc
blobdae4c014d02dffc74a4125393986d272f2226f6f
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
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-type-check-item.h"
21 #include "rust-hir-trait-resolve.h"
23 namespace Rust {
24 namespace Resolver {
26 // PathProbeCandidate
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)
36 : trait (trait)
39 PathProbeCandidate::PathProbeCandidate (CandidateType type, TyTy::BaseType *ty,
40 Location locus,
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,
51 Location locus,
52 TraitItemCandidate trait)
53 : type (type), ty (ty), locus (locus), item (trait)
56 std::string
57 PathProbeCandidate::as_string () const
59 return "PathProbe candidate TODO - as_string";
62 bool
63 PathProbeCandidate::is_enum_candidate () const
65 return type == ENUM_VARIANT;
68 bool
69 PathProbeCandidate::is_impl_candidate () const
71 return type == IMPL_CONST || type == IMPL_TYPE_ALIAS || type == IMPL_FUNC;
74 bool
75 PathProbeCandidate::is_trait_candidate () const
77 return type == TRAIT_ITEM_CONST || type == TRAIT_TYPE_ALIAS
78 || type == TRAIT_FUNC;
81 bool
82 PathProbeCandidate::is_full_trait_item_candidate () const
84 return is_trait_candidate () && item.trait.impl == nullptr;
87 PathProbeCandidate
88 PathProbeCandidate::get_error ()
90 return PathProbeCandidate (ERROR, nullptr, Location (),
91 ImplItemCandidate{nullptr, nullptr});
94 bool
95 PathProbeCandidate::is_error () const
97 return type == ERROR;
100 DefId
101 PathProbeCandidate::get_defid () const
103 switch (type)
105 case ENUM_VARIANT:
106 return item.enum_field.variant->get_defid ();
107 break;
109 case IMPL_CONST:
110 case IMPL_TYPE_ALIAS:
111 case IMPL_FUNC:
112 return item.impl.impl_item->get_impl_mappings ().get_defid ();
113 break;
115 case TRAIT_ITEM_CONST:
116 case TRAIT_TYPE_ALIAS:
117 case TRAIT_FUNC:
118 return item.trait.item_ref->get_mappings ().get_defid ();
119 break;
121 case ERROR:
122 default:
123 return UNKNOWN_DEFID;
126 return UNKNOWN_DEFID;
129 bool
130 PathProbeCandidate::operator< (const PathProbeCandidate &c) const
132 return get_defid () < c.get_defid ();
135 // PathProbeType
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);
152 if (probe_impls)
154 if (receiver->get_kind () == TyTy::TypeKind::ADT)
156 const TyTy::ADTType *adt
157 = static_cast<const TyTy::ADTType *> (receiver);
158 if (adt->is_enum ())
159 probe.process_enum_item_for_candiates (adt);
162 probe.process_impl_items_for_candidates ();
165 if (!probe_bounds)
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)
178 continue;
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)
194 continue;
197 probe.process_predicate_for_candidates (predicate,
198 ignore_mandatory_trait_items);
201 return probe.candidates;
204 void
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);
213 rust_assert (ok);
215 PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias,
216 current_impl};
217 PathProbeCandidate candidate{
218 PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS, ty,
219 alias.get_locus (), impl_item_candidate};
220 candidates.insert (std::move (candidate));
224 void
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);
233 rust_assert (ok);
235 PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant,
236 current_impl};
237 PathProbeCandidate candidate{
238 PathProbeCandidate::CandidateType::IMPL_CONST, ty,
239 constant.get_locus (), impl_item_candidate};
240 candidates.insert (std::move (candidate));
244 void
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);
253 rust_assert (ok);
255 PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function,
256 current_impl};
257 PathProbeCandidate candidate{PathProbeCandidate::CandidateType::IMPL_FUNC,
258 ty, function.get_locus (),
259 impl_item_candidate};
260 candidates.insert (std::move (candidate));
264 void
265 PathProbeType::process_enum_item_for_candiates (const TyTy::ADTType *adt)
267 if (specific_trait_id != UNKNOWN_DEFID)
268 return;
270 TyTy::VariantDef *v;
271 if (!adt->lookup_variant (search.as_string (), &v))
272 return;
274 PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v};
275 PathProbeCandidate candidate{PathProbeCandidate::CandidateType::ENUM_VARIANT,
276 receiver->clone (),
277 mappings->lookup_location (adt->get_ty_ref ()),
278 enum_item_candidate};
279 candidates.insert (std::move (candidate));
282 void
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);
288 return true;
292 void
293 PathProbeType::process_impl_item_candidate (HirId id, HIR::ImplItem *item,
294 HIR::ImplBlock *impl)
296 current_impl = 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))
300 return;
302 if (!receiver->can_eq (impl_block_ty, false))
304 if (!impl_block_ty->can_eq (receiver, false))
305 return;
308 // lets visit the impl_item
309 item->accept_vis (*this);
312 void
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))
319 return;
321 bool trait_item_needs_implementation = !trait_item_ref->is_optional ();
322 if (ignore_mandatory_trait_items && trait_item_needs_implementation)
323 return;
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;
330 break;
331 case TraitItemReference::TraitItemType::CONST:
332 candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
333 break;
334 case TraitItemReference::TraitItemType::TYPE:
335 candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
336 break;
338 case TraitItemReference::TraitItemType::ERROR:
339 default:
340 gcc_unreachable ();
341 break;
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 &param_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 = &param_mapping;
357 break;
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,
371 trait_item_ref,
372 impl};
374 PathProbeCandidate candidate{candidate_type, trait_item_tyty,
375 trait_item_ref->get_locus (),
376 trait_item_candidate};
377 candidates.insert (std::move (candidate));
380 void
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 ())
389 return;
391 if (ignore_mandatory_trait_items && item.needs_implementation ())
392 return;
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;
400 break;
401 case TraitItemReference::TraitItemType::CONST:
402 candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
403 break;
404 case TraitItemReference::TraitItemType::TYPE:
405 candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
406 break;
408 case TraitItemReference::TraitItemType::ERROR:
409 default:
410 gcc_unreachable ();
411 break;
414 TyTy::BaseType *trait_item_tyty = item.get_tyty_for_receiver (receiver);
415 PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
416 trait_item_ref,
417 nullptr};
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)
428 const
430 std::map<DefId, std::pair<const TraitReference *, HIR::ImplBlock *>> mapper;
431 for (auto &ref : a)
433 mapper.insert ({ref.first->get_mappings ().get_defid (), ref});
435 for (auto &ref : b)
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});
445 return union_set;
448 bool
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;
457 // PathProbImplTrait
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;
478 void
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 ())
486 return true;
488 TraitReference *resolved
489 = TraitResolver::Lookup (*(impl->get_trait_ref ().get ()));
490 if (!trait_reference->is_equal (*resolved))
491 return true;
493 process_impl_item_candidate (id, item, impl);
494 return true;
498 } // namespace Resolver
499 } // namespace Rust