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