rustc_hir_analysis/hir_ty_lowering/
dyn_compatibility.rs

1use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
2use rustc_errors::codes::*;
3use rustc_errors::struct_span_code_err;
4use rustc_hir as hir;
5use rustc_hir::def::{DefKind, Res};
6use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
7use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
8use rustc_middle::ty::{
9    self, BottomUpFolder, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
10    TypeVisitableExt, Upcast,
11};
12use rustc_span::{ErrorGuaranteed, Span};
13use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
14use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
15use smallvec::{SmallVec, smallvec};
16use tracing::{debug, instrument};
17
18use super::HirTyLowerer;
19use crate::hir_ty_lowering::{
20    GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason,
21};
22
23impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24    /// Lower a trait object type from the HIR to our internal notion of a type.
25    #[instrument(level = "debug", skip_all, ret)]
26    pub(super) fn lower_trait_object_ty(
27        &self,
28        span: Span,
29        hir_id: hir::HirId,
30        hir_bounds: &[hir::PolyTraitRef<'tcx>],
31        lifetime: &hir::Lifetime,
32        representation: DynKind,
33    ) -> Ty<'tcx> {
34        let tcx = self.tcx();
35        let dummy_self = tcx.types.trait_object_dummy_self;
36
37        let mut user_written_bounds = Vec::new();
38        let mut potential_assoc_types = Vec::new();
39        for trait_bound in hir_bounds.iter() {
40            if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
41                continue;
42            }
43            if let GenericArgCountResult {
44                correct:
45                    Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
46                ..
47            } = self.lower_poly_trait_ref(
48                &trait_bound.trait_ref,
49                trait_bound.span,
50                hir::BoundConstness::Never,
51                hir::BoundPolarity::Positive,
52                dummy_self,
53                &mut user_written_bounds,
54                PredicateFilter::SelfOnly,
55            ) {
56                potential_assoc_types.extend(cur_potential_assoc_types);
57            }
58        }
59
60        let (elaborated_trait_bounds, elaborated_projection_bounds) =
61            traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
62        let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds
63            .into_iter()
64            .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
65
66        // We  don't support empty trait objects.
67        if regular_traits.is_empty() && auto_traits.is_empty() {
68            let guar = self.report_trait_object_with_no_traits_error(
69                span,
70                user_written_bounds.iter().copied(),
71            );
72            return Ty::new_error(tcx, guar);
73        }
74        // We don't support >1 principal
75        if regular_traits.len() > 1 {
76            let guar = self.report_trait_object_addition_traits_error(&regular_traits);
77            return Ty::new_error(tcx, guar);
78        }
79        // Don't create a dyn trait if we have errors in the principal.
80        if let Err(guar) = regular_traits.error_reported() {
81            return Ty::new_error(tcx, guar);
82        }
83
84        // Check that there are no gross dyn-compatibility violations;
85        // most importantly, that the supertraits don't contain `Self`,
86        // to avoid ICEs.
87        for (clause, span) in user_written_bounds {
88            if let Some(trait_pred) = clause.as_trait_clause() {
89                let violations =
90                    hir_ty_lowering_dyn_compatibility_violations(tcx, trait_pred.def_id());
91                if !violations.is_empty() {
92                    let reported = report_dyn_incompatibility(
93                        tcx,
94                        span,
95                        Some(hir_id),
96                        trait_pred.def_id(),
97                        &violations,
98                    )
99                    .emit();
100                    return Ty::new_error(tcx, reported);
101                }
102            }
103        }
104
105        // Map the projection bounds onto a key that makes it easy to remove redundant
106        // bounds that are constrained by supertraits of the principal def id.
107        //
108        // Also make sure we detect conflicting bounds from expanding a trait alias and
109        // also specifying it manually, like:
110        // ```
111        // type Alias = Trait<Assoc = i32>;
112        // let _: &dyn Alias<Assoc = u32> = /* ... */;
113        // ```
114        let mut projection_bounds = FxIndexMap::default();
115        for (proj, proj_span) in elaborated_projection_bounds {
116            let key = (
117                proj.skip_binder().projection_term.def_id,
118                tcx.anonymize_bound_vars(
119                    proj.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
120                ),
121            );
122            if let Some((old_proj, old_proj_span)) =
123                projection_bounds.insert(key, (proj, proj_span))
124                && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
125            {
126                let item = tcx.item_name(proj.item_def_id());
127                self.dcx()
128                    .struct_span_err(
129                        span,
130                        format!(
131                            "conflicting associated type bounds for `{item}` when \
132                            expanding trait alias"
133                        ),
134                    )
135                    .with_span_label(
136                        old_proj_span,
137                        format!("`{item}` is specified to be `{}` here", old_proj.term()),
138                    )
139                    .with_span_label(
140                        proj_span,
141                        format!("`{item}` is specified to be `{}` here", proj.term()),
142                    )
143                    .emit();
144            }
145        }
146
147        let principal_trait = regular_traits.into_iter().next();
148
149        // A stable ordering of associated types from the principal trait and all its
150        // supertraits. We use this to ensure that different substitutions of a trait
151        // don't result in `dyn Trait` types with different projections lists, which
152        // can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
153        // We achieve a stable ordering by walking over the unsubstituted principal
154        // trait ref.
155        let mut ordered_associated_types = vec![];
156
157        if let Some((principal_trait, ref spans)) = principal_trait {
158            let principal_trait = principal_trait.map_bound(|trait_pred| {
159                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
160                trait_pred.trait_ref
161            });
162
163            for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
164                tcx,
165                [ClauseWithSupertraitSpan::new(
166                    ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
167                    *spans.last().unwrap(),
168                )],
169            )
170            .filter_only_self()
171            {
172                let clause = clause.instantiate_supertrait(tcx, principal_trait);
173                debug!("observing object predicate `{clause:?}`");
174
175                let bound_predicate = clause.kind();
176                match bound_predicate.skip_binder() {
177                    ty::ClauseKind::Trait(pred) => {
178                        // FIXME(negative_bounds): Handle this correctly...
179                        let trait_ref =
180                            tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
181                        ordered_associated_types.extend(
182                            tcx.associated_items(pred.trait_ref.def_id)
183                                .in_definition_order()
184                                // We only care about associated types.
185                                .filter(|item| item.kind == ty::AssocKind::Type)
186                                // No RPITITs -- they're not dyn-compatible for now.
187                                .filter(|item| !item.is_impl_trait_in_trait())
188                                .map(|item| (item.def_id, trait_ref)),
189                        );
190                    }
191                    ty::ClauseKind::Projection(pred) => {
192                        let pred = bound_predicate.rebind(pred);
193                        // A `Self` within the original bound will be instantiated with a
194                        // `trait_object_dummy_self`, so check for that.
195                        let references_self = match pred.skip_binder().term.unpack() {
196                            ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
197                            // FIXME(associated_const_equality): We should walk the const instead of not doing anything
198                            ty::TermKind::Const(_) => false,
199                        };
200
201                        // If the projection output contains `Self`, force the user to
202                        // elaborate it explicitly to avoid a lot of complexity.
203                        //
204                        // The "classically useful" case is the following:
205                        // ```
206                        //     trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
207                        //         type MyOutput;
208                        //     }
209                        // ```
210                        //
211                        // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`,
212                        // but actually supporting that would "expand" to an infinitely-long type
213                        // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
214                        //
215                        // Instead, we force the user to write
216                        // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
217                        // the discussion in #56288 for alternatives.
218                        if !references_self {
219                            let key = (
220                                pred.skip_binder().projection_term.def_id,
221                                tcx.anonymize_bound_vars(
222                                    pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
223                                ),
224                            );
225                            if !projection_bounds.contains_key(&key) {
226                                projection_bounds.insert(key, (pred, supertrait_span));
227                            }
228                        }
229
230                        self.check_elaborated_projection_mentions_input_lifetimes(
231                            pred,
232                            *spans.first().unwrap(),
233                            supertrait_span,
234                        );
235                    }
236                    _ => (),
237                }
238            }
239        }
240
241        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
242        // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an
243        // `Assoc = Foo` bound. `needed_associated_types` contains all associated
244        // types that we expect to be provided by the user, so the following loop
245        // removes all the associated types that have a corresponding `Projection`
246        // clause, either from expanding trait aliases or written by the user.
247        for &(projection_bound, span) in projection_bounds.values() {
248            let def_id = projection_bound.item_def_id();
249            if tcx.generics_require_sized_self(def_id) {
250                tcx.emit_node_span_lint(
251                    UNUSED_ASSOCIATED_TYPE_BOUNDS,
252                    hir_id,
253                    span,
254                    crate::errors::UnusedAssociatedTypeBounds { span },
255                );
256            }
257        }
258
259        // We compute the list of projection bounds taking the ordered associated types,
260        // and check if there was an entry in the collected `projection_bounds`. Those
261        // are computed by first taking the user-written associated types, then elaborating
262        // the principal trait ref, and only using those if there was no user-written.
263        // See note below about how we handle missing associated types with `Self: Sized`,
264        // which are not required to be provided, but are still used if they are provided.
265        let mut missing_assoc_types = FxIndexSet::default();
266        let projection_bounds: Vec<_> = ordered_associated_types
267            .into_iter()
268            .filter_map(|key| {
269                if let Some(assoc) = projection_bounds.get(&key) {
270                    Some(*assoc)
271                } else {
272                    // If the associated type has a `where Self: Sized` bound, then
273                    // we do not need to provide the associated type. This results in
274                    // a `dyn Trait` type that has a different number of projection
275                    // bounds, which may lead to type mismatches.
276                    if !tcx.generics_require_sized_self(key.0) {
277                        missing_assoc_types.insert(key);
278                    }
279                    None
280                }
281            })
282            .collect();
283
284        if let Err(guar) = self.check_for_required_assoc_tys(
285            principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
286            missing_assoc_types,
287            potential_assoc_types,
288            hir_bounds,
289        ) {
290            return Ty::new_error(tcx, guar);
291        }
292
293        // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
294        // `dyn Trait + Send`.
295        // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
296        // the bounds
297        let mut duplicates = FxHashSet::default();
298        auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id()));
299
300        debug!(?principal_trait);
301        debug!(?auto_traits);
302
303        // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
304        let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| {
305            trait_pred.map_bound(|trait_pred| {
306                let trait_ref = trait_pred.trait_ref;
307                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
308                assert_eq!(trait_ref.self_ty(), dummy_self);
309
310                let span = *spans.first().unwrap();
311
312                // Verify that `dummy_self` did not leak inside default type parameters. This
313                // could not be done at path creation, since we need to see through trait aliases.
314                let mut missing_type_params = vec![];
315                let generics = tcx.generics_of(trait_ref.def_id);
316                let args: Vec<_> = trait_ref
317                    .args
318                    .iter()
319                    .enumerate()
320                    // Skip `Self`
321                    .skip(1)
322                    .map(|(index, arg)| {
323                        if arg.walk().any(|arg| arg == dummy_self.into()) {
324                            let param = &generics.own_params[index];
325                            missing_type_params.push(param.name);
326                            Ty::new_misc_error(tcx).into()
327                        } else {
328                            arg
329                        }
330                    })
331                    .collect();
332
333                let empty_generic_args = hir_bounds.iter().any(|hir_bound| {
334                    hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
335                        && hir_bound.span.contains(span)
336                });
337                self.complain_about_missing_type_params(
338                    missing_type_params,
339                    trait_ref.def_id,
340                    span,
341                    empty_generic_args,
342                );
343
344                ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new(
345                    tcx,
346                    trait_ref.def_id,
347                    args,
348                ))
349            })
350        });
351
352        let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
353            bound.map_bound(|mut b| {
354                assert_eq!(b.projection_term.self_ty(), dummy_self);
355
356                // Like for trait refs, verify that `dummy_self` did not leak inside default type
357                // parameters.
358                let references_self = b.projection_term.args.iter().skip(1).any(|arg| {
359                    if arg.walk().any(|arg| arg == dummy_self.into()) {
360                        return true;
361                    }
362                    false
363                });
364                if references_self {
365                    let guar = tcx
366                        .dcx()
367                        .span_delayed_bug(span, "trait object projection bounds reference `Self`");
368                    b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
369                }
370
371                ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
372                    tcx, b,
373                ))
374            })
375        });
376
377        let mut auto_trait_predicates: Vec<_> = auto_traits
378            .into_iter()
379            .map(|(trait_pred, _)| {
380                assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
381                assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
382
383                ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
384            })
385            .collect();
386        auto_trait_predicates.dedup();
387
388        // N.b. principal, projections, auto traits
389        // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
390        let mut v = principal_trait_ref
391            .into_iter()
392            .chain(existential_projections)
393            .chain(auto_trait_predicates)
394            .collect::<SmallVec<[_; 8]>>();
395        v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
396        let existential_predicates = tcx.mk_poly_existential_predicates(&v);
397
398        // Use explicitly-specified region bound, unless the bound is missing.
399        let region_bound = if !lifetime.is_elided() {
400            self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
401        } else {
402            self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
403                // Curiously, we prefer object lifetime default for `+ '_`...
404                if tcx.named_bound_var(lifetime.hir_id).is_some() {
405                    self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
406                } else {
407                    let reason =
408                        if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res {
409                            if let hir::Node::Ty(hir::Ty {
410                                kind: hir::TyKind::Ref(parent_lifetime, _),
411                                ..
412                            }) = tcx.parent_hir_node(hir_id)
413                                && tcx.named_bound_var(parent_lifetime.hir_id).is_none()
414                            {
415                                // Parent lifetime must have failed to resolve. Don't emit a redundant error.
416                                RegionInferReason::ExplicitObjectLifetime
417                            } else {
418                                RegionInferReason::ObjectLifetimeDefault
419                            }
420                        } else {
421                            RegionInferReason::ExplicitObjectLifetime
422                        };
423                    self.re_infer(span, reason)
424                }
425            })
426        };
427        debug!(?region_bound);
428
429        Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
430    }
431
432    /// Check that elaborating the principal of a trait ref doesn't lead to projections
433    /// that are unconstrained. This can happen because an otherwise unconstrained
434    /// *type variable* can be substituted with a type that has late-bound regions. See
435    /// `elaborated-predicates-unconstrained-late-bound.rs` for a test.
436    fn check_elaborated_projection_mentions_input_lifetimes(
437        &self,
438        pred: ty::PolyProjectionPredicate<'tcx>,
439        span: Span,
440        supertrait_span: Span,
441    ) {
442        let tcx = self.tcx();
443
444        // Find any late-bound regions declared in `ty` that are not
445        // declared in the trait-ref or assoc_item. These are not well-formed.
446        //
447        // Example:
448        //
449        //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
450        //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
451        let late_bound_in_projection_term =
452            tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
453        let late_bound_in_term =
454            tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
455        debug!(?late_bound_in_projection_term);
456        debug!(?late_bound_in_term);
457
458        // FIXME: point at the type params that don't have appropriate lifetimes:
459        // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
460        //                         ----  ----     ^^^^^^^
461        // NOTE(associated_const_equality): This error should be impossible to trigger
462        //                                  with associated const equality constraints.
463        self.validate_late_bound_regions(
464            late_bound_in_projection_term,
465            late_bound_in_term,
466            |br_name| {
467                let item_name = tcx.item_name(pred.item_def_id());
468                struct_span_code_err!(
469                    self.dcx(),
470                    span,
471                    E0582,
472                    "binding for associated type `{}` references {}, \
473                             which does not appear in the trait input types",
474                    item_name,
475                    br_name
476                )
477                .with_span_label(supertrait_span, "due to this supertrait")
478            },
479        );
480    }
481}
482
483fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
484    tcx: TyCtxt<'tcx>,
485    t: T,
486    guar: ErrorGuaranteed,
487) -> T {
488    t.fold_with(&mut BottomUpFolder {
489        tcx,
490        ty_op: |ty| {
491            if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
492        },
493        lt_op: |lt| lt,
494        ct_op: |ct| ct,
495    })
496}