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-trait-resolve.h"
20 #include "rust-hir-type-check-expr.h"
21 #include "rust-substitution-mapper.h"
22 #include "rust-type-util.h"
28 ResolveTraitItemToRef::Resolve (
29 HIR::TraitItem
&item
, TyTy::BaseType
*self
,
30 std::vector
<TyTy::SubstitutionParamMapping
> substitutions
)
32 ResolveTraitItemToRef
resolver (self
, std::move (substitutions
));
33 item
.accept_vis (resolver
);
34 return std::move (resolver
.resolved
);
38 ResolveTraitItemToRef::visit (HIR::TraitItemType
&type
)
40 // create trait-item-ref
41 location_t locus
= type
.get_locus ();
42 bool is_optional
= false;
43 std::string identifier
= type
.get_name ().as_string ();
45 resolved
= TraitItemReference (identifier
, is_optional
,
46 TraitItemReference::TraitItemType::TYPE
, &type
,
47 self
, substitutions
, locus
);
51 ResolveTraitItemToRef::visit (HIR::TraitItemConst
&cst
)
53 // create trait-item-ref
54 location_t locus
= cst
.get_locus ();
55 bool is_optional
= cst
.has_expr ();
56 std::string identifier
= cst
.get_name ().as_string ();
58 resolved
= TraitItemReference (identifier
, is_optional
,
59 TraitItemReference::TraitItemType::CONST
, &cst
,
60 self
, substitutions
, locus
);
64 ResolveTraitItemToRef::visit (HIR::TraitItemFunc
&fn
)
66 // create trait-item-ref
67 location_t locus
= fn
.get_locus ();
68 bool is_optional
= fn
.has_block_defined ();
69 std::string identifier
= fn
.get_decl ().get_function_name ().as_string ();
71 resolved
= TraitItemReference (identifier
, is_optional
,
72 TraitItemReference::TraitItemType::FN
, &fn
,
73 self
, std::move (substitutions
), locus
);
76 ResolveTraitItemToRef::ResolveTraitItemToRef (
78 std::vector
<TyTy::SubstitutionParamMapping
> &&substitutions
)
79 : TypeCheckBase (), resolved (TraitItemReference::error ()), self (self
),
80 substitutions (std::move (substitutions
))
83 // TraitItemReference items
86 TraitResolver::Resolve (HIR::TypePath
&path
)
88 TraitResolver resolver
;
89 return resolver
.resolve_path (path
);
93 TraitResolver::Resolve (HIR::Trait
&trait
)
95 TraitResolver resolver
;
96 return resolver
.resolve_trait (&trait
);
100 TraitResolver::Lookup (HIR::TypePath
&path
)
102 TraitResolver resolver
;
103 return resolver
.lookup_path (path
);
106 TraitResolver::TraitResolver () : TypeCheckBase () {}
109 TraitResolver::resolve_path_to_trait (const HIR::TypePath
&path
,
110 HIR::Trait
**resolved
) const
113 if (!resolver
->lookup_resolved_type (path
.get_mappings ().get_nodeid (),
116 rust_error_at (path
.get_locus (), "Failed to resolve path to node-id");
120 HirId hir_node
= UNKNOWN_HIRID
;
121 if (!mappings
->lookup_node_to_hir (ref
, &hir_node
))
123 rust_error_at (path
.get_locus (), "Failed to resolve path to hir-id");
127 HIR::Item
*resolved_item
= mappings
->lookup_hir_item (hir_node
);
128 rust_assert (resolved_item
!= nullptr);
129 rust_assert (resolved_item
->get_item_kind () == HIR::Item::ItemKind::Trait
);
130 *resolved
= static_cast<HIR::Trait
*> (resolved_item
);
136 TraitResolver::resolve_path (HIR::TypePath
&path
)
138 HIR::Trait
*resolved_trait_reference
;
139 bool ok
= resolve_path_to_trait (path
, &resolved_trait_reference
);
141 return &TraitReference::error_node ();
143 return resolve_trait (resolved_trait_reference
);
147 TraitResolver::resolve_trait (HIR::Trait
*trait_reference
)
149 TraitReference
*tref
= &TraitReference::error_node ();
150 if (context
->lookup_trait_reference (
151 trait_reference
->get_mappings ().get_defid (), &tref
))
156 DefId trait_id
= trait_reference
->get_mappings ().get_defid ();
157 if (context
->trait_query_in_progress (trait_id
))
160 trait_reference
->get_locus (), ErrorCode::E0391
,
161 "cycle detected when computing the super predicates of %qs",
162 trait_reference
->get_name ().as_string ().c_str ());
163 return &TraitReference::error_node ();
166 TraitQueryGuard
guard (trait_id
);
167 TyTy::BaseType
*self
= nullptr;
168 std::vector
<TyTy::SubstitutionParamMapping
> substitutions
;
170 // this needs to be special cased for the sized trait to not auto implemented
172 for (auto &generic_param
: trait_reference
->get_generic_params ())
174 switch (generic_param
.get ()->get_kind ())
176 case HIR::GenericParam::GenericKind::LIFETIME
:
177 case HIR::GenericParam::GenericKind::CONST
:
178 // FIXME: Skipping Lifetime and Const completely until better
182 case HIR::GenericParam::GenericKind::TYPE
: {
183 auto &typaram
= static_cast<HIR::TypeParam
&> (*generic_param
);
185 = typaram
.get_type_representation ().as_string ().compare ("Self")
188 // https://doc.rust-lang.org/std/marker/trait.Sized.html
189 // The one exception is the implicit Self type of a trait
190 bool apply_sized
= !is_self
;
192 = TypeResolveGenericParam::Resolve (generic_param
.get (),
194 context
->insert_type (generic_param
->get_mappings (), param_type
);
195 substitutions
.push_back (
196 TyTy::SubstitutionParamMapping (typaram
, param_type
));
200 rust_assert (param_type
->get_kind () == TyTy::TypeKind::PARAM
);
202 = static_cast<TyTy::ParamType
*> (param_type
);
203 p
->set_implicit_self_trait ();
210 rust_assert (self
!= nullptr);
212 // Check if there is a super-trait, and apply this bound to the Self
214 std::vector
<TyTy::TypeBoundPredicate
> specified_bounds
;
216 // copy the substitition mappings
217 std::vector
<TyTy::SubstitutionParamMapping
> self_subst_copy
;
218 for (auto &sub
: substitutions
)
219 self_subst_copy
.push_back (sub
.clone ());
221 // They also inherit themselves as a bound this enables a trait item to
222 // reference other Self::trait_items
224 = TyTy::TypeBoundPredicate (trait_reference
->get_mappings ().get_defid (),
225 std::move (self_subst_copy
),
226 BoundPolarity::RegularBound
,
227 trait_reference
->get_locus ());
228 specified_bounds
.push_back (self_hrtb
);
231 std::vector
<const TraitReference
*> super_traits
;
232 if (trait_reference
->has_type_param_bounds ())
234 for (auto &bound
: trait_reference
->get_type_param_bounds ())
236 if (bound
->get_bound_type ()
237 == HIR::TypeParamBound::BoundType::TRAITBOUND
)
240 = static_cast<HIR::TraitBound
*> (bound
.get ());
242 auto predicate
= get_predicate_from_bound (
244 nullptr /*this will setup a PLACEHOLDER for self*/);
245 if (predicate
.is_error ())
246 return &TraitReference::error_node ();
248 specified_bounds
.push_back (predicate
);
249 super_traits
.push_back (predicate
.get ());
253 self
->inherit_bounds (specified_bounds
);
255 std::vector
<TraitItemReference
> item_refs
;
256 for (auto &item
: trait_reference
->get_trait_items ())
258 // make a copy of the substs
259 std::vector
<TyTy::SubstitutionParamMapping
> item_subst
;
260 for (auto &sub
: substitutions
)
261 item_subst
.push_back (sub
.clone ());
263 TraitItemReference trait_item_ref
264 = ResolveTraitItemToRef::Resolve (*item
.get (), self
,
265 std::move (item_subst
));
266 item_refs
.push_back (std::move (trait_item_ref
));
269 TraitReference
trait_object (trait_reference
, item_refs
,
270 std::move (super_traits
),
271 std::move (substitutions
));
272 context
->insert_trait_reference (
273 trait_reference
->get_mappings ().get_defid (), std::move (trait_object
));
275 tref
= &TraitReference::error_node ();
276 bool ok
= context
->lookup_trait_reference (
277 trait_reference
->get_mappings ().get_defid (), &tref
);
280 // hook to allow the trait to resolve its optional item blocks, we cant
281 // resolve the blocks of functions etc because it can end up in a recursive
282 // loop of trying to resolve traits as required by the types
283 tref
->on_resolved ();
289 TraitResolver::lookup_path (HIR::TypePath
&path
)
291 HIR::Trait
*resolved_trait_reference
;
292 bool ok
= resolve_path_to_trait (path
, &resolved_trait_reference
);
294 return &TraitReference::error_node ();
296 TraitReference
*tref
= &TraitReference::error_node ();
297 if (context
->lookup_trait_reference (
298 resolved_trait_reference
->get_mappings ().get_defid (), &tref
))
302 return &TraitReference::error_node ();
306 TraitItemReference::on_resolved ()
311 resolve_item (static_cast<HIR::TraitItemConst
&> (*hir_trait_item
));
315 resolve_item (static_cast<HIR::TraitItemType
&> (*hir_trait_item
));
319 resolve_item (static_cast<HIR::TraitItemFunc
&> (*hir_trait_item
));
328 TraitItemReference::resolve_item (HIR::TraitItemType
&type
)
331 = new TyTy::PlaceholderType (type
.get_name ().as_string (),
332 type
.get_mappings ().get_hirid ());
333 context
->insert_type (type
.get_mappings (), ty
);
337 TraitItemReference::resolve_item (HIR::TraitItemConst
&constant
)
343 TraitItemReference::resolve_item (HIR::TraitItemFunc
&func
)
345 TyTy::BaseType
*item_tyty
= get_tyty ();
346 if (item_tyty
->get_kind () == TyTy::TypeKind::ERROR
)
352 // check the block and return types
353 rust_assert (item_tyty
->get_kind () == TyTy::TypeKind::FNDEF
);
355 // need to get the return type from this
356 TyTy::FnType
*resolved_fn_type
= static_cast<TyTy::FnType
*> (item_tyty
);
357 auto expected_ret_tyty
= resolved_fn_type
->get_return_type ();
358 context
->push_return_type (TypeCheckContextItem (&func
), expected_ret_tyty
);
360 auto block_expr_ty
= TypeCheckExpr::Resolve (func
.get_block_expr ().get ());
362 location_t fn_return_locus
363 = func
.get_decl ().has_return_type ()
364 ? func
.get_decl ().get_return_type ()->get_locus ()
367 coercion_site (func
.get_mappings ().get_hirid (),
368 TyTy::TyWithLocation (expected_ret_tyty
, fn_return_locus
),
369 TyTy::TyWithLocation (block_expr_ty
), func
.get_locus ());
371 context
->pop_return_type ();
375 TraitItemReference::associated_type_set (TyTy::BaseType
*ty
) const
377 rust_assert (get_trait_item_type () == TraitItemType::TYPE
);
379 TyTy::BaseType
*item_ty
= get_tyty ();
380 rust_assert (item_ty
->get_kind () == TyTy::TypeKind::PLACEHOLDER
);
381 TyTy::PlaceholderType
*placeholder
382 = static_cast<TyTy::PlaceholderType
*> (item_ty
);
384 placeholder
->set_associated_type (ty
->get_ty_ref ());
388 TraitItemReference::associated_type_reset (bool only_projections
) const
390 rust_assert (get_trait_item_type () == TraitItemType::TYPE
);
392 TyTy::BaseType
*item_ty
= get_tyty ();
393 rust_assert (item_ty
->get_kind () == TyTy::TypeKind::PLACEHOLDER
);
394 TyTy::PlaceholderType
*placeholder
395 = static_cast<TyTy::PlaceholderType
*> (item_ty
);
397 if (!only_projections
)
399 placeholder
->clear_associated_type ();
403 if (!placeholder
->can_resolve ())
406 const TyTy::BaseType
*r
= placeholder
->resolve ();
407 if (r
->get_kind () == TyTy::TypeKind::PROJECTION
)
409 placeholder
->clear_associated_type ();
415 AssociatedImplTrait::setup_raw_associated_types ()
417 auto &impl_items
= impl
->get_impl_items ();
418 for (auto &impl_item
: impl_items
)
420 bool is_type_alias
= impl_item
->get_impl_item_type ()
421 == HIR::ImplItem::ImplItemType::TYPE_ALIAS
;
425 HIR::TypeAlias
&type
= *static_cast<HIR::TypeAlias
*> (impl_item
.get ());
427 TraitItemReference
*resolved_trait_item
= nullptr;
429 = trait
->lookup_trait_item (type
.get_new_type_name ().as_string (),
430 &resolved_trait_item
);
433 if (resolved_trait_item
->get_trait_item_type ()
434 != TraitItemReference::TraitItemType::TYPE
)
437 TyTy::BaseType
*lookup
;
438 ok
= context
->lookup_type (type
.get_mappings ().get_hirid (), &lookup
);
441 resolved_trait_item
->associated_type_set (lookup
);
446 AssociatedImplTrait::setup_associated_types (
447 const TyTy::BaseType
*self
, const TyTy::TypeBoundPredicate
&bound
,
448 TyTy::SubstitutionArgumentMappings
*args
)
450 // compute the constrained impl block generic arguments based on self and the
451 // higher ranked trait bound
452 TyTy::BaseType
*receiver
= self
->clone ();
454 // impl<Y> SliceIndex<[Y]> for Range<usize>
456 // I: SliceIndex<[<integer>]> and Range<<integer>>
458 // we need to figure out what Y is
460 TyTy::BaseType
*associated_self
= get_self ();
462 rust_debug ("setup_associated_types for: %s->%s bound %s",
463 associated_self
->debug_str ().c_str (),
464 self
->debug_str ().c_str (), bound
.as_string ().c_str ());
466 // grab the parameters
467 HIR::ImplBlock
&impl_block
= *get_impl_block ();
468 std::vector
<TyTy::SubstitutionParamMapping
> substitutions
;
469 for (auto &generic_param
: impl_block
.get_generic_params ())
471 switch (generic_param
.get ()->get_kind ())
473 case HIR::GenericParam::GenericKind::LIFETIME
:
474 case HIR::GenericParam::GenericKind::CONST
:
475 // FIXME: Skipping Lifetime and Const completely until better
479 case HIR::GenericParam::GenericKind::TYPE
: {
480 TyTy::BaseType
*l
= nullptr;
481 bool ok
= context
->lookup_type (
482 generic_param
->get_mappings ().get_hirid (), &l
);
483 if (ok
&& l
->get_kind () == TyTy::TypeKind::PARAM
)
485 substitutions
.push_back (TyTy::SubstitutionParamMapping (
486 static_cast<HIR::TypeParam
&> (*generic_param
),
487 static_cast<TyTy::ParamType
*> (l
)));
494 // this callback gives us the parameters that get substituted so we can
495 // compute the constrained type parameters for this impl block
496 std::map
<std::string
, HirId
> param_mappings
;
497 TyTy::ParamSubstCb param_subst_cb
498 = [&] (const TyTy::ParamType
&p
, const TyTy::SubstitutionArg
&a
) {
499 param_mappings
[p
.get_symbol ()] = a
.get_tyty ()->get_ref ();
502 // generate inference variables for these bound arguments so we can compute
504 location_t locus
= UNKNOWN_LOCATION
;
505 std::vector
<TyTy::SubstitutionArg
> subst_args
;
506 for (auto &p
: substitutions
)
508 if (p
.needs_substitution ())
510 TyTy::TyVar infer_var
= TyTy::TyVar::get_implicit_infer_var (locus
);
511 subst_args
.push_back (
512 TyTy::SubstitutionArg (&p
, infer_var
.get_tyty ()));
516 TyTy::ParamType
*param
= p
.get_param_ty ();
517 TyTy::BaseType
*resolved
= param
->destructure ();
518 subst_args
.push_back (TyTy::SubstitutionArg (&p
, resolved
));
519 param_mappings
[param
->get_symbol ()] = resolved
->get_ref ();
523 TyTy::SubstitutionArgumentMappings
infer_arguments (
524 std::move (subst_args
), {},
525 TyTy::SubstitutionArgumentMappings::regions_from_nullable_args (args
),
526 locus
, param_subst_cb
);
527 TyTy::BaseType
*impl_self_infer
528 = (!associated_self
->is_concrete ())
529 ? SubstMapperInternal::Resolve (associated_self
, infer_arguments
)
532 const TyTy::TypeBoundPredicate
&impl_predicate
533 = associated_self
->lookup_predicate (bound
.get_id ());
534 rust_assert (!impl_predicate
.is_error ());
536 // infer the arguments on the predicate
537 std::vector
<TyTy::BaseType
*> impl_trait_predicate_args
;
539 for (size_t i
= 0; i
< impl_predicate
.get_substs ().size (); i
++)
541 const auto &arg
= impl_predicate
.get_substs ().at (i
);
545 const TyTy::ParamType
*p
= arg
.get_param_ty ();
546 TyTy::BaseType
*r
= p
->resolve ();
547 if (!r
->is_concrete ())
549 r
= SubstMapperInternal::Resolve (r
, infer_arguments
);
551 impl_trait_predicate_args
.push_back (r
);
554 // unify the bounds arguments
555 std::vector
<TyTy::BaseType
*> hrtb_bound_arguments
;
556 for (size_t i
= 0; i
< bound
.get_substs ().size (); i
++)
558 const auto &arg
= bound
.get_substs ().at (i
);
562 const TyTy::ParamType
*p
= arg
.get_param_ty ();
563 TyTy::BaseType
*r
= p
->resolve ();
564 if (!r
->is_concrete ())
566 r
= SubstMapperInternal::Resolve (r
, infer_arguments
);
568 hrtb_bound_arguments
.push_back (r
);
571 rust_assert (impl_trait_predicate_args
.size ()
572 == hrtb_bound_arguments
.size ());
573 for (size_t i
= 0; i
< impl_trait_predicate_args
.size (); i
++)
575 TyTy::BaseType
*a
= impl_trait_predicate_args
.at (i
);
576 TyTy::BaseType
*b
= hrtb_bound_arguments
.at (i
);
578 TyTy::BaseType
*result
579 = unify_site_and (a
->get_ref (), TyTy::TyWithLocation (a
),
580 TyTy::TyWithLocation (b
), impl_predicate
.get_locus (),
581 true /*emit-errors*/, true /*commit-if-ok*/,
582 false /*infer*/, true /*cleanup-on-fail*/);
583 rust_assert (result
->get_kind () != TyTy::TypeKind::ERROR
);
586 // we need to unify the receiver with the impl-block Self so that we compute
587 // the type correctly as our receiver may be generic and we are inferring its
588 // generic arguments and this Self might be the concrete version or vice
590 auto result
= unify_site_and (get_impl_block ()->get_mappings ().get_hirid (),
591 TyTy::TyWithLocation (receiver
),
592 TyTy::TyWithLocation (impl_self_infer
),
593 impl_predicate
.get_locus (),
594 true /*emit-errors*/, true /*commit-if-ok*/,
595 false /*infer*/, true /*cleanup-on-fail*/);
596 rust_assert (result
->get_kind () != TyTy::TypeKind::ERROR
);
597 TyTy::BaseType
*self_result
= result
;
599 // create the argument list
600 std::vector
<TyTy::SubstitutionArg
> associated_arguments
;
601 for (auto &p
: substitutions
)
603 std::string symbol
= p
.get_param_ty ()->get_symbol ();
604 auto it
= param_mappings
.find (symbol
);
605 rust_assert (it
!= param_mappings
.end ());
607 HirId id
= it
->second
;
608 TyTy::BaseType
*argument
= nullptr;
609 bool ok
= context
->lookup_type (id
, &argument
);
612 TyTy::SubstitutionArg
arg (&p
, argument
);
613 associated_arguments
.push_back (arg
);
616 TyTy::SubstitutionArgumentMappings
associated_type_args (
617 std::move (associated_arguments
), {},
618 TyTy::SubstitutionArgumentMappings::regions_from_nullable_args (args
),
621 auto &impl_items
= impl
->get_impl_items ();
622 for (auto &impl_item
: impl_items
)
624 bool is_type_alias
= impl_item
->get_impl_item_type ()
625 == HIR::ImplItem::ImplItemType::TYPE_ALIAS
;
629 HIR::TypeAlias
&type
= *static_cast<HIR::TypeAlias
*> (impl_item
.get ());
631 TraitItemReference
*resolved_trait_item
= nullptr;
633 = trait
->lookup_trait_item (type
.get_new_type_name ().as_string (),
634 &resolved_trait_item
);
637 if (resolved_trait_item
->get_trait_item_type ()
638 != TraitItemReference::TraitItemType::TYPE
)
641 TyTy::BaseType
*lookup
;
642 if (!context
->lookup_type (type
.get_mappings ().get_hirid (), &lookup
))
645 // this might be generic
646 TyTy::BaseType
*substituted
647 = SubstMapperInternal::Resolve (lookup
, associated_type_args
);
648 resolved_trait_item
->associated_type_set (substituted
);
653 *args
= associated_type_args
;
660 AssociatedImplTrait::reset_associated_types ()
662 trait
->clear_associated_types ();
665 Analysis::NodeMapping
666 TraitItemReference::get_parent_trait_mappings () const
668 auto mappings
= Analysis::Mappings::get ();
671 = mappings
->lookup_trait_item_mapping (get_mappings ().get_hirid ());
672 rust_assert (trait
!= nullptr);
674 return trait
->get_mappings ();
678 TraitItemReference::is_object_safe () const
680 // https://doc.rust-lang.org/reference/items/traits.html#object-safety
681 switch (get_trait_item_type ())
683 case TraitItemReference::TraitItemType::FN
: {
684 // lets be boring and just check that this is indeed a method will do
686 const HIR::TraitItem
*item
= get_hir_trait_item ();
687 const HIR::TraitItemFunc
*fn
688 = static_cast<const HIR::TraitItemFunc
*> (item
);
689 return fn
->get_decl ().is_method ();
692 // constants are not available via dyn dispatch and so is not object safe
693 case TraitItemReference::TraitItemType::CONST
:
696 // types are object safe since they are not available via dyn dispatch
697 case TraitItemReference::TraitItemType::TYPE
:
700 // this is just an error so lets just fail it
701 case TraitItemReference::TraitItemType::ERROR
:
707 } // namespace Resolver