]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_hir_analysis/src/collect/item_bounds.rs
New upstream version 1.75.0+dfsg1
[rustc.git] / compiler / rustc_hir_analysis / src / collect / item_bounds.rs
1 use super::ItemCtxt;
2 use crate::astconv::{AstConv, PredicateFilter};
3 use rustc_hir as hir;
4 use rustc_infer::traits::util;
5 use rustc_middle::ty::GenericArgs;
6 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder};
7 use rustc_span::def_id::{DefId, LocalDefId};
8 use rustc_span::Span;
9
10 /// For associated types we include both bounds written on the type
11 /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
12 ///
13 /// Note that this filtering is done with the items identity args to
14 /// simplify checking that these bounds are met in impls. This means that
15 /// a bound such as `for<'b> <Self as X<'b>>::U: Clone` can't be used, as in
16 /// `hr-associated-type-bound-1.rs`.
17 fn associated_type_bounds<'tcx>(
18 tcx: TyCtxt<'tcx>,
19 assoc_item_def_id: LocalDefId,
20 ast_bounds: &'tcx [hir::GenericBound<'tcx>],
21 span: Span,
22 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
23 let item_ty = Ty::new_projection(
24 tcx,
25 assoc_item_def_id.to_def_id(),
26 GenericArgs::identity_for_item(tcx, assoc_item_def_id),
27 );
28
29 let icx = ItemCtxt::new(tcx, assoc_item_def_id);
30 let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
31 // Associated types are implicitly sized unless a `?Sized` bound is found
32 icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
33
34 let trait_def_id = tcx.local_parent(assoc_item_def_id);
35 let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
36
37 let bounds_from_parent = trait_predicates
38 .predicates
39 .iter()
40 .copied()
41 .filter(|(pred, _)| match pred.kind().skip_binder() {
42 ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty,
43 ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
44 ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty,
45 _ => false,
46 })
47 .map(|(clause, span)| (clause, span));
48
49 let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
50 debug!(
51 "associated_type_bounds({}) = {:?}",
52 tcx.def_path_str(assoc_item_def_id.to_def_id()),
53 all_bounds
54 );
55 all_bounds
56 }
57
58 /// Opaque types don't inherit bounds from their parent: for return position
59 /// impl trait it isn't possible to write a suitable predicate on the
60 /// containing function and for type-alias impl trait we don't have a backwards
61 /// compatibility issue.
62 #[instrument(level = "trace", skip(tcx), ret)]
63 fn opaque_type_bounds<'tcx>(
64 tcx: TyCtxt<'tcx>,
65 opaque_def_id: LocalDefId,
66 ast_bounds: &'tcx [hir::GenericBound<'tcx>],
67 item_ty: Ty<'tcx>,
68 span: Span,
69 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
70 ty::print::with_no_queries!({
71 let icx = ItemCtxt::new(tcx, opaque_def_id);
72 let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
73 // Opaque types are implicitly sized unless a `?Sized` bound is found
74 icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
75 debug!(?bounds);
76
77 tcx.arena.alloc_from_iter(bounds.clauses())
78 })
79 }
80
81 pub(super) fn explicit_item_bounds(
82 tcx: TyCtxt<'_>,
83 def_id: LocalDefId,
84 ) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
85 match tcx.opt_rpitit_info(def_id.to_def_id()) {
86 // RPITIT's bounds are the same as opaque type bounds, but with
87 // a projection self type.
88 Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
89 let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item();
90 let opaque_ty = item.expect_opaque_ty();
91 return ty::EarlyBinder::bind(opaque_type_bounds(
92 tcx,
93 opaque_def_id.expect_local(),
94 opaque_ty.bounds,
95 Ty::new_projection(
96 tcx,
97 def_id.to_def_id(),
98 ty::GenericArgs::identity_for_item(tcx, def_id),
99 ),
100 item.span,
101 ));
102 }
103 // These should have been fed!
104 Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(),
105 None => {}
106 }
107
108 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
109 let bounds = match tcx.hir().get(hir_id) {
110 hir::Node::TraitItem(hir::TraitItem {
111 kind: hir::TraitItemKind::Type(bounds, _),
112 span,
113 ..
114 }) => associated_type_bounds(tcx, def_id, bounds, *span),
115 hir::Node::Item(hir::Item {
116 kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }),
117 span,
118 ..
119 }) => {
120 let args = GenericArgs::identity_for_item(tcx, def_id);
121 let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
122 opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
123 }
124 // Since RPITITs are astconv'd as projections in `ast_ty_to_ty`, when we're asking
125 // for the item bounds of the *opaques* in a trait's default method signature, we
126 // need to map these projections back to opaques.
127 hir::Node::Item(hir::Item {
128 kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }),
129 span,
130 ..
131 }) => {
132 let (hir::OpaqueTyOrigin::FnReturn(fn_def_id)
133 | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = *origin
134 else {
135 bug!()
136 };
137 let args = GenericArgs::identity_for_item(tcx, def_id);
138 let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
139 tcx.arena.alloc_slice(
140 &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
141 .to_vec()
142 .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }),
143 )
144 }
145 hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
146 _ => bug!("item_bounds called on {:?}", def_id),
147 };
148 ty::EarlyBinder::bind(bounds)
149 }
150
151 pub(super) fn item_bounds(
152 tcx: TyCtxt<'_>,
153 def_id: DefId,
154 ) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
155 tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
156 tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
157 })
158 }
159
160 struct AssocTyToOpaque<'tcx> {
161 tcx: TyCtxt<'tcx>,
162 fn_def_id: DefId,
163 }
164
165 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> {
166 fn interner(&self) -> TyCtxt<'tcx> {
167 self.tcx
168 }
169
170 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
171 if let ty::Alias(ty::Projection, projection_ty) = ty.kind()
172 && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
173 self.tcx.opt_rpitit_info(projection_ty.def_id)
174 && fn_def_id == self.fn_def_id
175 {
176 self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args)
177 } else {
178 ty
179 }
180 }
181 }