]>
Commit | Line | Data |
---|---|---|
2b03887a | 1 | // FIXME(@lcnr): Move this module out of `rustc_hir_analysis`. |
064997fb FG |
2 | // |
3 | // We don't do any drop checking during hir typeck. | |
49aad941 | 4 | use rustc_data_structures::fx::FxHashSet; |
5e7ed085 | 5 | use rustc_errors::{struct_span_err, ErrorGuaranteed}; |
49aad941 FG |
6 | use rustc_infer::infer::outlives::env::OutlivesEnvironment; |
7 | use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; | |
923072b8 | 8 | use rustc_middle::ty::subst::SubstsRef; |
49aad941 FG |
9 | use rustc_middle::ty::util::CheckRegions; |
10 | use rustc_middle::ty::{self, TyCtxt}; | |
11 | use rustc_trait_selection::traits::{self, ObligationCtxt}; | |
12 | ||
13 | use crate::errors; | |
14 | use crate::hir::def_id::{DefId, LocalDefId}; | |
60c5eb7d | 15 | |
9fa01778 | 16 | /// This function confirms that the `Drop` implementation identified by |
c34b1796 AL |
17 | /// `drop_impl_did` is not any more specialized than the type it is |
18 | /// attached to (Issue #8142). | |
19 | /// | |
20 | /// This means: | |
21 | /// | |
22 | /// 1. The self type must be nominal (this is already checked during | |
23 | /// coherence), | |
24 | /// | |
9fa01778 | 25 | /// 2. The generic region/type parameters of the impl's self type must |
0731742a | 26 | /// all be parameters of the Drop impl itself (i.e., no |
c34b1796 AL |
27 | /// specialization like `impl Drop for Foo<i32>`), and, |
28 | /// | |
29 | /// 3. Any bounds on the generic parameters must be reflected in the | |
30 | /// struct/enum definition for the nominal type itself (i.e. | |
31 | /// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`). | |
32 | /// | |
5e7ed085 | 33 | pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorGuaranteed> { |
49aad941 FG |
34 | match tcx.impl_polarity(drop_impl_did) { |
35 | ty::ImplPolarity::Positive => {} | |
36 | ty::ImplPolarity::Negative => { | |
37 | return Err(tcx.sess.emit_err(errors::DropImplPolarity::Negative { | |
38 | span: tcx.def_span(drop_impl_did), | |
39 | })); | |
40 | } | |
41 | ty::ImplPolarity::Reservation => { | |
42 | return Err(tcx.sess.emit_err(errors::DropImplPolarity::Reservation { | |
43 | span: tcx.def_span(drop_impl_did), | |
44 | })); | |
45 | } | |
46 | } | |
9ffffee4 | 47 | let dtor_self_type = tcx.type_of(drop_impl_did).subst_identity(); |
1b1a35ee | 48 | match dtor_self_type.kind() { |
49aad941 | 49 | ty::Adt(adt_def, adt_to_impl_substs) => { |
0bf4aa26 XL |
50 | ensure_drop_params_and_item_params_correspond( |
51 | tcx, | |
f9f354fc | 52 | drop_impl_did.expect_local(), |
5e7ed085 | 53 | adt_def.did(), |
49aad941 | 54 | adt_to_impl_substs, |
0bf4aa26 | 55 | )?; |
c34b1796 | 56 | |
0bf4aa26 XL |
57 | ensure_drop_predicates_are_implied_by_item_defn( |
58 | tcx, | |
49aad941 | 59 | drop_impl_did.expect_local(), |
5e7ed085 | 60 | adt_def.did().expect_local(), |
49aad941 | 61 | adt_to_impl_substs, |
0bf4aa26 | 62 | ) |
c34b1796 AL |
63 | } |
64 | _ => { | |
9c376795 | 65 | // Destructors only work on nominal types. This was |
2c00a5a8 XL |
66 | // already checked by coherence, but compilation may |
67 | // not have been terminated. | |
8bb4bdeb | 68 | let span = tcx.def_span(drop_impl_did); |
5e7ed085 | 69 | let reported = tcx.sess.delay_span_bug( |
dfeec247 | 70 | span, |
49aad941 | 71 | format!("should have been rejected by coherence check: {dtor_self_type}"), |
dfeec247 | 72 | ); |
5e7ed085 | 73 | Err(reported) |
c34b1796 AL |
74 | } |
75 | } | |
76 | } | |
77 | ||
dc9dc135 XL |
78 | fn ensure_drop_params_and_item_params_correspond<'tcx>( |
79 | tcx: TyCtxt<'tcx>, | |
f9f354fc | 80 | drop_impl_did: LocalDefId, |
0bf4aa26 | 81 | self_type_did: DefId, |
49aad941 | 82 | adt_to_impl_substs: SubstsRef<'tcx>, |
5e7ed085 | 83 | ) -> Result<(), ErrorGuaranteed> { |
49aad941 | 84 | let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, CheckRegions::OnlyEarlyBound) else { |
923072b8 FG |
85 | return Ok(()) |
86 | }; | |
e9174d1e | 87 | |
923072b8 FG |
88 | let drop_impl_span = tcx.def_span(drop_impl_did); |
89 | let item_span = tcx.def_span(self_type_did); | |
9ffffee4 | 90 | let self_descr = tcx.def_descr(self_type_did); |
923072b8 FG |
91 | let mut err = |
92 | struct_span_err!(tcx.sess, drop_impl_span, E0366, "`Drop` impls cannot be specialized"); | |
93 | match arg { | |
94 | ty::util::NotUniqueParam::DuplicateParam(arg) => { | |
49aad941 | 95 | err.note(format!("`{arg}` is mentioned multiple times")) |
a7813a04 | 96 | } |
923072b8 | 97 | ty::util::NotUniqueParam::NotParam(arg) => { |
49aad941 | 98 | err.note(format!("`{arg}` is not a generic parameter")) |
a7813a04 | 99 | } |
923072b8 FG |
100 | }; |
101 | err.span_note( | |
102 | item_span, | |
49aad941 | 103 | format!( |
923072b8 FG |
104 | "use the same sequence of generic lifetime, type and const parameters \ |
105 | as the {self_descr} definition", | |
106 | ), | |
107 | ); | |
108 | Err(err.emit()) | |
c34b1796 AL |
109 | } |
110 | ||
111 | /// Confirms that every predicate imposed by dtor_predicates is | |
112 | /// implied by assuming the predicates attached to self_type_did. | |
dc9dc135 XL |
113 | fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( |
114 | tcx: TyCtxt<'tcx>, | |
49aad941 FG |
115 | drop_impl_def_id: LocalDefId, |
116 | adt_def_id: LocalDefId, | |
117 | adt_to_impl_substs: SubstsRef<'tcx>, | |
5e7ed085 | 118 | ) -> Result<(), ErrorGuaranteed> { |
49aad941 FG |
119 | let infcx = tcx.infer_ctxt().build(); |
120 | let ocx = ObligationCtxt::new(&infcx); | |
121 | ||
122 | // Take the param-env of the adt and substitute the substs that show up in | |
123 | // the implementation's self type. This gives us the assumptions that the | |
124 | // self ty of the implementation is allowed to know just from it being a | |
125 | // well-formed adt, since that's all we're allowed to assume while proving | |
126 | // the Drop implementation is not specialized. | |
c34b1796 | 127 | // |
49aad941 FG |
128 | // We don't need to normalize this param-env or anything, since we're only |
129 | // substituting it with free params, so no additional param-env normalization | |
130 | // can occur on top of what has been done in the param_env query itself. | |
131 | let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id)) | |
132 | .subst(tcx, adt_to_impl_substs) | |
133 | .with_constness(tcx.constness(drop_impl_def_id)); | |
134 | ||
135 | for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) { | |
136 | let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); | |
137 | let pred = ocx.normalize(&normalize_cause, param_env, pred); | |
138 | let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl); | |
139 | ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred)); | |
140 | } | |
c34b1796 | 141 | |
49aad941 FG |
142 | // All of the custom error reporting logic is to preserve parity with the old |
143 | // error messages. | |
144 | // | |
145 | // They can probably get removed with better treatment of the new `DropImpl` | |
146 | // obligation cause code, and perhaps some custom logic in `report_region_errors`. | |
147 | ||
148 | let errors = ocx.select_all_or_error(); | |
149 | if !errors.is_empty() { | |
150 | let mut guar = None; | |
151 | let mut root_predicates = FxHashSet::default(); | |
152 | for error in errors { | |
153 | let root_predicate = error.root_obligation.predicate; | |
154 | if root_predicates.insert(root_predicate) { | |
155 | let item_span = tcx.def_span(adt_def_id); | |
156 | let self_descr = tcx.def_descr(adt_def_id.to_def_id()); | |
157 | guar = Some( | |
158 | struct_span_err!( | |
159 | tcx.sess, | |
160 | error.root_obligation.cause.span, | |
161 | E0367, | |
162 | "`Drop` impl requires `{root_predicate}` \ | |
163 | but the {self_descr} it is implemented for does not", | |
164 | ) | |
165 | .span_note(item_span, "the implementor must specify the same requirement") | |
166 | .emit(), | |
167 | ); | |
dfeec247 | 168 | } |
c34b1796 | 169 | } |
49aad941 | 170 | return Err(guar.unwrap()); |
c34b1796 | 171 | } |
85aaf69f | 172 | |
49aad941 FG |
173 | let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env)); |
174 | if !errors.is_empty() { | |
175 | let mut guar = None; | |
176 | for error in errors { | |
177 | let item_span = tcx.def_span(adt_def_id); | |
178 | let self_descr = tcx.def_descr(adt_def_id.to_def_id()); | |
179 | let outlives = match error { | |
180 | RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"), | |
181 | RegionResolutionError::GenericBoundFailure(_, generic, r) => { | |
182 | format!("{generic}: {r}") | |
183 | } | |
184 | RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"), | |
185 | RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => { | |
186 | format!("{b}: {a}", a = tcx.mk_re_var(a)) | |
187 | } | |
188 | }; | |
189 | guar = Some( | |
190 | struct_span_err!( | |
191 | tcx.sess, | |
192 | error.origin().span(), | |
193 | E0367, | |
194 | "`Drop` impl requires `{outlives}` \ | |
195 | but the {self_descr} it is implemented for does not", | |
196 | ) | |
197 | .span_note(item_span, "the implementor must specify the same requirement") | |
198 | .emit(), | |
199 | ); | |
dfeec247 | 200 | } |
49aad941 | 201 | return Err(guar.unwrap()); |
dfeec247 XL |
202 | } |
203 | ||
49aad941 | 204 | Ok(()) |
dfeec247 | 205 | } |