|
1 | 1 | use rustc_data_structures::fx::FxHashMap;
|
2 | 2 | use rustc_hir as hir;
|
3 |
| -use rustc_hir::def_id::DefId; |
4 |
| -use rustc_middle::ty::{self, TyCtxt}; |
| 3 | +use rustc_hir::def::DefKind; |
| 4 | +use rustc_hir::def_id::{DefId, LocalDefId}; |
| 5 | +use rustc_hir::definitions::DefPathData; |
| 6 | +use rustc_hir::intravisit::{self, Visitor}; |
| 7 | +use rustc_middle::ty::{self, DefIdTree, TyCtxt}; |
5 | 8 |
|
6 | 9 | pub fn provide(providers: &mut ty::query::Providers) {
|
7 | 10 | *providers = ty::query::Providers {
|
8 | 11 | associated_item,
|
9 | 12 | associated_item_def_ids,
|
10 | 13 | associated_items,
|
| 14 | + associated_items_for_impl_trait_in_trait, |
| 15 | + associated_item_for_impl_trait_in_trait, |
11 | 16 | impl_item_implementor_ids,
|
12 | 17 | ..*providers
|
13 | 18 | };
|
@@ -112,3 +117,97 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
|
112 | 117 | fn_has_self_parameter: has_self,
|
113 | 118 | }
|
114 | 119 | }
|
| 120 | + |
| 121 | +/// Given an `fn_def_id` of a trait or of an impl that implements a given trait: |
| 122 | +/// if `fn_def_id` is the def id of a function defined inside a trait, then it creates and returns |
| 123 | +/// the associated items that correspond to each impl trait in return position for that trait. |
| 124 | +/// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it |
| 125 | +/// creates and returns the associated items that correspond to each impl trait in return position |
| 126 | +/// of the implemented trait. |
| 127 | +fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -> &'_ [DefId] { |
| 128 | + let parent_def_id = tcx.parent(fn_def_id); |
| 129 | + |
| 130 | + match tcx.def_kind(parent_def_id) { |
| 131 | + DefKind::Trait => { |
| 132 | + struct RPITVisitor { |
| 133 | + rpits: Vec<LocalDefId>, |
| 134 | + } |
| 135 | + |
| 136 | + impl<'v> Visitor<'v> for RPITVisitor { |
| 137 | + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { |
| 138 | + if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind { |
| 139 | + self.rpits.push(item_id.owner_id.def_id) |
| 140 | + } |
| 141 | + intravisit::walk_ty(self, ty) |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + let mut visitor = RPITVisitor { rpits: Vec::new() }; |
| 146 | + |
| 147 | + if let Some(output) = tcx.hir().get_fn_output(fn_def_id.expect_local()) { |
| 148 | + visitor.visit_fn_ret_ty(output); |
| 149 | + |
| 150 | + tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { |
| 151 | + tcx.associated_item_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id() |
| 152 | + })) |
| 153 | + } else { |
| 154 | + &[] |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + DefKind::Impl { .. } => { |
| 159 | + let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[] }; |
| 160 | + |
| 161 | + tcx.arena.alloc_from_iter( |
| 162 | + tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id).iter().map( |
| 163 | + move |trait_assoc_def_id| { |
| 164 | + impl_associated_item_for_impl_trait_in_trait( |
| 165 | + tcx, |
| 166 | + trait_assoc_def_id.expect_local(), |
| 167 | + fn_def_id.expect_local(), |
| 168 | + ) |
| 169 | + .to_def_id() |
| 170 | + }, |
| 171 | + ), |
| 172 | + ) |
| 173 | + } |
| 174 | + |
| 175 | + def_kind => bug!( |
| 176 | + "associated_items_for_impl_trait_in_trait: {:?} should be Trait or Impl but is {:?}", |
| 177 | + parent_def_id, |
| 178 | + def_kind |
| 179 | + ), |
| 180 | + } |
| 181 | +} |
| 182 | + |
| 183 | +/// Given an `opaque_ty_def_id` corresponding to an impl trait in trait, create and return the |
| 184 | +/// corresponding associated item. |
| 185 | +fn associated_item_for_impl_trait_in_trait( |
| 186 | + tcx: TyCtxt<'_>, |
| 187 | + opaque_ty_def_id: LocalDefId, |
| 188 | +) -> LocalDefId { |
| 189 | + let fn_def_id = tcx.impl_trait_in_trait_parent(opaque_ty_def_id.to_def_id()); |
| 190 | + let trait_def_id = tcx.parent(fn_def_id); |
| 191 | + assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); |
| 192 | + |
| 193 | + let span = tcx.def_span(opaque_ty_def_id); |
| 194 | + let trait_assoc_ty = |
| 195 | + tcx.at(span).create_def(trait_def_id.expect_local(), DefPathData::ImplTraitAssocTy); |
| 196 | + trait_assoc_ty.def_id() |
| 197 | +} |
| 198 | + |
| 199 | +/// Given an `trait_assoc_def_id` that corresponds to a previously synthethized impl trait in trait |
| 200 | +/// into an associated type and an `impl_def_id` corresponding to an impl block, create and return |
| 201 | +/// the corresponding associated item inside the impl block. |
| 202 | +fn impl_associated_item_for_impl_trait_in_trait( |
| 203 | + tcx: TyCtxt<'_>, |
| 204 | + trait_assoc_def_id: LocalDefId, |
| 205 | + impl_fn_def_id: LocalDefId, |
| 206 | +) -> LocalDefId { |
| 207 | + let impl_def_id = tcx.local_parent(impl_fn_def_id); |
| 208 | + |
| 209 | + let span = tcx.def_span(trait_assoc_def_id); |
| 210 | + let impl_assoc_ty = tcx.at(span).create_def(impl_def_id, DefPathData::ImplTraitAssocTy); |
| 211 | + |
| 212 | + impl_assoc_ty.def_id() |
| 213 | +} |
0 commit comments