rustc_hir_analysis/check/
dropck.rs
1use rustc_data_structures::fx::FxHashSet;
2use rustc_errors::codes::*;
3use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
4use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
5use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
6use rustc_middle::ty::util::CheckRegions;
7use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode};
8use rustc_trait_selection::regions::InferCtxtRegionExt;
9use rustc_trait_selection::traits::{self, ObligationCtxt};
10
11use crate::errors;
12use crate::hir::def_id::{DefId, LocalDefId};
13
14pub(crate) fn check_drop_impl(
32 tcx: TyCtxt<'_>,
33 drop_impl_did: DefId,
34) -> Result<(), ErrorGuaranteed> {
35 match tcx.impl_polarity(drop_impl_did) {
36 ty::ImplPolarity::Positive => {}
37 ty::ImplPolarity::Negative => {
38 return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Negative {
39 span: tcx.def_span(drop_impl_did),
40 }));
41 }
42 ty::ImplPolarity::Reservation => {
43 return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Reservation {
44 span: tcx.def_span(drop_impl_did),
45 }));
46 }
47 }
48 let dtor_self_type = tcx.type_of(drop_impl_did).instantiate_identity();
49 match dtor_self_type.kind() {
50 ty::Adt(adt_def, adt_to_impl_args) => {
51 ensure_drop_params_and_item_params_correspond(
52 tcx,
53 drop_impl_did.expect_local(),
54 adt_def.did(),
55 adt_to_impl_args,
56 )?;
57
58 ensure_drop_predicates_are_implied_by_item_defn(
59 tcx,
60 drop_impl_did.expect_local(),
61 adt_def.did().expect_local(),
62 adt_to_impl_args,
63 )
64 }
65 _ => {
66 let span = tcx.def_span(drop_impl_did);
70 let reported = tcx.dcx().span_delayed_bug(
71 span,
72 format!("should have been rejected by coherence check: {dtor_self_type}"),
73 );
74 Err(reported)
75 }
76 }
77}
78
79fn ensure_drop_params_and_item_params_correspond<'tcx>(
80 tcx: TyCtxt<'tcx>,
81 drop_impl_did: LocalDefId,
82 self_type_did: DefId,
83 adt_to_impl_args: GenericArgsRef<'tcx>,
84) -> Result<(), ErrorGuaranteed> {
85 let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else {
86 return Ok(());
87 };
88
89 let drop_impl_span = tcx.def_span(drop_impl_did);
90 let item_span = tcx.def_span(self_type_did);
91 let self_descr = tcx.def_descr(self_type_did);
92 let mut err = struct_span_code_err!(
93 tcx.dcx(),
94 drop_impl_span,
95 E0366,
96 "`Drop` impls cannot be specialized"
97 );
98 match arg {
99 ty::util::NotUniqueParam::DuplicateParam(arg) => {
100 err.note(format!("`{arg}` is mentioned multiple times"))
101 }
102 ty::util::NotUniqueParam::NotParam(arg) => {
103 err.note(format!("`{arg}` is not a generic parameter"))
104 }
105 };
106 err.span_note(
107 item_span,
108 format!(
109 "use the same sequence of generic lifetime, type and const parameters \
110 as the {self_descr} definition",
111 ),
112 );
113 Err(err.emit())
114}
115
116fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
120 tcx: TyCtxt<'tcx>,
121 drop_impl_def_id: LocalDefId,
122 adt_def_id: LocalDefId,
123 adt_to_impl_args: GenericArgsRef<'tcx>,
124) -> Result<(), ErrorGuaranteed> {
125 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
126 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
127
128 let impl_span = tcx.def_span(drop_impl_def_id.to_def_id());
129
130 let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
145 let adt_env =
146 ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
147
148 let fresh_impl_args = infcx.fresh_args_for_item(impl_span, drop_impl_def_id.to_def_id());
149 let fresh_adt_ty =
150 tcx.impl_trait_ref(drop_impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
151
152 ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
153 .unwrap();
154
155 for (clause, span) in tcx.predicates_of(drop_impl_def_id).instantiate(tcx, fresh_impl_args) {
156 let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
157 let pred = ocx.normalize(&normalize_cause, adt_env, clause);
158 let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl);
159 ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred));
160 }
161
162 let errors = ocx.select_all_or_error();
169 if !errors.is_empty() {
170 let mut guar = None;
171 let mut root_predicates = FxHashSet::default();
172 for error in errors {
173 let root_predicate = error.root_obligation.predicate;
174 if root_predicates.insert(root_predicate) {
175 let item_span = tcx.def_span(adt_def_id);
176 let self_descr = tcx.def_descr(adt_def_id.to_def_id());
177 guar = Some(
178 struct_span_code_err!(
179 tcx.dcx(),
180 error.root_obligation.cause.span,
181 E0367,
182 "`Drop` impl requires `{root_predicate}` \
183 but the {self_descr} it is implemented for does not",
184 )
185 .with_span_note(item_span, "the implementor must specify the same requirement")
186 .emit(),
187 );
188 }
189 }
190 return Err(guar.unwrap());
191 }
192
193 let errors = ocx.infcx.resolve_regions(adt_def_id, adt_env, []);
194 if !errors.is_empty() {
195 let mut guar = None;
196 for error in errors {
197 let item_span = tcx.def_span(adt_def_id);
198 let self_descr = tcx.def_descr(adt_def_id.to_def_id());
199 let outlives = match error {
200 RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"),
201 RegionResolutionError::GenericBoundFailure(_, generic, r) => {
202 format!("{generic}: {r}")
203 }
204 RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"),
205 RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
206 format!("{b}: {a}", a = ty::Region::new_var(tcx, a))
207 }
208 RegionResolutionError::CannotNormalize(..) => unreachable!(),
209 };
210 guar = Some(
211 struct_span_code_err!(
212 tcx.dcx(),
213 error.origin().span(),
214 E0367,
215 "`Drop` impl requires `{outlives}` \
216 but the {self_descr} it is implemented for does not",
217 )
218 .with_span_note(item_span, "the implementor must specify the same requirement")
219 .emit(),
220 );
221 }
222 return Err(guar.unwrap());
223 }
224
225 Ok(())
226}