1 // Copyright (C) 2021-2024 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-type-bounds.h"
20 #include "rust-hir-trait-resolve.h"
21 #include "rust-hir-type-check-item.h"
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
);
35 return probe
.trait_references
;
39 TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType
*receiver
,
42 for (auto &bound
: receiver
->get_specified_bounds ())
44 const TraitReference
*b
= bound
.get ();
45 if (b
->is_equal (*ref
))
49 std::vector
<std::pair
<TraitReference
*, HIR::ImplBlock
*>> bounds
51 for (auto &bound
: bounds
)
53 const TraitReference
*b
= bound
.first
;
54 if (b
->is_equal (*ref
))
62 TypeBoundsProbe::scan ()
64 std::vector
<std::pair
<HIR::TypePath
*, HIR::ImplBlock
*>>
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 ())
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
))
77 if (!receiver
->can_eq (impl_type
, false))
79 if (!impl_type
->can_eq (receiver
, false))
83 possible_trait_paths
.push_back ({impl
->get_trait_ref ().get (), impl
});
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
});
97 assemble_sized_builtin ();
101 TypeBoundsProbe::assemble_sized_builtin ()
103 const TyTy::BaseType
*raw
= receiver
->destructure ();
105 // does this thing actually implement sized?
106 switch (raw
->get_kind ())
125 assemble_builtin_candidate (Analysis::RustLangItem::SIZED
);
128 // not-sure about this.... FIXME
131 case TyTy::PLACEHOLDER
:
132 case TyTy::PROJECTION
:
141 TypeBoundsProbe::assemble_builtin_candidate (
142 Analysis::RustLangItem::ItemType lang_item
)
145 bool found_lang_item
= mappings
->lookup_lang_item (lang_item
, &id
);
146 if (!found_lang_item
)
149 HIR::Item
*item
= mappings
->lookup_defid (id
);
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 ());
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 (),
179 if (already_resolved
)
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 ();
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
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 (),
243 // setup the associated type.. ??
244 // fn_once_output_ty->debug ();
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 (),
267 } // namespace Resolver
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
),
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
;
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
));
329 = SubstitutionArgumentMappings (copied_arg_mappings
, {},
330 other
.used_arguments
.get_locus ());
334 TypeBoundPredicate::operator= (const TypeBoundPredicate
&other
)
336 reference
= other
.reference
;
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
;
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
));
365 = SubstitutionArgumentMappings (copied_arg_mappings
, {},
366 other
.used_arguments
.get_locus ());
372 TypeBoundPredicate::error ()
374 auto p
= TypeBoundPredicate (UNKNOWN_DEFID
, {}, Location ());
380 TypeBoundPredicate::as_string () const
382 return get ()->as_string () + subst_as_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
);
404 TypeBoundPredicate::get_name () const
406 return get ()->get_name ();
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
);
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 ();
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
);
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);
485 TypeBoundPredicateItem::is_error () const
487 return parent
== nullptr || trait_item_ref
== nullptr;
490 const TypeBoundPredicate
*
491 TypeBoundPredicateItem::get_parent () const
496 TypeBoundPredicateItem
497 TypeBoundPredicate::lookup_associated_item (
498 const Resolver::TraitItemReference
*ref
) const
500 return lookup_associated_item (ref
->get_identifier ());
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
, {},
535 gargs
.get_subst_cb (),
536 true /* trait-mode-flag */);
537 return Resolver::SubstMapperInternal::Resolve (trait_item_tyty
, adjusted
);
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
;
551 TypeBoundPredicate::handle_substitions (
552 SubstitutionArgumentMappings
&subst_mappings
)
554 for (auto &sub
: get_substs ())
556 if (sub
.get_param_ty () == nullptr)
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 ();
587 TypeBoundPredicate::requires_generic_args () const
592 return substitutions
.size () > 1;
596 TypeBoundPredicate::contains_associated_types () const
598 return get_num_associated_bindings () > 0;
602 TypeBoundPredicate::get_num_associated_bindings () const
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
)
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 ();
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
));
653 // trait item reference
655 const Resolver::TraitItemReference
*
656 TypeBoundPredicateItem::get_raw_item () const
658 return trait_item_ref
;
662 TypeBoundPredicateItem::needs_implementation () const
664 return !get_raw_item ()->is_optional ();
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
;
693 TypeBoundsMappings::num_specified_bounds () const
695 return specified_bounds
.size ();
699 TypeBoundsMappings::raw_bounds_as_string () const
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
? " + " : "");
712 TypeBoundsMappings::bounds_as_string () const
714 return "bounds:[" + raw_bounds_as_string () + "]";
718 TypeBoundsMappings::raw_bounds_as_name () const
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
? " + " : "");
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
)
741 specified_bounds
.push_back (predicate
);