rustc_hir_analysis/check/
always_applicable.rs

1//! This module contains methods that assist in checking that impls are general
2//! enough, i.e. that they always apply to every valid instantaiton of the ADT
3//! they're implemented for.
4//!
5//! This is necessary for `Drop` and negative impls to be well-formed.
6
7use rustc_data_structures::fx::FxHashSet;
8use rustc_errors::codes::*;
9use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
10use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
11use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
12use rustc_middle::span_bug;
13use rustc_middle::ty::util::CheckRegions;
14use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode};
15use rustc_trait_selection::regions::InferCtxtRegionExt;
16use rustc_trait_selection::traits::{self, ObligationCtxt};
17
18use crate::errors;
19use crate::hir::def_id::{DefId, LocalDefId};
20
21/// This function confirms that the `Drop` implementation identified by
22/// `drop_impl_did` is not any more specialized than the type it is
23/// attached to (Issue #8142).
24///
25/// This means:
26///
27/// 1. The self type must be nominal (this is already checked during
28///    coherence),
29///
30/// 2. The generic region/type parameters of the impl's self type must
31///    all be parameters of the Drop impl itself (i.e., no
32///    specialization like `impl Drop for Foo<i32>`), and,
33///
34/// 3. Any bounds on the generic parameters must be reflected in the
35///    struct/enum definition for the nominal type itself (i.e.
36///    cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
37pub(crate) fn check_drop_impl(
38    tcx: TyCtxt<'_>,
39    drop_impl_did: LocalDefId,
40) -> Result<(), ErrorGuaranteed> {
41    match tcx.impl_polarity(drop_impl_did) {
42        ty::ImplPolarity::Positive => {}
43        ty::ImplPolarity::Negative => {
44            return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Negative {
45                span: tcx.def_span(drop_impl_did),
46            }));
47        }
48        ty::ImplPolarity::Reservation => {
49            return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Reservation {
50                span: tcx.def_span(drop_impl_did),
51            }));
52        }
53    }
54
55    tcx.ensure_ok().orphan_check_impl(drop_impl_did)?;
56
57    let self_ty = tcx.type_of(drop_impl_did).instantiate_identity();
58
59    match self_ty.kind() {
60        ty::Adt(adt_def, adt_to_impl_args) => {
61            ensure_impl_params_and_item_params_correspond(
62                tcx,
63                drop_impl_did,
64                adt_def.did(),
65                adt_to_impl_args,
66            )?;
67
68            ensure_impl_predicates_are_implied_by_item_defn(
69                tcx,
70                drop_impl_did,
71                adt_def.did(),
72                adt_to_impl_args,
73            )
74        }
75        _ => {
76            span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop");
77        }
78    }
79}
80
81pub(crate) fn check_negative_auto_trait_impl<'tcx>(
82    tcx: TyCtxt<'tcx>,
83    impl_def_id: LocalDefId,
84    impl_trait_ref: ty::TraitRef<'tcx>,
85    polarity: ty::ImplPolarity,
86) -> Result<(), ErrorGuaranteed> {
87    let ty::ImplPolarity::Negative = polarity else {
88        return Ok(());
89    };
90
91    if !tcx.trait_is_auto(impl_trait_ref.def_id) {
92        return Ok(());
93    }
94
95    if tcx.defaultness(impl_def_id).is_default() {
96        tcx.dcx().span_delayed_bug(tcx.def_span(impl_def_id), "default impl cannot be negative");
97    }
98
99    tcx.ensure_ok().orphan_check_impl(impl_def_id)?;
100
101    match impl_trait_ref.self_ty().kind() {
102        ty::Adt(adt_def, adt_to_impl_args) => {
103            ensure_impl_params_and_item_params_correspond(
104                tcx,
105                impl_def_id,
106                adt_def.did(),
107                adt_to_impl_args,
108            )?;
109
110            ensure_impl_predicates_are_implied_by_item_defn(
111                tcx,
112                impl_def_id,
113                adt_def.did(),
114                adt_to_impl_args,
115            )
116        }
117        _ => {
118            if tcx.features().auto_traits() {
119                // NOTE: We ignore the applicability check for negative auto impls
120                // defined in libcore. In the (almost impossible) future where we
121                // stabilize auto impls, then the proper applicability check MUST
122                // be implemented here to handle non-ADT rigid types.
123                Ok(())
124            } else {
125                Err(tcx.dcx().span_delayed_bug(
126                    tcx.def_span(impl_def_id),
127                    "incoherent impl of negative auto trait",
128                ))
129            }
130        }
131    }
132}
133
134fn ensure_impl_params_and_item_params_correspond<'tcx>(
135    tcx: TyCtxt<'tcx>,
136    impl_def_id: LocalDefId,
137    adt_def_id: DefId,
138    adt_to_impl_args: GenericArgsRef<'tcx>,
139) -> Result<(), ErrorGuaranteed> {
140    let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else {
141        return Ok(());
142    };
143
144    let impl_span = tcx.def_span(impl_def_id);
145    let item_span = tcx.def_span(adt_def_id);
146    let self_descr = tcx.def_descr(adt_def_id);
147    let polarity = match tcx.impl_polarity(impl_def_id) {
148        ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
149        ty::ImplPolarity::Negative => "!",
150    };
151    let trait_name = tcx
152        .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
153    let mut err = struct_span_code_err!(
154        tcx.dcx(),
155        impl_span,
156        E0366,
157        "`{polarity}{trait_name}` impls cannot be specialized",
158    );
159    match arg {
160        ty::util::NotUniqueParam::DuplicateParam(arg) => {
161            err.note(format!("`{arg}` is mentioned multiple times"))
162        }
163        ty::util::NotUniqueParam::NotParam(arg) => {
164            err.note(format!("`{arg}` is not a generic parameter"))
165        }
166    };
167    err.span_note(
168        item_span,
169        format!(
170            "use the same sequence of generic lifetime, type and const parameters \
171                     as the {self_descr} definition",
172        ),
173    );
174    Err(err.emit())
175}
176
177/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
178/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
179/// implied by the ADT being well formed.
180fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
181    tcx: TyCtxt<'tcx>,
182    impl_def_id: LocalDefId,
183    adt_def_id: DefId,
184    adt_to_impl_args: GenericArgsRef<'tcx>,
185) -> Result<(), ErrorGuaranteed> {
186    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
187    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
188
189    let impl_span = tcx.def_span(impl_def_id.to_def_id());
190    let trait_name = tcx
191        .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
192    let polarity = match tcx.impl_polarity(impl_def_id) {
193        ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
194        ty::ImplPolarity::Negative => "!",
195    };
196    // Take the param-env of the adt and instantiate the args that show up in
197    // the implementation's self type. This gives us the assumptions that the
198    // self ty of the implementation is allowed to know just from it being a
199    // well-formed adt, since that's all we're allowed to assume while proving
200    // the Drop implementation is not specialized.
201    //
202    // We don't need to normalize this param-env or anything, since we're only
203    // instantiating it with free params, so no additional param-env normalization
204    // can occur on top of what has been done in the param_env query itself.
205    //
206    // Note: Ideally instead of instantiating the `ParamEnv` with the arguments from the impl ty we
207    // could instead use identity args for the adt. Unfortunately this would cause any errors to
208    // reference the params from the ADT instead of from the impl which is bad UX. To resolve
209    // this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
210    let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
211    let adt_env =
212        ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
213
214    let fresh_impl_args = infcx.fresh_args_for_item(impl_span, impl_def_id.to_def_id());
215    let fresh_adt_ty =
216        tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
217
218    ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
219        .expect("equating fully generic trait ref should never fail");
220
221    for (clause, span) in tcx.predicates_of(impl_def_id).instantiate(tcx, fresh_impl_args) {
222        let normalize_cause = traits::ObligationCause::misc(span, impl_def_id);
223        let pred = ocx.normalize(&normalize_cause, adt_env, clause);
224        let cause = traits::ObligationCause::new(
225            span,
226            impl_def_id,
227            ObligationCauseCode::AlwaysApplicableImpl,
228        );
229        ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred));
230    }
231
232    // All of the custom error reporting logic is to preserve parity with the old
233    // error messages.
234    //
235    // They can probably get removed with better treatment of the new `DropImpl`
236    // obligation cause code, and perhaps some custom logic in `report_region_errors`.
237
238    let errors = ocx.select_all_or_error();
239    if !errors.is_empty() {
240        let mut guar = None;
241        let mut root_predicates = FxHashSet::default();
242        for error in errors {
243            let root_predicate = error.root_obligation.predicate;
244            if root_predicates.insert(root_predicate) {
245                let item_span = tcx.def_span(adt_def_id);
246                let self_descr = tcx.def_descr(adt_def_id);
247                guar = Some(
248                    struct_span_code_err!(
249                        tcx.dcx(),
250                        error.root_obligation.cause.span,
251                        E0367,
252                        "`{polarity}{trait_name}` impl requires `{root_predicate}` \
253                        but the {self_descr} it is implemented for does not",
254                    )
255                    .with_span_note(item_span, "the implementor must specify the same requirement")
256                    .emit(),
257                );
258            }
259        }
260        return Err(guar.unwrap());
261    }
262
263    let errors = ocx.infcx.resolve_regions(impl_def_id, adt_env, []);
264    if !errors.is_empty() {
265        let mut guar = None;
266        for error in errors {
267            let item_span = tcx.def_span(adt_def_id);
268            let self_descr = tcx.def_descr(adt_def_id);
269            let outlives = match error {
270                RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"),
271                RegionResolutionError::GenericBoundFailure(_, generic, r) => {
272                    format!("{generic}: {r}")
273                }
274                RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"),
275                RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
276                    format!("{b}: {a}", a = ty::Region::new_var(tcx, a))
277                }
278                RegionResolutionError::CannotNormalize(..) => unreachable!(),
279            };
280            guar = Some(
281                struct_span_code_err!(
282                    tcx.dcx(),
283                    error.origin().span(),
284                    E0367,
285                    "`{polarity}{trait_name}` impl requires `{outlives}` \
286                    but the {self_descr} it is implemented for does not",
287                )
288                .with_span_note(item_span, "the implementor must specify the same requirement")
289                .emit(),
290            );
291        }
292        return Err(guar.unwrap());
293    }
294
295    Ok(())
296}