Require target lra in gcc.dg/pr108095.c
[official-gcc.git] / gcc / rust / typecheck / rust-tyty-bounds.cc
blob76d2eeff8ef5f9c70dd7b2f1a50bf7a7d526812b
1 // Copyright (C) 2021-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-type-bounds.h"
20 #include "rust-hir-trait-resolve.h"
21 #include "rust-hir-type-check-item.h"
23 namespace Rust {
24 namespace Resolver {
26 TypeBoundsProbe::TypeBoundsProbe (const TyTy::BaseType *receiver)
27 : TypeCheckBase (), receiver (receiver)
30 std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
31 TypeBoundsProbe::Probe (const TyTy::BaseType *receiver)
33 TypeBoundsProbe probe (receiver);
34 probe.scan ();
35 return probe.trait_references;
38 bool
39 TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType *receiver,
40 TraitReference *ref)
42 for (auto &bound : receiver->get_specified_bounds ())
44 const TraitReference *b = bound.get ();
45 if (b->is_equal (*ref))
46 return true;
49 std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
50 = Probe (receiver);
51 for (auto &bound : bounds)
53 const TraitReference *b = bound.first;
54 if (b->is_equal (*ref))
55 return true;
58 return false;
61 void
62 TypeBoundsProbe::scan ()
64 std::vector<std::pair<HIR::TypePath *, HIR::ImplBlock *>>
65 possible_trait_paths;
66 mappings->iterate_impl_blocks (
67 [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool {
68 // we are filtering for trait-impl-blocks
69 if (!impl->has_trait_ref ())
70 return true;
72 HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid ();
73 TyTy::BaseType *impl_type = nullptr;
74 if (!query_type (impl_ty_id, &impl_type))
75 return true;
77 if (!receiver->can_eq (impl_type, false))
79 if (!impl_type->can_eq (receiver, false))
80 return true;
83 possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl});
84 return true;
85 });
87 for (auto &path : possible_trait_paths)
89 HIR::TypePath *trait_path = path.first;
90 TraitReference *trait_ref = TraitResolver::Resolve (*trait_path);
92 if (!trait_ref->is_error ())
93 trait_references.push_back ({trait_ref, path.second});
96 // marker traits...
97 assemble_sized_builtin ();
100 void
101 TypeBoundsProbe::assemble_sized_builtin ()
103 const TyTy::BaseType *raw = receiver->destructure ();
105 // does this thing actually implement sized?
106 switch (raw->get_kind ())
108 case TyTy::ADT:
109 case TyTy::STR:
110 case TyTy::REF:
111 case TyTy::POINTER:
112 case TyTy::PARAM:
113 case TyTy::ARRAY:
114 case TyTy::SLICE:
115 case TyTy::FNDEF:
116 case TyTy::FNPTR:
117 case TyTy::TUPLE:
118 case TyTy::BOOL:
119 case TyTy::CHAR:
120 case TyTy::INT:
121 case TyTy::UINT:
122 case TyTy::FLOAT:
123 case TyTy::USIZE:
124 case TyTy::ISIZE:
125 assemble_builtin_candidate (Analysis::RustLangItem::SIZED);
126 break;
128 // not-sure about this.... FIXME
129 case TyTy::INFER:
130 case TyTy::NEVER:
131 case TyTy::PLACEHOLDER:
132 case TyTy::PROJECTION:
133 case TyTy::DYNAMIC:
134 case TyTy::CLOSURE:
135 case TyTy::ERROR:
136 break;
140 void
141 TypeBoundsProbe::assemble_builtin_candidate (
142 Analysis::RustLangItem::ItemType lang_item)
144 DefId id;
145 bool found_lang_item = mappings->lookup_lang_item (lang_item, &id);
146 if (!found_lang_item)
147 return;
149 HIR::Item *item = mappings->lookup_defid (id);
150 if (item == nullptr)
151 return;
153 rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
154 HIR::Trait *trait = static_cast<HIR::Trait *> (item);
155 const TyTy::BaseType *raw = receiver->destructure ();
157 // assemble the reference
158 TraitReference *trait_ref = TraitResolver::Resolve (*trait);
159 trait_references.push_back ({trait_ref, mappings->lookup_builtin_marker ()});
161 rust_debug ("Added builtin lang_item: %s for %s",
162 Analysis::RustLangItem::ToString (lang_item).c_str (),
163 raw->get_name ().c_str ());
166 TraitReference *
167 TypeCheckBase::resolve_trait_path (HIR::TypePath &path)
169 return TraitResolver::Resolve (path);
172 TyTy::TypeBoundPredicate
173 TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
175 TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error ();
176 bool already_resolved
177 = context->lookup_predicate (type_path.get_mappings ().get_hirid (),
178 &lookup);
179 if (already_resolved)
180 return lookup;
182 TraitReference *trait = resolve_trait_path (type_path);
183 if (trait->is_error ())
184 return TyTy::TypeBoundPredicate::error ();
186 TyTy::TypeBoundPredicate predicate (*trait, type_path.get_locus ());
187 HIR::GenericArgs args
188 = HIR::GenericArgs::create_empty (type_path.get_locus ());
190 auto &final_seg = type_path.get_final_segment ();
191 switch (final_seg->get_type ())
193 case HIR::TypePathSegment::SegmentType::GENERIC: {
194 auto final_generic_seg
195 = static_cast<HIR::TypePathSegmentGeneric *> (final_seg.get ());
196 if (final_generic_seg->has_generic_args ())
198 args = final_generic_seg->get_generic_args ();
201 break;
203 case HIR::TypePathSegment::SegmentType::FUNCTION: {
204 auto final_function_seg
205 = static_cast<HIR::TypePathSegmentFunction *> (final_seg.get ());
206 auto &fn = final_function_seg->get_function_path ();
208 // we need to make implicit generic args which must be an implicit
209 // Tuple
210 auto crate_num = mappings->get_current_crate ();
211 HirId implicit_args_id = mappings->get_next_hir_id ();
212 Analysis::NodeMapping mapping (crate_num,
213 final_seg->get_mappings ().get_nodeid (),
214 implicit_args_id, UNKNOWN_LOCAL_DEFID);
216 std::vector<std::unique_ptr<HIR::Type>> params_copy;
217 for (auto &p : fn.get_params ())
219 params_copy.push_back (p->clone_type ());
222 HIR::TupleType *implicit_tuple
223 = new HIR::TupleType (mapping, std::move (params_copy),
224 final_seg->get_locus ());
226 std::vector<std::unique_ptr<HIR::Type>> inputs;
227 inputs.push_back (std::unique_ptr<HIR::Type> (implicit_tuple));
229 args = HIR::GenericArgs ({} /* lifetimes */,
230 std::move (inputs) /* type_args*/,
231 {} /* binding_args*/, {} /* const_args */,
232 final_seg->get_locus ());
234 // resolve the fn_once_output type
235 TyTy::BaseType *fn_once_output_ty
236 = fn.has_return_type ()
237 ? TypeCheckType::Resolve (fn.get_return_type ().get ())
238 : TyTy::TupleType::get_unit_type (
239 final_seg->get_mappings ().get_hirid ());
240 context->insert_implicit_type (final_seg->get_mappings ().get_hirid (),
241 fn_once_output_ty);
243 // setup the associated type.. ??
244 // fn_once_output_ty->debug ();
246 break;
248 default:
249 /* nothing to do */
250 break;
253 // we try to apply generic arguments when they are non empty and or when the
254 // predicate requires them so that we get the relevant Foo expects x number
255 // arguments but got zero see test case rust/compile/traits12.rs
256 if (!args.is_empty () || predicate.requires_generic_args ())
258 // this is applying generic arguments to a trait reference
259 predicate.apply_generic_arguments (&args);
262 context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (),
263 predicate);
264 return predicate;
267 } // namespace Resolver
269 namespace TyTy {
271 TypeBoundPredicate::TypeBoundPredicate (
272 const Resolver::TraitReference &trait_reference, Location locus)
273 : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
274 reference (trait_reference.get_mappings ().get_defid ()), locus (locus),
275 error_flag (false)
277 substitutions.clear ();
278 for (const auto &p : trait_reference.get_trait_substs ())
279 substitutions.push_back (p.clone ());
281 // we setup a dummy implict self argument
282 SubstitutionArg placeholder_self (&get_substs ().front (), nullptr);
283 used_arguments.get_mappings ().push_back (placeholder_self);
286 TypeBoundPredicate::TypeBoundPredicate (
287 DefId reference, std::vector<SubstitutionParamMapping> subst, Location locus)
288 : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
289 reference (reference), locus (locus), error_flag (false)
291 substitutions.clear ();
292 for (const auto &p : subst)
293 substitutions.push_back (p.clone ());
295 // we setup a dummy implict self argument
296 SubstitutionArg placeholder_self (&get_substs ().front (), nullptr);
297 used_arguments.get_mappings ().push_back (placeholder_self);
300 TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other)
301 : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
302 reference (other.reference), locus (other.locus),
303 error_flag (other.error_flag)
305 substitutions.clear ();
306 for (const auto &p : other.get_substs ())
307 substitutions.push_back (p.clone ());
309 std::vector<SubstitutionArg> mappings;
310 for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
312 const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
313 SubstitutionArg arg (oa);
314 mappings.push_back (std::move (arg));
317 // we need to remap the argument mappings based on this copied constructor
318 std::vector<SubstitutionArg> copied_arg_mappings;
319 size_t i = 0;
320 for (const auto &m : other.used_arguments.get_mappings ())
322 TyTy::BaseType *argument
323 = m.get_tyty () == nullptr ? nullptr : m.get_tyty ()->clone ();
324 SubstitutionArg c (&substitutions.at (i++), argument);
325 copied_arg_mappings.push_back (std::move (c));
328 used_arguments
329 = SubstitutionArgumentMappings (copied_arg_mappings, {},
330 other.used_arguments.get_locus ());
333 TypeBoundPredicate &
334 TypeBoundPredicate::operator= (const TypeBoundPredicate &other)
336 reference = other.reference;
337 locus = other.locus;
338 error_flag = other.error_flag;
339 used_arguments = SubstitutionArgumentMappings::error ();
341 substitutions.clear ();
342 for (const auto &p : other.get_substs ())
343 substitutions.push_back (p.clone ());
345 std::vector<SubstitutionArg> mappings;
346 for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
348 const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
349 SubstitutionArg arg (oa);
350 mappings.push_back (std::move (arg));
353 // we need to remap the argument mappings based on this copied constructor
354 std::vector<SubstitutionArg> copied_arg_mappings;
355 size_t i = 0;
356 for (const auto &m : other.used_arguments.get_mappings ())
358 TyTy::BaseType *argument
359 = m.get_tyty () == nullptr ? nullptr : m.get_tyty ()->clone ();
360 SubstitutionArg c (&substitutions.at (i++), argument);
361 copied_arg_mappings.push_back (std::move (c));
364 used_arguments
365 = SubstitutionArgumentMappings (copied_arg_mappings, {},
366 other.used_arguments.get_locus ());
368 return *this;
371 TypeBoundPredicate
372 TypeBoundPredicate::error ()
374 auto p = TypeBoundPredicate (UNKNOWN_DEFID, {}, Location ());
375 p.error_flag = true;
376 return p;
379 std::string
380 TypeBoundPredicate::as_string () const
382 return get ()->as_string () + subst_as_string ();
385 std::string
386 TypeBoundPredicate::as_name () const
388 return get ()->get_name () + subst_as_string ();
391 const Resolver::TraitReference *
392 TypeBoundPredicate::get () const
394 auto context = Resolver::TypeCheckContext::get ();
396 Resolver::TraitReference *ref = nullptr;
397 bool ok = context->lookup_trait_reference (reference, &ref);
398 rust_assert (ok);
400 return ref;
403 std::string
404 TypeBoundPredicate::get_name () const
406 return get ()->get_name ();
409 bool
410 TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const
412 const Resolver::TraitReference *trait = get ();
413 rust_assert (trait != nullptr);
414 return trait->is_object_safe (emit_error, locus);
417 void
418 TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args)
420 // we need to get the substitutions argument mappings but also remember that
421 // we have an implicit Self argument which we must be careful to respect
422 rust_assert (!used_arguments.is_empty ());
423 rust_assert (!substitutions.empty ());
425 // now actually perform a substitution
426 used_arguments = get_mappings_from_generic_args (*generic_args);
428 error_flag |= used_arguments.is_error ();
429 auto &subst_mappings = used_arguments;
430 for (auto &sub : get_substs ())
432 SubstitutionArg arg = SubstitutionArg::error ();
433 bool ok
434 = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg);
435 if (ok && arg.get_tyty () != nullptr)
436 sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ());
439 // associated argument mappings
440 for (auto &it : subst_mappings.get_binding_args ())
442 std::string identifier = it.first;
443 TyTy::BaseType *type = it.second;
445 TypeBoundPredicateItem item = lookup_associated_item (identifier);
446 rust_assert (!item.is_error ());
448 const auto item_ref = item.get_raw_item ();
449 item_ref->associated_type_set (type);
453 bool
454 TypeBoundPredicate::contains_item (const std::string &search) const
456 auto trait_ref = get ();
457 const Resolver::TraitItemReference *trait_item_ref = nullptr;
458 return trait_ref->lookup_trait_item (search, &trait_item_ref);
461 TypeBoundPredicateItem
462 TypeBoundPredicate::lookup_associated_item (const std::string &search) const
464 auto trait_ref = get ();
465 const Resolver::TraitItemReference *trait_item_ref = nullptr;
466 if (!trait_ref->lookup_trait_item (search, &trait_item_ref))
467 return TypeBoundPredicateItem::error ();
469 return TypeBoundPredicateItem (this, trait_item_ref);
472 TypeBoundPredicateItem::TypeBoundPredicateItem (
473 const TypeBoundPredicate *parent,
474 const Resolver::TraitItemReference *trait_item_ref)
475 : parent (parent), trait_item_ref (trait_item_ref)
478 TypeBoundPredicateItem
479 TypeBoundPredicateItem::error ()
481 return TypeBoundPredicateItem (nullptr, nullptr);
484 bool
485 TypeBoundPredicateItem::is_error () const
487 return parent == nullptr || trait_item_ref == nullptr;
490 const TypeBoundPredicate *
491 TypeBoundPredicateItem::get_parent () const
493 return parent;
496 TypeBoundPredicateItem
497 TypeBoundPredicate::lookup_associated_item (
498 const Resolver::TraitItemReference *ref) const
500 return lookup_associated_item (ref->get_identifier ());
503 BaseType *
504 TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver)
506 TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty ();
507 if (parent->get_substitution_arguments ().is_empty ())
508 return trait_item_tyty;
510 const Resolver::TraitItemReference *tref = get_raw_item ();
511 bool is_associated_type = tref->get_trait_item_type ();
512 if (is_associated_type)
513 return trait_item_tyty;
515 // set up the self mapping
516 SubstitutionArgumentMappings gargs = parent->get_substitution_arguments ();
517 rust_assert (!gargs.is_empty ());
519 // setup the adjusted mappings
520 std::vector<SubstitutionArg> adjusted_mappings;
521 for (size_t i = 0; i < gargs.get_mappings ().size (); i++)
523 auto &mapping = gargs.get_mappings ().at (i);
525 bool is_implicit_self = i == 0;
526 TyTy::BaseType *argument
527 = is_implicit_self ? receiver->clone () : mapping.get_tyty ();
529 SubstitutionArg arg (mapping.get_param_mapping (), argument);
530 adjusted_mappings.push_back (std::move (arg));
533 SubstitutionArgumentMappings adjusted (adjusted_mappings, {},
534 gargs.get_locus (),
535 gargs.get_subst_cb (),
536 true /* trait-mode-flag */);
537 return Resolver::SubstMapperInternal::Resolve (trait_item_tyty, adjusted);
539 bool
540 TypeBoundPredicate::is_error () const
542 auto context = Resolver::TypeCheckContext::get ();
544 Resolver::TraitReference *ref = nullptr;
545 bool ok = context->lookup_trait_reference (reference, &ref);
547 return !ok || error_flag;
550 BaseType *
551 TypeBoundPredicate::handle_substitions (
552 SubstitutionArgumentMappings &subst_mappings)
554 for (auto &sub : get_substs ())
556 if (sub.get_param_ty () == nullptr)
557 continue;
559 ParamType *p = sub.get_param_ty ();
560 BaseType *r = p->resolve ();
561 BaseType *s = Resolver::SubstMapperInternal::Resolve (r, subst_mappings);
563 p->set_ty_ref (s->get_ty_ref ());
566 // associated argument mappings
567 for (auto &it : subst_mappings.get_binding_args ())
569 std::string identifier = it.first;
570 TyTy::BaseType *type = it.second;
572 TypeBoundPredicateItem item = lookup_associated_item (identifier);
573 rust_assert (!item.is_error ());
575 const auto item_ref = item.get_raw_item ();
576 item_ref->associated_type_set (type);
579 // FIXME more error handling at some point
580 // used_arguments = subst_mappings;
581 // error_flag |= used_arguments.is_error ();
583 return nullptr;
586 bool
587 TypeBoundPredicate::requires_generic_args () const
589 if (is_error ())
590 return false;
592 return substitutions.size () > 1;
595 bool
596 TypeBoundPredicate::contains_associated_types () const
598 return get_num_associated_bindings () > 0;
601 size_t
602 TypeBoundPredicate::get_num_associated_bindings () const
604 size_t count = 0;
605 auto trait_ref = get ();
606 for (const auto &trait_item : trait_ref->get_trait_items ())
608 bool is_associated_type
609 = trait_item.get_trait_item_type ()
610 == Resolver::TraitItemReference::TraitItemType::TYPE;
611 if (is_associated_type)
612 count++;
614 return count;
617 TypeBoundPredicateItem
618 TypeBoundPredicate::lookup_associated_type (const std::string &search)
620 TypeBoundPredicateItem item = lookup_associated_item (search);
622 // only need to check that it is infact an associated type because other
623 // wise if it was not found it will just be an error node anyway
624 if (!item.is_error ())
626 const auto raw = item.get_raw_item ();
627 if (raw->get_trait_item_type ()
628 != Resolver::TraitItemReference::TraitItemType::TYPE)
629 return TypeBoundPredicateItem::error ();
631 return item;
634 std::vector<TypeBoundPredicateItem>
635 TypeBoundPredicate::get_associated_type_items ()
637 std::vector<TypeBoundPredicateItem> items;
638 auto trait_ref = get ();
639 for (const auto &trait_item : trait_ref->get_trait_items ())
641 bool is_associated_type
642 = trait_item.get_trait_item_type ()
643 == Resolver::TraitItemReference::TraitItemType::TYPE;
644 if (is_associated_type)
646 TypeBoundPredicateItem item (this, &trait_item);
647 items.push_back (std::move (item));
650 return items;
653 // trait item reference
655 const Resolver::TraitItemReference *
656 TypeBoundPredicateItem::get_raw_item () const
658 return trait_item_ref;
661 bool
662 TypeBoundPredicateItem::needs_implementation () const
664 return !get_raw_item ()->is_optional ();
667 Location
668 TypeBoundPredicateItem::get_locus () const
670 return get_raw_item ()->get_locus ();
673 // TypeBoundsMappings
675 TypeBoundsMappings::TypeBoundsMappings (
676 std::vector<TypeBoundPredicate> specified_bounds)
677 : specified_bounds (specified_bounds)
680 std::vector<TypeBoundPredicate> &
681 TypeBoundsMappings::get_specified_bounds ()
683 return specified_bounds;
686 const std::vector<TypeBoundPredicate> &
687 TypeBoundsMappings::get_specified_bounds () const
689 return specified_bounds;
692 size_t
693 TypeBoundsMappings::num_specified_bounds () const
695 return specified_bounds.size ();
698 std::string
699 TypeBoundsMappings::raw_bounds_as_string () const
701 std::string buf;
702 for (size_t i = 0; i < specified_bounds.size (); i++)
704 const TypeBoundPredicate &b = specified_bounds.at (i);
705 bool has_next = (i + 1) < specified_bounds.size ();
706 buf += b.as_string () + (has_next ? " + " : "");
708 return buf;
711 std::string
712 TypeBoundsMappings::bounds_as_string () const
714 return "bounds:[" + raw_bounds_as_string () + "]";
717 std::string
718 TypeBoundsMappings::raw_bounds_as_name () const
720 std::string buf;
721 for (size_t i = 0; i < specified_bounds.size (); i++)
723 const TypeBoundPredicate &b = specified_bounds.at (i);
724 bool has_next = (i + 1) < specified_bounds.size ();
725 buf += b.as_name () + (has_next ? " + " : "");
728 return buf;
731 void
732 TypeBoundsMappings::add_bound (TypeBoundPredicate predicate)
734 for (auto &bound : specified_bounds)
736 bool same_trait_ref_p = bound.get_id () == predicate.get_id ();
737 if (same_trait_ref_p)
738 return;
741 specified_bounds.push_back (predicate);
744 } // namespace TyTy
745 } // namespace Rust