1
1
// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
2
2
//
3
3
// We don't do any drop checking during hir typeck.
4
+ use rustc_data_structures:: fx:: FxHashSet ;
4
5
use rustc_errors:: { struct_span_err, ErrorGuaranteed } ;
5
- use rustc_middle :: ty :: error :: TypeError ;
6
- use rustc_middle :: ty :: relate :: { Relate , RelateResult , TypeRelation } ;
6
+ use rustc_infer :: infer :: outlives :: env :: OutlivesEnvironment ;
7
+ use rustc_infer :: infer :: { RegionResolutionError , TyCtxtInferExt } ;
7
8
use rustc_middle:: ty:: subst:: SubstsRef ;
8
9
use rustc_middle:: ty:: util:: IgnoreRegions ;
9
- use rustc_middle:: ty:: { self , Predicate , Ty , TyCtxt } ;
10
+ use rustc_middle:: ty:: { self , TyCtxt } ;
11
+ use rustc_trait_selection:: traits:: { self , ObligationCtxt } ;
10
12
11
13
use crate :: errors;
12
14
use crate :: hir:: def_id:: { DefId , LocalDefId } ;
@@ -43,21 +45,20 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
43
45
}
44
46
}
45
47
let dtor_self_type = tcx. type_of ( drop_impl_did) . subst_identity ( ) ;
46
- let dtor_predicates = tcx. predicates_of ( drop_impl_did) ;
47
48
match dtor_self_type. kind ( ) {
48
- ty:: Adt ( adt_def, self_to_impl_substs ) => {
49
+ ty:: Adt ( adt_def, adt_to_impl_substs ) => {
49
50
ensure_drop_params_and_item_params_correspond (
50
51
tcx,
51
52
drop_impl_did. expect_local ( ) ,
52
53
adt_def. did ( ) ,
53
- self_to_impl_substs ,
54
+ adt_to_impl_substs ,
54
55
) ?;
55
56
56
57
ensure_drop_predicates_are_implied_by_item_defn (
57
58
tcx,
58
- dtor_predicates ,
59
+ drop_impl_did . expect_local ( ) ,
59
60
adt_def. did ( ) . expect_local ( ) ,
60
- self_to_impl_substs ,
61
+ adt_to_impl_substs ,
61
62
)
62
63
}
63
64
_ => {
@@ -78,9 +79,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
78
79
tcx : TyCtxt < ' tcx > ,
79
80
drop_impl_did : LocalDefId ,
80
81
self_type_did : DefId ,
81
- drop_impl_substs : SubstsRef < ' tcx > ,
82
+ adt_to_impl_substs : SubstsRef < ' tcx > ,
82
83
) -> Result < ( ) , ErrorGuaranteed > {
83
- let Err ( arg) = tcx. uses_unique_generic_params ( drop_impl_substs , IgnoreRegions :: No ) else {
84
+ let Err ( arg) = tcx. uses_unique_generic_params ( adt_to_impl_substs , IgnoreRegions :: No ) else {
84
85
return Ok ( ( ) )
85
86
} ;
86
87
@@ -111,237 +112,94 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
111
112
/// implied by assuming the predicates attached to self_type_did.
112
113
fn ensure_drop_predicates_are_implied_by_item_defn < ' tcx > (
113
114
tcx : TyCtxt < ' tcx > ,
114
- dtor_predicates : ty :: GenericPredicates < ' tcx > ,
115
- self_type_did : LocalDefId ,
116
- self_to_impl_substs : SubstsRef < ' tcx > ,
115
+ drop_impl_def_id : LocalDefId ,
116
+ adt_def_id : LocalDefId ,
117
+ adt_to_impl_substs : SubstsRef < ' tcx > ,
117
118
) -> Result < ( ) , ErrorGuaranteed > {
118
- let mut result = Ok ( ( ) ) ;
119
-
120
- // Here is an example, analogous to that from
121
- // `compare_impl_method`.
122
- //
123
- // Consider a struct type:
124
- //
125
- // struct Type<'c, 'b:'c, 'a> {
126
- // x: &'a Contents // (contents are irrelevant;
127
- // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.)
128
- // }
129
- //
130
- // and a Drop impl:
131
- //
132
- // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
133
- // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
134
- // }
135
- //
136
- // We start out with self_to_impl_substs, that maps the generic
137
- // parameters of Type to that of the Drop impl.
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.
138
127
//
139
- // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
140
- //
141
- // Applying this to the predicates (i.e., assumptions) provided by the item
142
- // definition yields the instantiated assumptions:
143
- //
144
- // ['y : 'z]
145
- //
146
- // We then check all of the predicates of the Drop impl:
147
- //
148
- // ['y:'z, 'x:'y]
149
- //
150
- // and ensure each is in the list of instantiated
151
- // assumptions. Here, `'y:'z` is present, but `'x:'y` is
152
- // absent. So we report an error that the Drop impl injected a
153
- // predicate that is not present on the struct definition.
154
-
155
- // We can assume the predicates attached to struct/enum definition
156
- // hold.
157
- let generic_assumptions = tcx. predicates_of ( self_type_did) ;
158
-
159
- let assumptions_in_impl_context = generic_assumptions. instantiate ( tcx, & self_to_impl_substs) ;
160
- let assumptions_in_impl_context = assumptions_in_impl_context. predicates ;
161
-
162
- debug ! ( ?assumptions_in_impl_context, ?dtor_predicates. predicates) ;
163
-
164
- let self_param_env = tcx. param_env ( self_type_did) ;
165
-
166
- // An earlier version of this code attempted to do this checking
167
- // via the traits::fulfill machinery. However, it ran into trouble
168
- // since the fulfill machinery merely turns outlives-predicates
169
- // 'a:'b and T:'b into region inference constraints. It is simpler
170
- // just to look for all the predicates directly.
171
-
172
- assert_eq ! ( dtor_predicates. parent, None ) ;
173
- for & ( predicate, predicate_sp) in dtor_predicates. predicates {
174
- // (We do not need to worry about deep analysis of type
175
- // expressions etc because the Drop impls are already forced
176
- // to take on a structure that is roughly an alpha-renaming of
177
- // the generic parameters of the item definition.)
178
-
179
- // This path now just checks *all* predicates via an instantiation of
180
- // the `SimpleEqRelation`, which simply forwards to the `relate` machinery
181
- // after taking care of anonymizing late bound regions.
182
- //
183
- // However, it may be more efficient in the future to batch
184
- // the analysis together via the fulfill (see comment above regarding
185
- // the usage of the fulfill machinery), rather than the
186
- // repeated `.iter().any(..)` calls.
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
+ }
187
141
188
- // This closure is a more robust way to check `Predicate` equality
189
- // than simple `==` checks (which were the previous implementation).
190
- // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`,
191
- // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait),
192
- // while delegating on simple equality for the other `Predicate`.
193
- // This implementation solves (Issue #59497) and (Issue #58311).
194
- // It is unclear to me at the moment whether the approach based on `relate`
195
- // could be extended easily also to the other `Predicate`.
196
- let predicate_matches_closure = |p : Predicate < ' tcx > | {
197
- let mut relator: SimpleEqRelation < ' tcx > = SimpleEqRelation :: new ( tcx, self_param_env) ;
198
- let predicate = predicate. kind ( ) ;
199
- let p = p. kind ( ) ;
200
- match ( predicate. skip_binder ( ) , p. skip_binder ( ) ) {
201
- (
202
- ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( a) ) ,
203
- ty:: PredicateKind :: Clause ( ty:: Clause :: Trait ( b) ) ,
204
- ) => relator. relate ( predicate. rebind ( a) , p. rebind ( b) ) . is_ok ( ) ,
205
- (
206
- ty:: PredicateKind :: Clause ( ty:: Clause :: Projection ( a) ) ,
207
- ty:: PredicateKind :: Clause ( ty:: Clause :: Projection ( b) ) ,
208
- ) => relator. relate ( predicate. rebind ( a) , p. rebind ( b) ) . is_ok ( ) ,
209
- (
210
- ty:: PredicateKind :: ConstEvaluatable ( a) ,
211
- ty:: PredicateKind :: ConstEvaluatable ( b) ,
212
- ) => relator. relate ( predicate. rebind ( a) , predicate. rebind ( b) ) . is_ok ( ) ,
213
- (
214
- ty:: PredicateKind :: Clause ( ty:: Clause :: TypeOutlives ( ty:: OutlivesPredicate (
215
- ty_a,
216
- lt_a,
217
- ) ) ) ,
218
- ty:: PredicateKind :: Clause ( ty:: Clause :: TypeOutlives ( ty:: OutlivesPredicate (
219
- ty_b,
220
- lt_b,
221
- ) ) ) ,
222
- ) => {
223
- relator. relate ( predicate. rebind ( ty_a) , p. rebind ( ty_b) ) . is_ok ( )
224
- && relator. relate ( predicate. rebind ( lt_a) , p. rebind ( lt_b) ) . is_ok ( )
225
- }
226
- ( ty:: PredicateKind :: WellFormed ( arg_a) , ty:: PredicateKind :: WellFormed ( arg_b) ) => {
227
- relator. relate ( predicate. rebind ( arg_a) , p. rebind ( arg_b) ) . is_ok ( )
228
- }
229
- _ => predicate == p,
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
+ ) ;
230
168
}
231
- } ;
232
-
233
- if !assumptions_in_impl_context. iter ( ) . copied ( ) . any ( predicate_matches_closure) {
234
- let item_span = tcx. def_span ( self_type_did) ;
235
- let self_descr = tcx. def_descr ( self_type_did. to_def_id ( ) ) ;
236
- let reported = struct_span_err ! (
237
- tcx. sess,
238
- predicate_sp,
239
- E0367 ,
240
- "`Drop` impl requires `{predicate}` but the {self_descr} it is implemented for does not" ,
241
- )
242
- . span_note ( item_span, "the implementor must specify the same requirement" )
243
- . emit ( ) ;
244
- result = Err ( reported) ;
245
169
}
170
+ return Err ( guar. unwrap ( ) ) ;
246
171
}
247
172
248
- result
249
- }
250
-
251
- /// This is an implementation of the [`TypeRelation`] trait with the
252
- /// aim of simply comparing for equality (without side-effects).
253
- ///
254
- /// It is not intended to be used anywhere else other than here.
255
- pub ( crate ) struct SimpleEqRelation < ' tcx > {
256
- tcx : TyCtxt < ' tcx > ,
257
- param_env : ty:: ParamEnv < ' tcx > ,
258
- }
259
-
260
- impl < ' tcx > SimpleEqRelation < ' tcx > {
261
- fn new ( tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> SimpleEqRelation < ' tcx > {
262
- SimpleEqRelation { tcx, param_env }
263
- }
264
- }
265
-
266
- impl < ' tcx > TypeRelation < ' tcx > for SimpleEqRelation < ' tcx > {
267
- fn tcx ( & self ) -> TyCtxt < ' tcx > {
268
- self . tcx
269
- }
270
-
271
- fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > {
272
- self . param_env
273
- }
274
-
275
- fn tag ( & self ) -> & ' static str {
276
- "dropck::SimpleEqRelation"
277
- }
278
-
279
- fn a_is_expected ( & self ) -> bool {
280
- true
281
- }
282
-
283
- fn relate_with_variance < T : Relate < ' tcx > > (
284
- & mut self ,
285
- _: ty:: Variance ,
286
- _info : ty:: VarianceDiagInfo < ' tcx > ,
287
- a : T ,
288
- b : T ,
289
- ) -> RelateResult < ' tcx , T > {
290
- // Here we ignore variance because we require drop impl's types
291
- // to be *exactly* the same as to the ones in the struct definition.
292
- self . relate ( a, b)
293
- }
294
-
295
- fn tys ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> RelateResult < ' tcx , Ty < ' tcx > > {
296
- debug ! ( "SimpleEqRelation::tys(a={:?}, b={:?})" , a, b) ;
297
- ty:: relate:: super_relate_tys ( self , a, b)
298
- }
299
-
300
- fn regions (
301
- & mut self ,
302
- a : ty:: Region < ' tcx > ,
303
- b : ty:: Region < ' tcx > ,
304
- ) -> RelateResult < ' tcx , ty:: Region < ' tcx > > {
305
- debug ! ( "SimpleEqRelation::regions(a={:?}, b={:?})" , a, b) ;
306
-
307
- // We can just equate the regions because LBRs have been
308
- // already anonymized.
309
- if a == b {
310
- Ok ( a)
311
- } else {
312
- // I'm not sure is this `TypeError` is the right one, but
313
- // it should not matter as it won't be checked (the dropck
314
- // will emit its own, more informative and higher-level errors
315
- // in case anything goes wrong).
316
- Err ( TypeError :: RegionsPlaceholderMismatch )
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
+ ) ;
317
200
}
201
+ return Err ( guar. unwrap ( ) ) ;
318
202
}
319
203
320
- fn consts (
321
- & mut self ,
322
- a : ty:: Const < ' tcx > ,
323
- b : ty:: Const < ' tcx > ,
324
- ) -> RelateResult < ' tcx , ty:: Const < ' tcx > > {
325
- debug ! ( "SimpleEqRelation::consts(a={:?}, b={:?})" , a, b) ;
326
- ty:: relate:: super_relate_consts ( self , a, b)
327
- }
328
-
329
- fn binders < T > (
330
- & mut self ,
331
- a : ty:: Binder < ' tcx , T > ,
332
- b : ty:: Binder < ' tcx , T > ,
333
- ) -> RelateResult < ' tcx , ty:: Binder < ' tcx , T > >
334
- where
335
- T : Relate < ' tcx > ,
336
- {
337
- debug ! ( "SimpleEqRelation::binders({:?}: {:?}" , a, b) ;
338
-
339
- // Anonymizing the LBRs is necessary to solve (Issue #59497).
340
- // After we do so, it should be totally fine to skip the binders.
341
- let anon_a = self . tcx . anonymize_bound_vars ( a) ;
342
- let anon_b = self . tcx . anonymize_bound_vars ( b) ;
343
- self . relate ( anon_a. skip_binder ( ) , anon_b. skip_binder ( ) ) ?;
344
-
345
- Ok ( a)
346
- }
204
+ Ok ( ( ) )
347
205
}
0 commit comments