@@ -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
@@ -255,15 +262,15 @@ fn compare_predicate_entailment<'tcx>(
255
262
256
263
let mut wf_tys = FxIndexSet :: default ( ) ;
257
264
258
- let impl_sig = infcx. replace_bound_vars_with_fresh_vars (
265
+ let unnormalized_impl_sig = infcx. replace_bound_vars_with_fresh_vars (
259
266
impl_m_span,
260
267
infer:: HigherRankedType ,
261
268
tcx. fn_sig ( impl_m. def_id ) ,
262
269
) ;
270
+ let unnormalized_impl_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( unnormalized_impl_sig) ) ;
263
271
264
272
let norm_cause = ObligationCause :: misc ( impl_m_span, impl_m_hir_id) ;
265
- let impl_sig = ocx. normalize ( & norm_cause, param_env, impl_sig) ;
266
- let impl_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( impl_sig) ) ;
273
+ let impl_fty = ocx. normalize ( & norm_cause, param_env, unnormalized_impl_fty) ;
267
274
debug ! ( "compare_impl_method: impl_fty={:?}" , impl_fty) ;
268
275
269
276
let trait_sig = tcx. bound_fn_sig ( trait_m. def_id ) . subst ( tcx, trait_to_placeholder_substs) ;
@@ -304,29 +311,108 @@ fn compare_predicate_entailment<'tcx>(
304
311
return Err ( emitted) ;
305
312
}
306
313
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
+ ) ) ;
323
+ }
324
+ let emit_implied_wf_lint = || {
325
+ infcx. tcx . struct_span_lint_hir (
326
+ rustc_session:: lint:: builtin:: IMPLIED_BOUNDS_ENTAILMENT ,
327
+ impl_m_hir_id,
328
+ infcx. tcx . def_span ( impl_m. def_id ) ,
329
+ "impl method assumes more implied bounds than the corresponding trait method" ,
330
+ |lint| lint,
331
+ ) ;
332
+ } ;
333
+
307
334
// Check that all obligations are satisfied by the implementation's
308
335
// version.
309
336
let errors = ocx. select_all_or_error ( ) ;
310
337
if !errors. is_empty ( ) {
311
- let reported = infcx. err_ctxt ( ) . report_fulfillment_errors ( & errors, None ) ;
312
- return Err ( reported) ;
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
+ }
313
358
}
314
359
315
360
// Finally, resolve all regions. This catches wily misuses of
316
361
// lifetime parameters.
317
- let outlives_environment = OutlivesEnvironment :: with_bounds (
362
+ let outlives_env = OutlivesEnvironment :: with_bounds (
318
363
param_env,
319
364
Some ( infcx) ,
320
- infcx. implied_bounds_tys ( param_env, impl_m_hir_id, wf_tys) ,
365
+ infcx. implied_bounds_tys ( param_env, impl_m_hir_id, wf_tys. clone ( ) ) ,
321
366
) ;
322
- infcx. check_region_obligations_and_report_errors (
323
- impl_m . def_id . expect_local ( ) ,
324
- & outlives_environment ,
367
+ infcx. process_registered_region_obligations (
368
+ outlives_env . region_bound_pairs ( ) ,
369
+ outlives_env . param_env ,
325
370
) ;
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
+ }
399
+ }
326
400
327
401
Ok ( ( ) )
328
402
}
329
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 ,
414
+ }
415
+
330
416
fn compare_asyncness < ' tcx > (
331
417
tcx : TyCtxt < ' tcx > ,
332
418
impl_m : & ty:: AssocItem ,
0 commit comments