]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/typecheck/rust-tyty-bounds.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / typecheck / rust-tyty-bounds.cc
CommitLineData
a945c346 1// Copyright (C) 2021-2024 Free Software Foundation, Inc.
06688fe4
PH
2
3// This file is part of GCC.
4
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.
9
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.
14
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/>.
18
19#include "rust-hir-type-bounds.h"
20#include "rust-hir-trait-resolve.h"
104cc285 21#include "rust-hir-type-check-item.h"
06688fe4
PH
22
23namespace Rust {
24namespace Resolver {
25
4b25fc15
PH
26TypeBoundsProbe::TypeBoundsProbe (const TyTy::BaseType *receiver)
27 : TypeCheckBase (), receiver (receiver)
28{}
29
30std::vector<std::pair<TraitReference *, HIR::ImplBlock *>>
31TypeBoundsProbe::Probe (const TyTy::BaseType *receiver)
32{
33 TypeBoundsProbe probe (receiver);
34 probe.scan ();
35 return probe.trait_references;
36}
37
38bool
39TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType *receiver,
40 TraitReference *ref)
41{
42 for (auto &bound : receiver->get_specified_bounds ())
43 {
44 const TraitReference *b = bound.get ();
45 if (b->is_equal (*ref))
46 return true;
47 }
48
49 std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> bounds
50 = Probe (receiver);
51 for (auto &bound : bounds)
52 {
53 const TraitReference *b = bound.first;
54 if (b->is_equal (*ref))
55 return true;
56 }
57
58 return false;
59}
60
06688fe4
PH
61void
62TypeBoundsProbe::scan ()
63{
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;
71
543ba359
PH
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))
06688fe4
PH
75 return true;
76
77 if (!receiver->can_eq (impl_type, false))
78 {
79 if (!impl_type->can_eq (receiver, false))
80 return true;
81 }
82
83 possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl});
84 return true;
85 });
86
87 for (auto &path : possible_trait_paths)
88 {
89 HIR::TypePath *trait_path = path.first;
90 TraitReference *trait_ref = TraitResolver::Resolve (*trait_path);
91
92 if (!trait_ref->is_error ())
93 trait_references.push_back ({trait_ref, path.second});
94 }
4b25fc15
PH
95
96 // marker traits...
97 assemble_sized_builtin ();
98}
99
100void
101TypeBoundsProbe::assemble_sized_builtin ()
102{
103 const TyTy::BaseType *raw = receiver->destructure ();
104
105 // does this thing actually implement sized?
106 switch (raw->get_kind ())
107 {
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;
127
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;
137 }
138}
139
140void
141TypeBoundsProbe::assemble_builtin_candidate (
142 Analysis::RustLangItem::ItemType lang_item)
143{
144 DefId id;
145 bool found_lang_item = mappings->lookup_lang_item (lang_item, &id);
146 if (!found_lang_item)
147 return;
148
149 HIR::Item *item = mappings->lookup_defid (id);
150 if (item == nullptr)
151 return;
152
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 ();
156
157 // assemble the reference
158 TraitReference *trait_ref = TraitResolver::Resolve (*trait);
159 trait_references.push_back ({trait_ref, mappings->lookup_builtin_marker ()});
160
161 rust_debug ("Added builtin lang_item: %s for %s",
162 Analysis::RustLangItem::ToString (lang_item).c_str (),
163 raw->get_name ().c_str ());
06688fe4
PH
164}
165
166TraitReference *
167TypeCheckBase::resolve_trait_path (HIR::TypePath &path)
168{
169 return TraitResolver::Resolve (path);
170}
171
172TyTy::TypeBoundPredicate
173TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path)
174{
104cc285
PH
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;
181
06688fe4
PH
182 TraitReference *trait = resolve_trait_path (type_path);
183 if (trait->is_error ())
184 return TyTy::TypeBoundPredicate::error ();
185
186 TyTy::TypeBoundPredicate predicate (*trait, type_path.get_locus ());
187 HIR::GenericArgs args
188 = HIR::GenericArgs::create_empty (type_path.get_locus ());
189
190 auto &final_seg = type_path.get_final_segment ();
51d180fc 191 switch (final_seg->get_type ())
06688fe4 192 {
51d180fc
PH
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 ())
197 {
198 args = final_generic_seg->get_generic_args ();
199 }
200 }
201 break;
202
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 ();
207
4b25fc15
PH
208 // we need to make implicit generic args which must be an implicit
209 // Tuple
51d180fc
PH
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);
215
216 std::vector<std::unique_ptr<HIR::Type>> params_copy;
217 for (auto &p : fn.get_params ())
218 {
219 params_copy.push_back (p->clone_type ());
220 }
221
222 HIR::TupleType *implicit_tuple
223 = new HIR::TupleType (mapping, std::move (params_copy),
224 final_seg->get_locus ());
225
226 std::vector<std::unique_ptr<HIR::Type>> inputs;
227 inputs.push_back (std::unique_ptr<HIR::Type> (implicit_tuple));
228
229 args = HIR::GenericArgs ({} /* lifetimes */,
230 std::move (inputs) /* type_args*/,
231 {} /* binding_args*/, {} /* const_args */,
232 final_seg->get_locus ());
233
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);
242
243 // setup the associated type.. ??
244 // fn_once_output_ty->debug ();
245 }
246 break;
247
248 default:
249 /* nothing to do */
250 break;
06688fe4
PH
251 }
252
7eab9d18
PH
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 ())
06688fe4
PH
257 {
258 // this is applying generic arguments to a trait reference
259 predicate.apply_generic_arguments (&args);
260 }
261
104cc285
PH
262 context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (),
263 predicate);
06688fe4
PH
264 return predicate;
265}
266
267} // namespace Resolver
268
269namespace TyTy {
270
271TypeBoundPredicate::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)
276{
277 substitutions.clear ();
278 for (const auto &p : trait_reference.get_trait_substs ())
279 substitutions.push_back (p.clone ());
280
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);
284}
285
286TypeBoundPredicate::TypeBoundPredicate (
287 DefId reference, std::vector<SubstitutionParamMapping> subst, Location locus)
288 : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
289 reference (reference), locus (locus), error_flag (false)
290{
291 substitutions.clear ();
292 for (const auto &p : subst)
293 substitutions.push_back (p.clone ());
294
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);
298}
299
300TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other)
301 : SubstitutionRef ({}, SubstitutionArgumentMappings::error ()),
302 reference (other.reference), locus (other.locus),
303 error_flag (other.error_flag)
304{
305 substitutions.clear ();
306 for (const auto &p : other.get_substs ())
307 substitutions.push_back (p.clone ());
308
309 std::vector<SubstitutionArg> mappings;
310 for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
311 {
312 const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
313 SubstitutionArg arg (oa);
314 mappings.push_back (std::move (arg));
315 }
316
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 ())
321 {
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));
326 }
327
328 used_arguments
7eab9d18 329 = SubstitutionArgumentMappings (copied_arg_mappings, {},
06688fe4
PH
330 other.used_arguments.get_locus ());
331}
332
333TypeBoundPredicate &
334TypeBoundPredicate::operator= (const TypeBoundPredicate &other)
335{
336 reference = other.reference;
337 locus = other.locus;
338 error_flag = other.error_flag;
339 used_arguments = SubstitutionArgumentMappings::error ();
340
341 substitutions.clear ();
342 for (const auto &p : other.get_substs ())
343 substitutions.push_back (p.clone ());
344
345 std::vector<SubstitutionArg> mappings;
346 for (size_t i = 0; i < other.used_arguments.get_mappings ().size (); i++)
347 {
348 const SubstitutionArg &oa = other.used_arguments.get_mappings ().at (i);
349 SubstitutionArg arg (oa);
350 mappings.push_back (std::move (arg));
351 }
352
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 ())
357 {
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));
362 }
363
364 used_arguments
7eab9d18 365 = SubstitutionArgumentMappings (copied_arg_mappings, {},
06688fe4
PH
366 other.used_arguments.get_locus ());
367
368 return *this;
369}
370
371TypeBoundPredicate
372TypeBoundPredicate::error ()
373{
374 auto p = TypeBoundPredicate (UNKNOWN_DEFID, {}, Location ());
375 p.error_flag = true;
376 return p;
377}
378
379std::string
380TypeBoundPredicate::as_string () const
381{
382 return get ()->as_string () + subst_as_string ();
383}
384
385std::string
386TypeBoundPredicate::as_name () const
387{
388 return get ()->get_name () + subst_as_string ();
389}
390
391const Resolver::TraitReference *
392TypeBoundPredicate::get () const
393{
394 auto context = Resolver::TypeCheckContext::get ();
395
396 Resolver::TraitReference *ref = nullptr;
397 bool ok = context->lookup_trait_reference (reference, &ref);
398 rust_assert (ok);
399
400 return ref;
401}
402
403std::string
404TypeBoundPredicate::get_name () const
405{
406 return get ()->get_name ();
407}
408
409bool
410TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const
411{
412 const Resolver::TraitReference *trait = get ();
413 rust_assert (trait != nullptr);
414 return trait->is_object_safe (emit_error, locus);
415}
416
417void
418TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args)
419{
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 ());
424
425 // now actually perform a substitution
426 used_arguments = get_mappings_from_generic_args (*generic_args);
427
428 error_flag |= used_arguments.is_error ();
429 auto &subst_mappings = used_arguments;
430 for (auto &sub : get_substs ())
431 {
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 ());
437 }
7eab9d18
PH
438
439 // associated argument mappings
440 for (auto &it : subst_mappings.get_binding_args ())
441 {
442 std::string identifier = it.first;
443 TyTy::BaseType *type = it.second;
444
445 TypeBoundPredicateItem item = lookup_associated_item (identifier);
446 rust_assert (!item.is_error ());
447
448 const auto item_ref = item.get_raw_item ();
449 item_ref->associated_type_set (type);
450 }
06688fe4
PH
451}
452
453bool
454TypeBoundPredicate::contains_item (const std::string &search) const
455{
456 auto trait_ref = get ();
457 const Resolver::TraitItemReference *trait_item_ref = nullptr;
458 return trait_ref->lookup_trait_item (search, &trait_item_ref);
459}
460
461TypeBoundPredicateItem
462TypeBoundPredicate::lookup_associated_item (const std::string &search) const
463{
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 ();
468
469 return TypeBoundPredicateItem (this, trait_item_ref);
470}
471
c1b1bbbc
PH
472TypeBoundPredicateItem::TypeBoundPredicateItem (
473 const TypeBoundPredicate *parent,
474 const Resolver::TraitItemReference *trait_item_ref)
475 : parent (parent), trait_item_ref (trait_item_ref)
476{}
477
478TypeBoundPredicateItem
479TypeBoundPredicateItem::error ()
480{
481 return TypeBoundPredicateItem (nullptr, nullptr);
482}
483
484bool
485TypeBoundPredicateItem::is_error () const
486{
487 return parent == nullptr || trait_item_ref == nullptr;
488}
489
490const TypeBoundPredicate *
491TypeBoundPredicateItem::get_parent () const
492{
493 return parent;
494}
495
06688fe4
PH
496TypeBoundPredicateItem
497TypeBoundPredicate::lookup_associated_item (
498 const Resolver::TraitItemReference *ref) const
499{
500 return lookup_associated_item (ref->get_identifier ());
501}
502
503BaseType *
504TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver)
505{
506 TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty ();
507 if (parent->get_substitution_arguments ().is_empty ())
508 return trait_item_tyty;
509
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;
514
515 // set up the self mapping
516 SubstitutionArgumentMappings gargs = parent->get_substitution_arguments ();
517 rust_assert (!gargs.is_empty ());
518
519 // setup the adjusted mappings
520 std::vector<SubstitutionArg> adjusted_mappings;
521 for (size_t i = 0; i < gargs.get_mappings ().size (); i++)
522 {
523 auto &mapping = gargs.get_mappings ().at (i);
524
525 bool is_implicit_self = i == 0;
526 TyTy::BaseType *argument
527 = is_implicit_self ? receiver->clone () : mapping.get_tyty ();
528
529 SubstitutionArg arg (mapping.get_param_mapping (), argument);
530 adjusted_mappings.push_back (std::move (arg));
531 }
532
7eab9d18
PH
533 SubstitutionArgumentMappings adjusted (adjusted_mappings, {},
534 gargs.get_locus (),
06688fe4
PH
535 gargs.get_subst_cb (),
536 true /* trait-mode-flag */);
537 return Resolver::SubstMapperInternal::Resolve (trait_item_tyty, adjusted);
538}
539bool
540TypeBoundPredicate::is_error () const
541{
542 auto context = Resolver::TypeCheckContext::get ();
543
544 Resolver::TraitReference *ref = nullptr;
545 bool ok = context->lookup_trait_reference (reference, &ref);
546
547 return !ok || error_flag;
548}
549
550BaseType *
551TypeBoundPredicate::handle_substitions (
dcb2e571 552 SubstitutionArgumentMappings &subst_mappings)
06688fe4
PH
553{
554 for (auto &sub : get_substs ())
555 {
556 if (sub.get_param_ty () == nullptr)
557 continue;
558
559 ParamType *p = sub.get_param_ty ();
560 BaseType *r = p->resolve ();
561 BaseType *s = Resolver::SubstMapperInternal::Resolve (r, subst_mappings);
562
563 p->set_ty_ref (s->get_ty_ref ());
564 }
565
7eab9d18
PH
566 // associated argument mappings
567 for (auto &it : subst_mappings.get_binding_args ())
568 {
569 std::string identifier = it.first;
570 TyTy::BaseType *type = it.second;
571
572 TypeBoundPredicateItem item = lookup_associated_item (identifier);
573 rust_assert (!item.is_error ());
574
575 const auto item_ref = item.get_raw_item ();
576 item_ref->associated_type_set (type);
577 }
578
06688fe4
PH
579 // FIXME more error handling at some point
580 // used_arguments = subst_mappings;
581 // error_flag |= used_arguments.is_error ();
582
583 return nullptr;
584}
585
586bool
587TypeBoundPredicate::requires_generic_args () const
588{
589 if (is_error ())
590 return false;
591
592 return substitutions.size () > 1;
593}
594
e641158a
PH
595bool
596TypeBoundPredicate::contains_associated_types () const
597{
7eab9d18
PH
598 return get_num_associated_bindings () > 0;
599}
600
601size_t
602TypeBoundPredicate::get_num_associated_bindings () const
603{
604 size_t count = 0;
e641158a
PH
605 auto trait_ref = get ();
606 for (const auto &trait_item : trait_ref->get_trait_items ())
607 {
608 bool is_associated_type
609 = trait_item.get_trait_item_type ()
610 == Resolver::TraitItemReference::TraitItemType::TYPE;
611 if (is_associated_type)
7eab9d18
PH
612 count++;
613 }
614 return count;
615}
616
617TypeBoundPredicateItem
618TypeBoundPredicate::lookup_associated_type (const std::string &search)
619{
620 TypeBoundPredicateItem item = lookup_associated_item (search);
621
4b25fc15
PH
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
7eab9d18
PH
624 if (!item.is_error ())
625 {
626 const auto raw = item.get_raw_item ();
627 if (raw->get_trait_item_type ()
628 != Resolver::TraitItemReference::TraitItemType::TYPE)
629 return TypeBoundPredicateItem::error ();
630 }
631 return item;
632}
633
634std::vector<TypeBoundPredicateItem>
635TypeBoundPredicate::get_associated_type_items ()
636{
637 std::vector<TypeBoundPredicateItem> items;
638 auto trait_ref = get ();
639 for (const auto &trait_item : trait_ref->get_trait_items ())
640 {
641 bool is_associated_type
642 = trait_item.get_trait_item_type ()
643 == Resolver::TraitItemReference::TraitItemType::TYPE;
644 if (is_associated_type)
645 {
646 TypeBoundPredicateItem item (this, &trait_item);
647 items.push_back (std::move (item));
648 }
e641158a 649 }
7eab9d18 650 return items;
e641158a
PH
651}
652
06688fe4
PH
653// trait item reference
654
655const Resolver::TraitItemReference *
656TypeBoundPredicateItem::get_raw_item () const
657{
658 return trait_item_ref;
659}
660
661bool
662TypeBoundPredicateItem::needs_implementation () const
663{
664 return !get_raw_item ()->is_optional ();
665}
666
667Location
668TypeBoundPredicateItem::get_locus () const
669{
670 return get_raw_item ()->get_locus ();
671}
672
673// TypeBoundsMappings
674
675TypeBoundsMappings::TypeBoundsMappings (
676 std::vector<TypeBoundPredicate> specified_bounds)
677 : specified_bounds (specified_bounds)
678{}
679
680std::vector<TypeBoundPredicate> &
681TypeBoundsMappings::get_specified_bounds ()
682{
683 return specified_bounds;
684}
685
686const std::vector<TypeBoundPredicate> &
687TypeBoundsMappings::get_specified_bounds () const
688{
689 return specified_bounds;
690}
691
692size_t
693TypeBoundsMappings::num_specified_bounds () const
694{
695 return specified_bounds.size ();
696}
697
698std::string
699TypeBoundsMappings::raw_bounds_as_string () const
700{
701 std::string buf;
702 for (size_t i = 0; i < specified_bounds.size (); i++)
703 {
704 const TypeBoundPredicate &b = specified_bounds.at (i);
705 bool has_next = (i + 1) < specified_bounds.size ();
706 buf += b.as_string () + (has_next ? " + " : "");
707 }
708 return buf;
709}
710
711std::string
712TypeBoundsMappings::bounds_as_string () const
713{
714 return "bounds:[" + raw_bounds_as_string () + "]";
715}
716
717std::string
718TypeBoundsMappings::raw_bounds_as_name () const
719{
720 std::string buf;
721 for (size_t i = 0; i < specified_bounds.size (); i++)
722 {
723 const TypeBoundPredicate &b = specified_bounds.at (i);
724 bool has_next = (i + 1) < specified_bounds.size ();
725 buf += b.as_name () + (has_next ? " + " : "");
726 }
727
728 return buf;
729}
730
731void
732TypeBoundsMappings::add_bound (TypeBoundPredicate predicate)
733{
104cc285
PH
734 for (auto &bound : specified_bounds)
735 {
736 bool same_trait_ref_p = bound.get_id () == predicate.get_id ();
737 if (same_trait_ref_p)
738 return;
739 }
740
06688fe4
PH
741 specified_bounds.push_back (predicate);
742}
743
744} // namespace TyTy
745} // namespace Rust