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        let mut needed_associated_types = vec![];
150        if let Some((principal_trait, ref spans)) = principal_trait {
151            let principal_trait = principal_trait.map_bound(|trait_pred| {
152                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
153                trait_pred.trait_ref
154            });
155
156            for ClauseWithSupertraitSpan { clause, supertrait_span } in traits::elaborate(
157                tcx,
158                [ClauseWithSupertraitSpan::new(
159                    ty::TraitRef::identity(tcx, principal_trait.def_id()).upcast(tcx),
160                    *spans.last().unwrap(),
161                )],
162            )
163            .filter_only_self()
164            {
165                let clause = clause.instantiate_supertrait(tcx, principal_trait);
166                debug!("observing object predicate `{clause:?}`");
167
168                let bound_predicate = clause.kind();
169                match bound_predicate.skip_binder() {
170                    ty::ClauseKind::Trait(pred) => {
171                        // FIXME(negative_bounds): Handle this correctly...
172                        let trait_ref =
173                            tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
174                        needed_associated_types.extend(
175                            tcx.associated_items(pred.trait_ref.def_id)
176                                .in_definition_order()
177                                // We only care about associated types.
178                                .filter(|item| item.kind == ty::AssocKind::Type)
179                                // No RPITITs -- they're not dyn-compatible for now.
180                                .filter(|item| !item.is_impl_trait_in_trait())
181                                // If the associated type has a `where Self: Sized` bound,
182                                // we do not need to constrain the associated type.
183                                .filter(|item| !tcx.generics_require_sized_self(item.def_id))
184                                .map(|item| (item.def_id, trait_ref)),
185                        );
186                    }
187                    ty::ClauseKind::Projection(pred) => {
188                        let pred = bound_predicate.rebind(pred);
189                        // A `Self` within the original bound will be instantiated with a
190                        // `trait_object_dummy_self`, so check for that.
191                        let references_self = match pred.skip_binder().term.unpack() {
192                            ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
193                            // FIXME(associated_const_equality): We should walk the const instead of not doing anything
194                            ty::TermKind::Const(_) => false,
195                        };
196
197                        // If the projection output contains `Self`, force the user to
198                        // elaborate it explicitly to avoid a lot of complexity.
199                        //
200                        // The "classically useful" case is the following:
201                        // ```
202                        //     trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
203                        //         type MyOutput;
204                        //     }
205                        // ```
206                        //
207                        // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`,
208                        // but actually supporting that would "expand" to an infinitely-long type
209                        // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
210                        //
211                        // Instead, we force the user to write
212                        // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
213                        // the discussion in #56288 for alternatives.
214                        if !references_self {
215                            let key = (
216                                pred.skip_binder().projection_term.def_id,
217                                tcx.anonymize_bound_vars(
218                                    pred.map_bound(|proj| proj.projection_term.trait_ref(tcx)),
219                                ),
220                            );
221                            if !projection_bounds.contains_key(&key) {
222                                projection_bounds.insert(key, (pred, supertrait_span));
223                            }
224                        }
225
226                        self.check_elaborated_projection_mentions_input_lifetimes(
227                            pred,
228                            *spans.first().unwrap(),
229                            supertrait_span,
230                        );
231                    }
232                    _ => (),
233                }
234            }
235        }
236
237        // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where
238        // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an
239        // `Assoc = Foo` bound. `needed_associated_types` contains all associated
240        // types that we expect to be provided by the user, so the following loop
241        // removes all the associated types that have a corresponding `Projection`
242        // clause, either from expanding trait aliases or written by the user.
243        for &(projection_bound, span) in projection_bounds.values() {
244            let def_id = projection_bound.item_def_id();
245            if tcx.generics_require_sized_self(def_id) {
246                tcx.emit_node_span_lint(
247                    UNUSED_ASSOCIATED_TYPE_BOUNDS,
248                    hir_id,
249                    span,
250                    crate::errors::UnusedAssociatedTypeBounds { span },
251                );
252            }
253        }
254
255        let mut missing_assoc_types = FxIndexSet::default();
256        let projection_bounds: Vec<_> = needed_associated_types
257            .into_iter()
258            .filter_map(|key| {
259                if let Some(assoc) = projection_bounds.get(&key) {
260                    Some(*assoc)
261                } else {
262                    missing_assoc_types.insert(key);
263                    None
264                }
265            })
266            .collect();
267
268        if let Err(guar) = self.check_for_required_assoc_tys(
269            principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
270            missing_assoc_types,
271            potential_assoc_types,
272            hir_bounds,
273        ) {
274            return Ty::new_error(tcx, guar);
275        }
276
277        // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
278        // `dyn Trait + Send`.
279        // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
280        // the bounds
281        let mut duplicates = FxHashSet::default();
282        auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id()));
283
284        debug!(?principal_trait);
285        debug!(?auto_traits);
286
287        // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
288        let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| {
289            trait_pred.map_bound(|trait_pred| {
290                let trait_ref = trait_pred.trait_ref;
291                assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
292                assert_eq!(trait_ref.self_ty(), dummy_self);
293
294                let span = *spans.first().unwrap();
295
296                // Verify that `dummy_self` did not leak inside default type parameters. This
297                // could not be done at path creation, since we need to see through trait aliases.
298                let mut missing_type_params = vec![];
299                let generics = tcx.generics_of(trait_ref.def_id);
300                let args: Vec<_> = trait_ref
301                    .args
302                    .iter()
303                    .enumerate()
304                    // Skip `Self`
305                    .skip(1)
306                    .map(|(index, arg)| {
307                        if arg.walk().any(|arg| arg == dummy_self.into()) {
308                            let param = &generics.own_params[index];
309                            missing_type_params.push(param.name);
310                            Ty::new_misc_error(tcx).into()
311                        } else {
312                            arg
313                        }
314                    })
315                    .collect();
316
317                let empty_generic_args = hir_bounds.iter().any(|hir_bound| {
318                    hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
319                        && hir_bound.span.contains(span)
320                });
321                self.complain_about_missing_type_params(
322                    missing_type_params,
323                    trait_ref.def_id,
324                    span,
325                    empty_generic_args,
326                );
327
328                ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new(
329                    tcx,
330                    trait_ref.def_id,
331                    args,
332                ))
333            })
334        });
335
336        let existential_projections = projection_bounds.into_iter().map(|(bound, _)| {
337            bound.map_bound(|mut b| {
338                assert_eq!(b.projection_term.self_ty(), dummy_self);
339
340                // Like for trait refs, verify that `dummy_self` did not leak inside default type
341                // parameters.
342                let references_self = b.projection_term.args.iter().skip(1).any(|arg| {
343                    if arg.walk().any(|arg| arg == dummy_self.into()) {
344                        return true;
345                    }
346                    false
347                });
348                if references_self {
349                    let guar = tcx
350                        .dcx()
351                        .span_delayed_bug(span, "trait object projection bounds reference `Self`");
352                    b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
353                }
354
355                ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
356                    tcx, b,
357                ))
358            })
359        });
360
361        let mut auto_trait_predicates: Vec<_> = auto_traits
362            .into_iter()
363            .map(|(trait_pred, _)| {
364                assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
365                assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
366
367                ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
368            })
369            .collect();
370        auto_trait_predicates.dedup();
371
372        // N.b. principal, projections, auto traits
373        // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
374        let mut v = principal_trait_ref
375            .into_iter()
376            .chain(existential_projections)
377            .chain(auto_trait_predicates)
378            .collect::<SmallVec<[_; 8]>>();
379        v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
380        let existential_predicates = tcx.mk_poly_existential_predicates(&v);
381
382        // Use explicitly-specified region bound, unless the bound is missing.
383        let region_bound = if !lifetime.is_elided() {
384            self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
385        } else {
386            self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
387                // Curiously, we prefer object lifetime default for `+ '_`...
388                if tcx.named_bound_var(lifetime.hir_id).is_some() {
389                    self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
390                } else {
391                    let reason =
392                        if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res {
393                            if let hir::Node::Ty(hir::Ty {
394                                kind: hir::TyKind::Ref(parent_lifetime, _),
395                                ..
396                            }) = tcx.parent_hir_node(hir_id)
397                                && tcx.named_bound_var(parent_lifetime.hir_id).is_none()
398                            {
399                                // Parent lifetime must have failed to resolve. Don't emit a redundant error.
400                                RegionInferReason::ExplicitObjectLifetime
401                            } else {
402                                RegionInferReason::ObjectLifetimeDefault
403                            }
404                        } else {
405                            RegionInferReason::ExplicitObjectLifetime
406                        };
407                    self.re_infer(span, reason)
408                }
409            })
410        };
411        debug!(?region_bound);
412
413        Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
414    }
415
416    /// Check that elaborating the principal of a trait ref doesn't lead to projections
417    /// that are unconstrained. This can happen because an otherwise unconstrained
418    /// *type variable* can be substituted with a type that has late-bound regions. See
419    /// `elaborated-predicates-unconstrained-late-bound.rs` for a test.
420    fn check_elaborated_projection_mentions_input_lifetimes(
421        &self,
422        pred: ty::PolyProjectionPredicate<'tcx>,
423        span: Span,
424        supertrait_span: Span,
425    ) {
426        let tcx = self.tcx();
427
428        // Find any late-bound regions declared in `ty` that are not
429        // declared in the trait-ref or assoc_item. These are not well-formed.
430        //
431        // Example:
432        //
433        //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
434        //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
435        let late_bound_in_projection_term =
436            tcx.collect_constrained_late_bound_regions(pred.map_bound(|pred| pred.projection_term));
437        let late_bound_in_term =
438            tcx.collect_referenced_late_bound_regions(pred.map_bound(|pred| pred.term));
439        debug!(?late_bound_in_projection_term);
440        debug!(?late_bound_in_term);
441
442        // FIXME: point at the type params that don't have appropriate lifetimes:
443        // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
444        //                         ----  ----     ^^^^^^^
445        // NOTE(associated_const_equality): This error should be impossible to trigger
446        //                                  with associated const equality constraints.
447        self.validate_late_bound_regions(
448            late_bound_in_projection_term,
449            late_bound_in_term,
450            |br_name| {
451                let item_name = tcx.item_name(pred.item_def_id());
452                struct_span_code_err!(
453                    self.dcx(),
454                    span,
455                    E0582,
456                    "binding for associated type `{}` references {}, \
457                             which does not appear in the trait input types",
458                    item_name,
459                    br_name
460                )
461                .with_span_label(supertrait_span, "due to this supertrait")
462            },
463        );
464    }
465}
466
467fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
468    tcx: TyCtxt<'tcx>,
469    t: T,
470    guar: ErrorGuaranteed,
471) -> T {
472    t.fold_with(&mut BottomUpFolder {
473        tcx,
474        ty_op: |ty| {
475            if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
476        },
477        lt_op: |lt| lt,
478        ct_op: |ct| ct,
479    })
480}