1 // Copyright (C) 2020-2025 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-tyty-subst.h"
21 #include "rust-system.h"
22 #include "rust-tyty.h"
23 #include "rust-hir-type-check.h"
24 #include "rust-substitution-mapper.h"
25 #include "rust-hir-type-check-type.h"
26 #include "rust-type-util.h"
31 SubstitutionParamMapping::SubstitutionParamMapping (
32 const HIR::TypeParam
&generic
, ParamType
*param
)
33 : generic (generic
), param (param
)
36 SubstitutionParamMapping::SubstitutionParamMapping (
37 const SubstitutionParamMapping
&other
)
38 : generic (other
.generic
), param (other
.param
)
42 SubstitutionParamMapping::as_string () const
47 return param
->get_name ();
50 SubstitutionParamMapping
51 SubstitutionParamMapping::clone () const
53 return SubstitutionParamMapping (generic
,
54 static_cast<ParamType
*> (param
->clone ()));
58 SubstitutionParamMapping::get_param_ty ()
64 SubstitutionParamMapping::get_param_ty () const
69 const HIR::TypeParam
&
70 SubstitutionParamMapping::get_generic_param () const
76 SubstitutionParamMapping::needs_substitution () const
78 return !(get_param_ty ()->is_concrete ());
82 SubstitutionParamMapping::get_param_locus () const
84 return generic
.get_locus ();
88 SubstitutionParamMapping::param_has_default_ty () const
90 return generic
.has_type ();
94 SubstitutionParamMapping::get_default_ty () const
96 TyVar
var (generic
.get_type_mappings ().get_hirid ());
97 return var
.get_tyty ();
101 SubstitutionParamMapping::need_substitution () const
103 if (!param
->can_resolve ())
106 auto resolved
= param
->resolve ();
107 return !resolved
->is_concrete ();
111 SubstitutionParamMapping::fill_param_ty (
112 SubstitutionArgumentMappings
&subst_mappings
, location_t locus
)
114 SubstitutionArg arg
= SubstitutionArg::error ();
115 bool ok
= subst_mappings
.get_argument_for_symbol (get_param_ty (), &arg
);
119 TyTy::BaseType
&type
= *arg
.get_tyty ();
120 if (type
.get_kind () == TyTy::TypeKind::INFER
)
122 type
.inherit_bounds (*param
);
125 if (type
.get_kind () == TypeKind::PARAM
)
128 param
= static_cast<ParamType
*> (type
.clone ());
132 // check the substitution is compatible with bounds
133 rust_debug_loc (locus
,
134 "fill_param_ty bounds_compatible: param %s type %s",
135 param
->get_name ().c_str (), type
.get_name ().c_str ());
137 if (!param
->is_implicit_self_trait ())
139 if (!param
->bounds_compatible (type
, locus
, true))
143 // recursively pass this down to all HRTB's
144 for (auto &bound
: param
->get_specified_bounds ())
145 bound
.handle_substitions (subst_mappings
);
147 param
->set_ty_ref (type
.get_ref ());
148 subst_mappings
.on_param_subst (*param
, arg
);
155 SubstitutionParamMapping::override_context ()
157 if (!param
->can_resolve ())
160 auto mappings
= Analysis::Mappings::get ();
161 auto context
= Resolver::TypeCheckContext::get ();
163 context
->insert_type (Analysis::NodeMapping (mappings
->get_current_crate (),
166 UNKNOWN_LOCAL_DEFID
),
170 SubstitutionArg::SubstitutionArg (const SubstitutionParamMapping
*param
,
172 : param (param
), argument (argument
)
174 if (param
!= nullptr)
175 original_param
= param
->get_param_ty ();
178 SubstitutionArg::SubstitutionArg (const SubstitutionArg
&other
)
179 : param (other
.param
), original_param (other
.original_param
),
180 argument (other
.argument
)
184 SubstitutionArg::operator= (const SubstitutionArg
&other
)
187 argument
= other
.argument
;
188 original_param
= other
.original_param
;
194 SubstitutionArg::get_tyty ()
200 SubstitutionArg::get_tyty () const
205 const SubstitutionParamMapping
*
206 SubstitutionArg::get_param_mapping () const
212 SubstitutionArg::get_param_ty () const
214 return original_param
;
218 SubstitutionArg::error ()
220 return SubstitutionArg (nullptr, nullptr);
224 SubstitutionArg::is_error () const
226 return param
== nullptr || argument
== nullptr;
230 SubstitutionArg::is_conrete () const
232 if (argument
== nullptr)
235 if (argument
->get_kind () == TyTy::TypeKind::PARAM
)
238 return argument
->is_concrete ();
242 SubstitutionArg::as_string () const
244 return original_param
->as_string ()
245 + (argument
!= nullptr ? ":" + argument
->as_string () : "");
248 const RegionParamList
&
249 SubstitutionArgumentMappings::get_regions () const
255 SubstitutionArgumentMappings::get_mut_regions ()
260 // SubstitutionArgumentMappings
262 SubstitutionArgumentMappings::SubstitutionArgumentMappings (
263 std::vector
<SubstitutionArg
> mappings
,
264 std::map
<std::string
, BaseType
*> binding_args
, RegionParamList regions
,
265 location_t locus
, ParamSubstCb param_subst_cb
, bool trait_item_flag
,
267 : mappings (std::move (mappings
)), binding_args (binding_args
),
268 regions (regions
), locus (locus
), param_subst_cb (param_subst_cb
),
269 trait_item_flag (trait_item_flag
), error_flag (error_flag
)
272 SubstitutionArgumentMappings::SubstitutionArgumentMappings (
273 const SubstitutionArgumentMappings
&other
)
274 : mappings (other
.mappings
), binding_args (other
.binding_args
),
275 regions (other
.regions
), locus (other
.locus
), param_subst_cb (nullptr),
276 trait_item_flag (other
.trait_item_flag
), error_flag (other
.error_flag
)
279 SubstitutionArgumentMappings
&
280 SubstitutionArgumentMappings::operator= (
281 const SubstitutionArgumentMappings
&other
)
283 mappings
= other
.mappings
;
284 binding_args
= other
.binding_args
;
285 regions
= other
.regions
;
287 param_subst_cb
= nullptr;
288 trait_item_flag
= other
.trait_item_flag
;
289 error_flag
= other
.error_flag
;
294 SubstitutionArgumentMappings
295 SubstitutionArgumentMappings::error ()
297 return SubstitutionArgumentMappings ({}, {}, 0, UNDEF_LOCATION
, nullptr,
301 SubstitutionArgumentMappings
302 SubstitutionArgumentMappings::empty (size_t num_regions
)
304 return SubstitutionArgumentMappings ({}, {}, num_regions
, UNDEF_LOCATION
,
305 nullptr, false, false);
309 SubstitutionArgumentMappings::is_error () const
315 SubstitutionArgumentMappings::get_argument_for_symbol (
316 const ParamType
*param_to_find
, SubstitutionArg
*argument
) const
318 for (const auto &mapping
: mappings
)
320 const ParamType
*p
= mapping
.get_param_ty ();
321 if (p
->get_symbol () == param_to_find
->get_symbol ())
330 SubstitutionArgumentMappings::find_symbol (const ParamType
¶m_to_find
) const
332 auto it
= std::find_if (mappings
.begin (), mappings
.end (),
333 [param_to_find
] (const SubstitutionArg
&arg
) {
334 return arg
.get_param_ty ()->get_symbol ()
335 == param_to_find
.get_symbol ();
337 if (it
== mappings
.end ())
339 return std::distance (mappings
.begin (), it
);
343 SubstitutionArgumentMappings::get_argument_at (size_t index
,
344 SubstitutionArg
*argument
)
346 if (index
> mappings
.size ())
349 *argument
= mappings
.at (index
);
354 SubstitutionArgumentMappings::is_concrete () const
356 for (auto &mapping
: mappings
)
358 if (!mapping
.is_conrete ())
365 SubstitutionArgumentMappings::get_locus () const
371 SubstitutionArgumentMappings::size () const
373 return mappings
.size ();
377 SubstitutionArgumentMappings::is_empty () const
382 std::vector
<SubstitutionArg
> &
383 SubstitutionArgumentMappings::get_mappings ()
388 const std::vector
<SubstitutionArg
> &
389 SubstitutionArgumentMappings::get_mappings () const
394 std::map
<std::string
, BaseType
*> &
395 SubstitutionArgumentMappings::get_binding_args ()
400 const std::map
<std::string
, BaseType
*> &
401 SubstitutionArgumentMappings::get_binding_args () const
407 SubstitutionArgumentMappings::as_string () const
410 for (auto &mapping
: mappings
)
412 buffer
+= mapping
.as_string () + ", ";
414 return "<" + buffer
+ ">";
418 SubstitutionArgumentMappings::on_param_subst (const ParamType
&p
,
419 const SubstitutionArg
&a
) const
421 if (param_subst_cb
== nullptr)
424 param_subst_cb (p
, a
);
428 SubstitutionArgumentMappings::get_subst_cb () const
430 return param_subst_cb
;
434 SubstitutionArgumentMappings::trait_item_mode () const
436 return trait_item_flag
;
441 SubstitutionRef::SubstitutionRef (
442 std::vector
<SubstitutionParamMapping
> substitutions
,
443 SubstitutionArgumentMappings arguments
, RegionConstraints region_constraints
)
444 : substitutions (substitutions
), used_arguments (arguments
),
445 region_constraints (region_constraints
)
449 SubstitutionRef::has_substitutions () const
451 return substitutions
.size () > 0;
455 SubstitutionRef::subst_as_string () const
458 for (size_t i
= 0; i
< substitutions
.size (); i
++)
460 const SubstitutionParamMapping
&sub
= substitutions
.at (i
);
461 buffer
+= sub
.as_string ();
463 if ((i
+ 1) < substitutions
.size ())
467 return buffer
.empty () ? "" : "<" + buffer
+ ">";
471 SubstitutionRef::supports_associated_bindings () const
473 return get_num_associated_bindings () > 0;
477 SubstitutionRef::get_num_associated_bindings () const
482 TypeBoundPredicateItem
483 SubstitutionRef::lookup_associated_type (const std::string
&search
)
485 return TypeBoundPredicateItem::error ();
489 SubstitutionRef::get_num_substitutions () const
491 return substitutions
.size ();
494 SubstitutionRef::get_num_lifetime_params () const
496 return used_arguments
.get_regions ().size ();
499 SubstitutionRef::get_num_type_params () const
501 return get_num_substitutions ();
504 std::vector
<SubstitutionParamMapping
> &
505 SubstitutionRef::get_substs ()
507 return substitutions
;
510 const std::vector
<SubstitutionParamMapping
> &
511 SubstitutionRef::get_substs () const
513 return substitutions
;
516 std::vector
<SubstitutionParamMapping
>
517 SubstitutionRef::clone_substs () const
519 std::vector
<SubstitutionParamMapping
> clone
;
521 for (auto &sub
: substitutions
)
522 clone
.push_back (sub
.clone ());
528 SubstitutionRef::override_context ()
530 for (auto &sub
: substitutions
)
532 sub
.override_context ();
537 SubstitutionRef::needs_substitution () const
539 return std::any_of (substitutions
.begin (), substitutions
.end (),
541 &SubstitutionParamMapping::needs_substitution
));
545 SubstitutionRef::was_substituted () const
547 return !needs_substitution ();
550 SubstitutionArgumentMappings
&
551 SubstitutionRef::get_substitution_arguments ()
553 return used_arguments
;
556 const SubstitutionArgumentMappings
&
557 SubstitutionRef::get_substitution_arguments () const
559 return used_arguments
;
563 SubstitutionRef::num_required_substitutions () const
566 for (auto &p
: substitutions
)
568 if (p
.needs_substitution ())
575 SubstitutionRef::min_required_substitutions () const
578 for (auto &p
: substitutions
)
580 if (p
.needs_substitution () && !p
.param_has_default_ty ())
586 const SubstitutionArgumentMappings
&
587 SubstitutionRef::get_used_arguments () const
589 return used_arguments
;
592 tl::optional
<SubstitutionArg
>
593 SubstitutionRef::get_arg_at (size_t i
) const
595 auto param_ty
= get_substs ().at (i
).get_param_ty ();
596 SubstitutionArg arg
= SubstitutionArg::error ();
597 get_used_arguments ().get_argument_for_symbol (param_ty
, &arg
);
603 const RegionConstraints
&
604 SubstitutionRef::get_region_constraints () const
606 return region_constraints
;
609 SubstitutionArgumentMappings
610 SubstitutionRef::get_mappings_from_generic_args (
611 HIR::GenericArgs
&args
, const std::vector
<Region
> ®ions
)
613 std::map
<std::string
, BaseType
*> binding_arguments
;
614 if (args
.get_binding_args ().size () > 0)
616 if (supports_associated_bindings ())
618 if (args
.get_binding_args ().size () > get_num_associated_bindings ())
620 rich_location
r (line_table
, args
.get_locus ());
623 "generic item takes at most %lu type binding "
624 "arguments but %lu were supplied",
625 (unsigned long) get_num_associated_bindings (),
626 (unsigned long) args
.get_binding_args ().size ());
627 return SubstitutionArgumentMappings::error ();
630 for (auto &binding
: args
.get_binding_args ())
633 = Resolver::TypeCheckType::Resolve (binding
.get_type ().get ());
634 if (resolved
== nullptr
635 || resolved
->get_kind () == TyTy::TypeKind::ERROR
)
637 rust_error_at (binding
.get_locus (),
638 "failed to resolve type arguments");
639 return SubstitutionArgumentMappings::error ();
642 // resolve to relevant binding
643 auto binding_item
= lookup_associated_type (
644 binding
.get_identifier ().as_string ());
645 if (binding_item
.is_error ())
648 binding
.get_locus (), "unknown associated type binding: %s",
649 binding
.get_identifier ().as_string ().c_str ());
650 return SubstitutionArgumentMappings::error ();
653 binding_arguments
[binding
.get_identifier ().as_string ()]
659 rich_location
r (line_table
, args
.get_locus ());
660 for (auto &binding
: args
.get_binding_args ())
661 r
.add_range (binding
.get_locus ());
663 rust_error_at (r
, ErrorCode::E0229
,
664 "associated type bindings are not allowed here");
665 return SubstitutionArgumentMappings::error ();
669 // for inherited arguments
670 size_t offs
= used_arguments
.size ();
671 if (args
.get_type_args ().size () + offs
> substitutions
.size ())
673 rich_location
r (line_table
, args
.get_locus ());
674 if (!substitutions
.empty ())
675 r
.add_range (substitutions
.front ().get_param_locus ());
679 "generic item takes at most %lu type arguments but %lu were supplied",
680 (unsigned long) substitutions
.size (),
681 (unsigned long) args
.get_type_args ().size ());
682 return SubstitutionArgumentMappings::error ();
685 if (args
.get_type_args ().size () + offs
< min_required_substitutions ())
687 rich_location
r (line_table
, args
.get_locus ());
688 r
.add_range (substitutions
.front ().get_param_locus ());
692 "generic item takes at least %lu type arguments but %lu were supplied",
693 (unsigned long) (min_required_substitutions () - offs
),
694 (unsigned long) args
.get_type_args ().size ());
695 return SubstitutionArgumentMappings::error ();
698 std::vector
<SubstitutionArg
> mappings
= used_arguments
.get_mappings ();
699 for (auto &arg
: args
.get_type_args ())
701 BaseType
*resolved
= Resolver::TypeCheckType::Resolve (arg
.get ());
702 if (resolved
== nullptr || resolved
->get_kind () == TyTy::TypeKind::ERROR
)
704 rust_error_at (args
.get_locus (), "failed to resolve type arguments");
705 return SubstitutionArgumentMappings::error ();
708 SubstitutionArg
subst_arg (&substitutions
.at (offs
), resolved
);
710 mappings
.push_back (std::move (subst_arg
));
713 // we must need to fill out defaults
715 = num_required_substitutions () - min_required_substitutions ();
718 for (size_t offs
= mappings
.size (); offs
< substitutions
.size (); offs
++)
720 SubstitutionParamMapping
¶m
= substitutions
.at (offs
);
721 rust_assert (param
.param_has_default_ty ());
723 BaseType
*resolved
= param
.get_default_ty ();
724 if (resolved
->get_kind () == TypeKind::ERROR
)
725 return SubstitutionArgumentMappings::error ();
727 // this resolved default might already contain default parameters
728 if (!resolved
->is_concrete ())
730 SubstitutionArgumentMappings
intermediate (
731 mappings
, binding_arguments
,
732 {used_arguments
.get_regions ().size ()}, args
.get_locus ());
733 resolved
= Resolver::SubstMapperInternal::Resolve (resolved
,
736 if (resolved
->get_kind () == TypeKind::ERROR
)
737 return SubstitutionArgumentMappings::error ();
740 SubstitutionArg
subst_arg (¶m
, resolved
);
741 mappings
.push_back (std::move (subst_arg
));
745 return {mappings
, binding_arguments
,
746 RegionParamList::from_subst (used_arguments
.get_regions ().size (),
752 SubstitutionRef::infer_substitions (location_t locus
)
754 std::vector
<SubstitutionArg
> args
;
755 std::map
<std::string
, BaseType
*> argument_mappings
;
756 for (auto &p
: get_substs ())
758 if (p
.needs_substitution ())
760 const std::string
&symbol
= p
.get_param_ty ()->get_symbol ();
761 auto it
= argument_mappings
.find (symbol
);
762 bool have_mapping
= it
!= argument_mappings
.end ();
766 args
.push_back (SubstitutionArg (&p
, it
->second
));
770 TyVar infer_var
= TyVar::get_implicit_infer_var (locus
);
771 args
.push_back (SubstitutionArg (&p
, infer_var
.get_tyty ()));
772 argument_mappings
[symbol
] = infer_var
.get_tyty ();
777 args
.push_back (SubstitutionArg (&p
, p
.get_param_ty ()->resolve ()));
781 // FIXME do we need to add inference variables to all the possible bindings?
782 // it might just lead to inference variable hell not 100% sure if rustc does
783 // this i think the language might needs this to be explicitly set
785 SubstitutionArgumentMappings
infer_arguments (std::move (args
),
786 {} /* binding_arguments */,
787 used_arguments
.get_regions (),
789 return handle_substitions (infer_arguments
);
792 SubstitutionArgumentMappings
793 SubstitutionRef::adjust_mappings_for_this (
794 SubstitutionArgumentMappings
&mappings
)
796 std::vector
<SubstitutionArg
> resolved_mappings
;
797 for (size_t i
= 0; i
< substitutions
.size (); i
++)
799 auto &subst
= substitutions
.at (i
);
801 SubstitutionArg arg
= SubstitutionArg::error ();
802 if (mappings
.size () == substitutions
.size ())
804 mappings
.get_argument_at (i
, &arg
);
808 if (subst
.needs_substitution ())
810 // get from passed in mappings
811 mappings
.get_argument_for_symbol (subst
.get_param_ty (), &arg
);
815 // we should already have this somewhere
816 used_arguments
.get_argument_for_symbol (subst
.get_param_ty (),
821 bool ok
= !arg
.is_error ();
824 SubstitutionArg
adjusted (&subst
, arg
.get_tyty ());
825 resolved_mappings
.push_back (std::move (adjusted
));
829 if (resolved_mappings
.empty ())
830 return SubstitutionArgumentMappings::error ();
832 return SubstitutionArgumentMappings (resolved_mappings
,
833 mappings
.get_binding_args (),
834 mappings
.get_regions (),
835 mappings
.get_locus (),
836 mappings
.get_subst_cb (),
837 mappings
.trait_item_mode ());
841 SubstitutionRef::are_mappings_bound (SubstitutionArgumentMappings
&mappings
)
843 std::vector
<SubstitutionArg
> resolved_mappings
;
844 for (size_t i
= 0; i
< substitutions
.size (); i
++)
846 auto &subst
= substitutions
.at (i
);
848 SubstitutionArg arg
= SubstitutionArg::error ();
849 if (mappings
.size () == substitutions
.size ())
851 mappings
.get_argument_at (i
, &arg
);
855 if (subst
.needs_substitution ())
857 // get from passed in mappings
858 mappings
.get_argument_for_symbol (subst
.get_param_ty (), &arg
);
862 // we should already have this somewhere
863 used_arguments
.get_argument_for_symbol (subst
.get_param_ty (),
868 bool ok
= !arg
.is_error ();
871 SubstitutionArg
adjusted (&subst
, arg
.get_tyty ());
872 resolved_mappings
.push_back (std::move (adjusted
));
876 return !resolved_mappings
.empty ();
879 // this function assumes that the mappings being passed are for the same type as
880 // this new substitution reference so ordering matters here
881 SubstitutionArgumentMappings
882 SubstitutionRef::solve_mappings_from_receiver_for_self (
883 SubstitutionArgumentMappings
&mappings
) const
885 std::vector
<SubstitutionArg
> resolved_mappings
;
887 rust_assert (mappings
.size () == get_num_substitutions ());
888 for (size_t i
= 0; i
< get_num_substitutions (); i
++)
890 const SubstitutionParamMapping
¶m_mapping
= substitutions
.at (i
);
891 SubstitutionArg
&arg
= mappings
.get_mappings ().at (i
);
893 if (param_mapping
.needs_substitution ())
895 SubstitutionArg
adjusted (¶m_mapping
, arg
.get_tyty ());
896 resolved_mappings
.push_back (std::move (adjusted
));
900 return SubstitutionArgumentMappings (resolved_mappings
,
901 mappings
.get_binding_args (),
902 mappings
.get_regions (),
903 mappings
.get_locus ());
907 SubstitutionRef::prepare_higher_ranked_bounds ()
909 for (const auto &subst
: get_substs ())
911 const TyTy::ParamType
*pty
= subst
.get_param_ty ();
912 for (const auto &bound
: pty
->get_specified_bounds ())
914 const auto ref
= bound
.get ();
915 ref
->clear_associated_type_projections ();
921 SubstitutionRef::monomorphize ()
923 for (const auto &subst
: get_substs ())
925 const TyTy::ParamType
*pty
= subst
.get_param_ty ();
927 if (!pty
->can_resolve ())
930 const TyTy::BaseType
*binding
= pty
->resolve ();
931 if (binding
->get_kind () == TyTy::TypeKind::PARAM
)
934 for (const auto &bound
: pty
->get_specified_bounds ())
936 bool ambigious
= false;
938 = Resolver::lookup_associated_impl_block (bound
, binding
,
940 if (associated
== nullptr && ambigious
)
942 // go for the first one? or error out?
943 auto &mappings
= *Analysis::Mappings::get ();
944 const auto &type_param
= subst
.get_generic_param ();
945 const auto *trait_ref
= bound
.get ();
947 rich_location
r (line_table
, type_param
.get_locus ());
948 r
.add_range (bound
.get_locus ());
949 r
.add_range (mappings
.lookup_location (binding
->get_ref ()));
951 rust_error_at (r
, "ambiguous type bound for trait %s and type %s",
952 trait_ref
->get_name ().c_str (),
953 binding
->get_name ().c_str ());
957 if (associated
!= nullptr)
959 associated
->setup_associated_types (binding
, bound
);