@@ -71,8 +71,14 @@ pub(crate) fn compare_impl_method<'tcx>(
7171 return ;
7272 }
7373
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+ ) {
7682 return ;
7783 }
7884}
@@ -150,6 +156,7 @@ fn compare_predicate_entailment<'tcx>(
150156 impl_m_span : Span ,
151157 trait_m : & ty:: AssocItem ,
152158 impl_trait_ref : ty:: TraitRef < ' tcx > ,
159+ check_implied_wf : CheckImpliedWfMode ,
153160) -> Result < ( ) , ErrorGuaranteed > {
154161 let trait_to_impl_substs = impl_trait_ref. substs ;
155162
@@ -304,92 +311,106 @@ fn compare_predicate_entailment<'tcx>(
304311 return Err ( emitted) ;
305312 }
306313
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+ ) ) ;
313323 }
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 = || {
366325 infcx. tcx . struct_span_lint_hir (
367326 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 ) ,
370329 "impl method assumes more implied bounds than the corresponding trait method" ,
371330 |lint| lint,
372331 ) ;
373332 } ;
374333
334+ // Check that all obligations are satisfied by the implementation's
335+ // version.
375336 let errors = ocx. select_all_or_error ( ) ;
376337 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+ }
378358 }
379359
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 (
381363 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 ( ) ) ,
384366 ) ;
385367 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 ,
388370 ) ;
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+ }
392399 }
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 ,
393414}
394415
395416fn compare_asyncness < ' tcx > (
0 commit comments