@@ -67,8 +67,14 @@ pub(crate) fn compare_impl_method<'tcx>(
6767 return ;
6868 }
6969
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+ ) {
7278 return ;
7379 }
7480}
@@ -146,6 +152,7 @@ fn compare_predicate_entailment<'tcx>(
146152 impl_m_span : Span ,
147153 trait_m : & ty:: AssocItem ,
148154 impl_trait_ref : ty:: TraitRef < ' tcx > ,
155+ check_implied_wf : CheckImpliedWfMode ,
149156) -> Result < ( ) , ErrorGuaranteed > {
150157 let trait_to_impl_substs = impl_trait_ref. substs ;
151158
@@ -300,92 +307,106 @@ fn compare_predicate_entailment<'tcx>(
300307 return Err ( emitted) ;
301308 }
302309
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+ ) ) ;
309319 }
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 = || {
362321 infcx. tcx . struct_span_lint_hir (
363322 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 ) ,
366325 "impl method assumes more implied bounds than the corresponding trait method" ,
367326 |lint| lint,
368327 ) ;
369328 } ;
370329
330+ // Check that all obligations are satisfied by the implementation's
331+ // version.
371332 let errors = ocx. select_all_or_error ( ) ;
372333 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+ }
374354 }
375355
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 (
377359 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 ( ) ) ,
380362 ) ;
381363 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 ,
384366 ) ;
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+ }
388395 }
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 ,
389410}
390411
391412#[ instrument( skip( tcx) , level = "debug" , ret) ]
0 commit comments