11// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
22//
33// We don't do any drop checking during hir typeck.
4+ use rustc_data_structures:: fx:: FxHashSet ;
45use 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 } ;
78use rustc_middle:: ty:: subst:: SubstsRef ;
89use 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 } ;
1012
1113use crate :: errors;
1214use crate :: hir:: def_id:: { DefId , LocalDefId } ;
@@ -43,21 +45,20 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
4345 }
4446 }
4547 let dtor_self_type = tcx. type_of ( drop_impl_did) . subst_identity ( ) ;
46- let dtor_predicates = tcx. predicates_of ( drop_impl_did) ;
4748 match dtor_self_type. kind ( ) {
48- ty:: Adt ( adt_def, self_to_impl_substs ) => {
49+ ty:: Adt ( adt_def, adt_to_impl_substs ) => {
4950 ensure_drop_params_and_item_params_correspond (
5051 tcx,
5152 drop_impl_did. expect_local ( ) ,
5253 adt_def. did ( ) ,
53- self_to_impl_substs ,
54+ adt_to_impl_substs ,
5455 ) ?;
5556
5657 ensure_drop_predicates_are_implied_by_item_defn (
5758 tcx,
58- dtor_predicates ,
59+ drop_impl_did . expect_local ( ) ,
5960 adt_def. did ( ) . expect_local ( ) ,
60- self_to_impl_substs ,
61+ adt_to_impl_substs ,
6162 )
6263 }
6364 _ => {
@@ -78,9 +79,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
7879 tcx : TyCtxt < ' tcx > ,
7980 drop_impl_did : LocalDefId ,
8081 self_type_did : DefId ,
81- drop_impl_substs : SubstsRef < ' tcx > ,
82+ adt_to_impl_substs : SubstsRef < ' tcx > ,
8283) -> 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 {
8485 return Ok ( ( ) )
8586 } ;
8687
@@ -111,237 +112,94 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
111112/// implied by assuming the predicates attached to self_type_did.
112113fn ensure_drop_predicates_are_implied_by_item_defn < ' tcx > (
113114 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 > ,
117118) -> 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.
138127 //
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+ }
187141
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+ ) ;
230168 }
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) ;
245169 }
170+ return Err ( guar. unwrap ( ) ) ;
246171 }
247172
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+ ) ;
317200 }
201+ return Err ( guar. unwrap ( ) ) ;
318202 }
319203
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 ( ( ) )
347205}
0 commit comments