@@ -67,8 +67,14 @@ pub(crate) fn compare_impl_method<'tcx>(
67
67
return ;
68
68
}
69
69
70
- if let Err ( _) = compare_predicate_entailment ( tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
71
- {
70
+ if let Err ( _) = compare_predicate_entailment (
71
+ tcx,
72
+ impl_m,
73
+ impl_m_span,
74
+ trait_m,
75
+ impl_trait_ref,
76
+ CheckImpliedWfMode :: Check ,
77
+ ) {
72
78
return ;
73
79
}
74
80
}
@@ -146,6 +152,7 @@ fn compare_predicate_entailment<'tcx>(
146
152
impl_m_span : Span ,
147
153
trait_m : & ty:: AssocItem ,
148
154
impl_trait_ref : ty:: TraitRef < ' tcx > ,
155
+ check_implied_wf : CheckImpliedWfMode ,
149
156
) -> Result < ( ) , ErrorGuaranteed > {
150
157
let trait_to_impl_substs = impl_trait_ref. substs ;
151
158
@@ -300,92 +307,106 @@ fn compare_predicate_entailment<'tcx>(
300
307
return Err ( emitted) ;
301
308
}
302
309
303
- // Check that all obligations are satisfied by the implementation's
304
- // version.
305
- let errors = ocx. select_all_or_error ( ) ;
306
- if !errors. is_empty ( ) {
307
- let reported = infcx. err_ctxt ( ) . report_fulfillment_errors ( & errors, None ) ;
308
- return Err ( reported) ;
310
+ if check_implied_wf == CheckImpliedWfMode :: Check {
311
+ // We need to check that the impl's args are well-formed given
312
+ // the hybrid param-env (impl + trait method where-clauses).
313
+ ocx. register_obligation ( traits:: Obligation :: new (
314
+ infcx. tcx ,
315
+ ObligationCause :: dummy ( ) ,
316
+ param_env,
317
+ ty:: Binder :: dummy ( ty:: PredicateKind :: WellFormed ( unnormalized_impl_fty. into ( ) ) ) ,
318
+ ) ) ;
309
319
}
310
-
311
- // FIXME(compiler-errors): This can be removed when IMPLIED_BOUNDS_ENTAILMENT
312
- // becomes a hard error.
313
- let lint_infcx = infcx. fork ( ) ;
314
-
315
- // Finally, resolve all regions. This catches wily misuses of
316
- // lifetime parameters.
317
- let outlives_environment = OutlivesEnvironment :: with_bounds (
318
- param_env,
319
- Some ( infcx) ,
320
- infcx. implied_bounds_tys ( param_env, impl_m_hir_id, wf_tys. clone ( ) ) ,
321
- ) ;
322
- if let Some ( guar) = infcx. check_region_obligations_and_report_errors (
323
- impl_m. def_id . expect_local ( ) ,
324
- & outlives_environment,
325
- ) {
326
- return Err ( guar) ;
327
- }
328
-
329
- // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
330
- // becomes a hard error (i.e. ideally we'd just register a WF obligation above...)
331
- lint_implied_wf_entailment (
332
- impl_m. def_id . expect_local ( ) ,
333
- lint_infcx,
334
- param_env,
335
- unnormalized_impl_fty,
336
- wf_tys,
337
- ) ;
338
-
339
- Ok ( ( ) )
340
- }
341
-
342
- fn lint_implied_wf_entailment < ' tcx > (
343
- impl_m_def_id : LocalDefId ,
344
- infcx : InferCtxt < ' tcx > ,
345
- param_env : ty:: ParamEnv < ' tcx > ,
346
- unnormalized_impl_fty : Ty < ' tcx > ,
347
- wf_tys : FxIndexSet < Ty < ' tcx > > ,
348
- ) {
349
- let ocx = ObligationCtxt :: new ( & infcx) ;
350
-
351
- // We need to check that the impl's args are well-formed given
352
- // the hybrid param-env (impl + trait method where-clauses).
353
- ocx. register_obligation ( traits:: Obligation :: new (
354
- infcx. tcx ,
355
- ObligationCause :: dummy ( ) ,
356
- param_env,
357
- ty:: Binder :: dummy ( ty:: PredicateKind :: WellFormed ( unnormalized_impl_fty. into ( ) ) ) ,
358
- ) ) ;
359
-
360
- let hir_id = infcx. tcx . hir ( ) . local_def_id_to_hir_id ( impl_m_def_id) ;
361
- let lint = || {
320
+ let emit_implied_wf_lint = || {
362
321
infcx. tcx . struct_span_lint_hir (
363
322
rustc_session:: lint:: builtin:: IMPLIED_BOUNDS_ENTAILMENT ,
364
- hir_id ,
365
- infcx. tcx . def_span ( impl_m_def_id ) ,
323
+ impl_m_hir_id ,
324
+ infcx. tcx . def_span ( impl_m . def_id ) ,
366
325
"impl method assumes more implied bounds than the corresponding trait method" ,
367
326
|lint| lint,
368
327
) ;
369
328
} ;
370
329
330
+ // Check that all obligations are satisfied by the implementation's
331
+ // version.
371
332
let errors = ocx. select_all_or_error ( ) ;
372
333
if !errors. is_empty ( ) {
373
- lint ( ) ;
334
+ match check_implied_wf {
335
+ CheckImpliedWfMode :: Check => {
336
+ return compare_predicate_entailment (
337
+ tcx,
338
+ impl_m,
339
+ impl_m_span,
340
+ trait_m,
341
+ impl_trait_ref,
342
+ CheckImpliedWfMode :: Skip ,
343
+ )
344
+ . map ( |( ) | {
345
+ // If the skip-mode was successful, emit a lint.
346
+ emit_implied_wf_lint ( ) ;
347
+ } ) ;
348
+ }
349
+ CheckImpliedWfMode :: Skip => {
350
+ let reported = infcx. err_ctxt ( ) . report_fulfillment_errors ( & errors, None ) ;
351
+ return Err ( reported) ;
352
+ }
353
+ }
374
354
}
375
355
376
- let outlives_environment = OutlivesEnvironment :: with_bounds (
356
+ // Finally, resolve all regions. This catches wily misuses of
357
+ // lifetime parameters.
358
+ let outlives_env = OutlivesEnvironment :: with_bounds (
377
359
param_env,
378
- Some ( & infcx) ,
379
- infcx. implied_bounds_tys ( param_env, hir_id , wf_tys. clone ( ) ) ,
360
+ Some ( infcx) ,
361
+ infcx. implied_bounds_tys ( param_env, impl_m_hir_id , wf_tys. clone ( ) ) ,
380
362
) ;
381
363
infcx. process_registered_region_obligations (
382
- outlives_environment . region_bound_pairs ( ) ,
383
- param_env,
364
+ outlives_env . region_bound_pairs ( ) ,
365
+ outlives_env . param_env ,
384
366
) ;
385
-
386
- if !infcx. resolve_regions ( & outlives_environment) . is_empty ( ) {
387
- lint ( ) ;
367
+ let errors = infcx. resolve_regions ( & outlives_env) ;
368
+ if !errors. is_empty ( ) {
369
+ // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
370
+ // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
371
+ match check_implied_wf {
372
+ CheckImpliedWfMode :: Check => {
373
+ return compare_predicate_entailment (
374
+ tcx,
375
+ impl_m,
376
+ impl_m_span,
377
+ trait_m,
378
+ impl_trait_ref,
379
+ CheckImpliedWfMode :: Skip ,
380
+ )
381
+ . map ( |( ) | {
382
+ // If the skip-mode was successful, emit a lint.
383
+ emit_implied_wf_lint ( ) ;
384
+ } ) ;
385
+ }
386
+ CheckImpliedWfMode :: Skip => {
387
+ if infcx. tainted_by_errors ( ) . is_none ( ) {
388
+ infcx. err_ctxt ( ) . report_region_errors ( impl_m. def_id . expect_local ( ) , & errors) ;
389
+ }
390
+ return Err ( tcx
391
+ . sess
392
+ . delay_span_bug ( rustc_span:: DUMMY_SP , "error should have been emitted" ) ) ;
393
+ }
394
+ }
388
395
}
396
+
397
+ Ok ( ( ) )
398
+ }
399
+
400
+ #[ derive( Debug , PartialEq , Eq ) ]
401
+ enum CheckImpliedWfMode {
402
+ /// Checks implied well-formedness of the impl method. If it fails, we will
403
+ /// re-check with `Skip`, and emit a lint if it succeeds.
404
+ Check ,
405
+ /// Skips checking implied well-formedness of the impl method, but will emit
406
+ /// a lint if the `compare_predicate_entailment` succeeded. This means that
407
+ /// the reason that we had failed earlier during `Check` was due to the impl
408
+ /// having stronger requirements than the trait.
409
+ Skip ,
389
410
}
390
411
391
412
#[ instrument( skip( tcx) , level = "debug" , ret) ]
0 commit comments