rustc_ty_utils/
opaque_types.rs1use rustc_data_structures::fx::FxHashSet;
2use rustc_hir::def::DefKind;
3use rustc_hir::def_id::LocalDefId;
4use rustc_hir::intravisit::Visitor;
5use rustc_hir::{CRATE_HIR_ID, intravisit};
6use rustc_middle::bug;
7use rustc_middle::query::Providers;
8use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
9use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
10use rustc_span::Span;
11use tracing::{instrument, trace};
12
13use crate::errors::{DuplicateArg, NotParam};
14
15struct OpaqueTypeCollector<'tcx> {
16 tcx: TyCtxt<'tcx>,
17 opaques: Vec<LocalDefId>,
18 item: LocalDefId,
20
21 seen: FxHashSet<LocalDefId>,
23
24 span: Option<Span>,
25
26 mode: CollectionMode,
27}
28
29enum CollectionMode {
30 ImplTraitInAssocTypes,
33 TypeAliasImplTraitTransition,
34}
35
36impl<'tcx> OpaqueTypeCollector<'tcx> {
37 fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self {
38 let mode = match tcx.def_kind(tcx.local_parent(item)) {
39 DefKind::Impl { of_trait: true } => CollectionMode::ImplTraitInAssocTypes,
40 _ => CollectionMode::TypeAliasImplTraitTransition,
41 };
42 Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None, mode }
43 }
44
45 fn span(&self) -> Span {
46 self.span.unwrap_or_else(|| {
47 self.tcx.def_ident_span(self.item).unwrap_or_else(|| self.tcx.def_span(self.item))
48 })
49 }
50
51 fn visit_spanned(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) {
52 let old = self.span;
53 self.span = Some(span);
54 value.visit_with(self);
55 self.span = old;
56 }
57
58 fn parent_impl_trait_ref(&self) -> Option<ty::TraitRef<'tcx>> {
59 let parent = self.parent()?;
60 if matches!(self.tcx.def_kind(parent), DefKind::Impl { .. }) {
61 Some(self.tcx.impl_trait_ref(parent)?.instantiate_identity())
62 } else {
63 None
64 }
65 }
66
67 fn parent(&self) -> Option<LocalDefId> {
68 match self.tcx.def_kind(self.item) {
69 DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
70 Some(self.tcx.local_parent(self.item))
71 }
72 _ => None,
73 }
74 }
75
76 #[instrument(level = "trace", skip(self), ret)]
96 fn check_tait_defining_scope(&self, opaque_def_id: LocalDefId) -> bool {
97 let mut hir_id = self.tcx.local_def_id_to_hir_id(self.item);
98 let opaque_hir_id = self.tcx.local_def_id_to_hir_id(opaque_def_id);
99
100 let scope = self.tcx.hir().get_defining_scope(opaque_hir_id);
102 while hir_id != scope && hir_id != CRATE_HIR_ID {
104 hir_id = self.tcx.hir().get_parent_item(hir_id).into();
105 }
106 hir_id == scope
108 }
109
110 #[instrument(level = "trace", skip(self))]
111 fn collect_taits_declared_in_body(&mut self) {
112 let body = self.tcx.hir().body_owned_by(self.item).value;
113 struct TaitInBodyFinder<'a, 'tcx> {
114 collector: &'a mut OpaqueTypeCollector<'tcx>,
115 }
116 impl<'v> intravisit::Visitor<'v> for TaitInBodyFinder<'_, '_> {
117 #[instrument(level = "trace", skip(self))]
118 fn visit_nested_item(&mut self, id: rustc_hir::ItemId) {
119 let id = id.owner_id.def_id;
120 if let DefKind::TyAlias = self.collector.tcx.def_kind(id) {
121 let items = self.collector.tcx.opaque_types_defined_by(id);
122 self.collector.opaques.extend(items);
123 }
124 }
125 #[instrument(level = "trace", skip(self))]
126 fn visit_nested_body(&mut self, id: rustc_hir::BodyId) {
128 let body = self.collector.tcx.hir().body(id);
129 self.visit_body(body);
130 }
131 }
132 TaitInBodyFinder { collector: self }.visit_expr(body);
133 }
134
135 #[instrument(level = "debug", skip(self))]
136 fn visit_opaque_ty(&mut self, alias_ty: ty::AliasTy<'tcx>) {
137 if !self.seen.insert(alias_ty.def_id.expect_local()) {
138 return;
139 }
140
141 let origin = self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local());
143 trace!(?origin);
144 match origin {
145 rustc_hir::OpaqueTyOrigin::FnReturn { .. }
146 | rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {}
147 rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => {
148 if !in_assoc_ty && !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
149 return;
150 }
151 }
152 }
153
154 self.opaques.push(alias_ty.def_id.expect_local());
155
156 let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count;
157 match self
161 .tcx
162 .uses_unique_generic_params(&alias_ty.args[..parent_count], CheckRegions::FromFunction)
163 {
164 Ok(()) => {
165 for (pred, span) in
173 self.tcx.explicit_item_bounds(alias_ty.def_id).iter_identity_copied()
174 {
175 trace!(?pred);
176 self.visit_spanned(span, pred);
177 }
178 }
179 Err(NotUniqueParam::NotParam(arg)) => {
180 self.tcx.dcx().emit_err(NotParam {
181 arg,
182 span: self.span(),
183 opaque_span: self.tcx.def_span(alias_ty.def_id),
184 });
185 }
186 Err(NotUniqueParam::DuplicateParam(arg)) => {
187 self.tcx.dcx().emit_err(DuplicateArg {
188 arg,
189 span: self.span(),
190 opaque_span: self.tcx.def_span(alias_ty.def_id),
191 });
192 }
193 }
194 }
195}
196
197impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
198 #[instrument(skip(self), ret, level = "trace")]
199 fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) {
200 self.visit_spanned(span, value);
201 }
202}
203
204impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
205 #[instrument(skip(self), ret, level = "trace")]
206 fn visit_ty(&mut self, t: Ty<'tcx>) {
207 t.super_visit_with(self);
208 match *t.kind() {
209 ty::Alias(ty::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
210 self.visit_opaque_ty(alias_ty);
211 }
212 ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => {
214 self.tcx
215 .type_of(alias_ty.def_id)
216 .instantiate(self.tcx, alias_ty.args)
217 .visit_with(self);
218 }
219 ty::Alias(ty::Projection, alias_ty) => {
220 if let Some(impl_trait_ref) = self.parent_impl_trait_ref() {
224 if alias_ty.trait_ref(self.tcx) == impl_trait_ref {
228 let parent = self.parent().expect("we should have a parent here");
229
230 for &assoc in self.tcx.associated_items(parent).in_definition_order() {
231 trace!(?assoc);
232 if assoc.trait_item_def_id != Some(alias_ty.def_id) {
233 continue;
234 }
235
236 if !assoc.defaultness(self.tcx).is_final() {
239 continue;
240 }
241
242 if !self.seen.insert(assoc.def_id.expect_local()) {
243 return;
244 }
245
246 let impl_args = alias_ty.args.rebase_onto(
247 self.tcx,
248 impl_trait_ref.def_id,
249 ty::GenericArgs::identity_for_item(self.tcx, parent),
250 );
251
252 if self.tcx.check_args_compatible(assoc.def_id, impl_args) {
253 self.tcx
254 .type_of(assoc.def_id)
255 .instantiate(self.tcx, impl_args)
256 .visit_with(self);
257 return;
258 } else {
259 self.tcx.dcx().span_delayed_bug(
260 self.tcx.def_span(assoc.def_id),
261 "item had incorrect args",
262 );
263 }
264 }
265 }
266 } else if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) =
267 self.tcx.opt_rpitit_info(alias_ty.def_id)
268 && fn_def_id == self.item.into()
269 {
270 let ty = self.tcx.type_of(alias_ty.def_id).instantiate(self.tcx, alias_ty.args);
282 let ty::Alias(ty::Opaque, alias_ty) = *ty.kind() else { bug!("{ty:?}") };
283 self.visit_opaque_ty(alias_ty);
284 }
285 }
286 ty::Adt(def, _) if def.did().is_local() => {
287 if let CollectionMode::ImplTraitInAssocTypes = self.mode {
288 return;
289 }
290 if !self.seen.insert(def.did().expect_local()) {
291 return;
292 }
293 for variant in def.variants().iter() {
294 for field in variant.fields.iter() {
295 let ty = self.tcx.type_of(field.did).instantiate_identity();
304 self.visit_spanned(self.tcx.def_span(field.did), ty);
305 }
306 }
307 }
308 _ => trace!(kind=?t.kind()),
309 }
310 }
311}
312
313fn opaque_types_defined_by<'tcx>(
314 tcx: TyCtxt<'tcx>,
315 item: LocalDefId,
316) -> &'tcx ty::List<LocalDefId> {
317 let kind = tcx.def_kind(item);
318 trace!(?kind);
319 let mut collector = OpaqueTypeCollector::new(tcx, item);
320 super::sig_types::walk_types(tcx, item, &mut collector);
321 match kind {
322 DefKind::AssocFn
323 | DefKind::Fn
324 | DefKind::Static { .. }
325 | DefKind::Const
326 | DefKind::AssocConst
327 | DefKind::AnonConst => {
328 collector.collect_taits_declared_in_body();
329 }
330 DefKind::OpaqueTy
331 | DefKind::TyAlias
332 | DefKind::AssocTy
333 | DefKind::Mod
334 | DefKind::Struct
335 | DefKind::Union
336 | DefKind::Enum
337 | DefKind::Variant
338 | DefKind::Trait
339 | DefKind::ForeignTy
340 | DefKind::TraitAlias
341 | DefKind::TyParam
342 | DefKind::ConstParam
343 | DefKind::Ctor(_, _)
344 | DefKind::Macro(_)
345 | DefKind::ExternCrate
346 | DefKind::Use
347 | DefKind::ForeignMod
348 | DefKind::Field
349 | DefKind::LifetimeParam
350 | DefKind::GlobalAsm
351 | DefKind::Impl { .. }
352 | DefKind::SyntheticCoroutineBody => {}
353 DefKind::Closure | DefKind::InlineConst => {
356 collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item)));
357 }
358 }
359 tcx.mk_local_def_ids(&collector.opaques)
360}
361
362pub(super) fn provide(providers: &mut Providers) {
363 *providers = Providers { opaque_types_defined_by, ..*providers };
364}