@@ -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
@@ -251,15 +258,15 @@ fn compare_predicate_entailment<'tcx>(
251
258
252
259
let mut wf_tys = FxIndexSet :: default ( ) ;
253
260
254
- let impl_sig = infcx. replace_bound_vars_with_fresh_vars (
261
+ let unnormalized_impl_sig = infcx. replace_bound_vars_with_fresh_vars (
255
262
impl_m_span,
256
263
infer:: HigherRankedType ,
257
264
tcx. fn_sig ( impl_m. def_id ) ,
258
265
) ;
266
+ let unnormalized_impl_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( unnormalized_impl_sig) ) ;
259
267
260
268
let norm_cause = ObligationCause :: misc ( impl_m_span, impl_m_hir_id) ;
261
- let impl_sig = ocx. normalize ( & norm_cause, param_env, impl_sig) ;
262
- let impl_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( impl_sig) ) ;
269
+ let impl_fty = ocx. normalize ( & norm_cause, param_env, unnormalized_impl_fty) ;
263
270
debug ! ( "compare_impl_method: impl_fty={:?}" , impl_fty) ;
264
271
265
272
let trait_sig = tcx. bound_fn_sig ( trait_m. def_id ) . subst ( tcx, trait_to_placeholder_substs) ;
@@ -300,29 +307,108 @@ fn compare_predicate_entailment<'tcx>(
300
307
return Err ( emitted) ;
301
308
}
302
309
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
+ ) ) ;
319
+ }
320
+ let emit_implied_wf_lint = || {
321
+ infcx. tcx . struct_span_lint_hir (
322
+ rustc_session:: lint:: builtin:: IMPLIED_BOUNDS_ENTAILMENT ,
323
+ impl_m_hir_id,
324
+ infcx. tcx . def_span ( impl_m. def_id ) ,
325
+ "impl method assumes more implied bounds than the corresponding trait method" ,
326
+ |lint| lint,
327
+ ) ;
328
+ } ;
329
+
303
330
// Check that all obligations are satisfied by the implementation's
304
331
// version.
305
332
let errors = ocx. select_all_or_error ( ) ;
306
333
if !errors. is_empty ( ) {
307
- let reported = infcx. err_ctxt ( ) . report_fulfillment_errors ( & errors, None ) ;
308
- return Err ( reported) ;
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
+ }
309
354
}
310
355
311
356
// Finally, resolve all regions. This catches wily misuses of
312
357
// lifetime parameters.
313
- let outlives_environment = OutlivesEnvironment :: with_bounds (
358
+ let outlives_env = OutlivesEnvironment :: with_bounds (
314
359
param_env,
315
360
Some ( infcx) ,
316
- infcx. implied_bounds_tys ( param_env, impl_m_hir_id, wf_tys) ,
361
+ infcx. implied_bounds_tys ( param_env, impl_m_hir_id, wf_tys. clone ( ) ) ,
317
362
) ;
318
- infcx. check_region_obligations_and_report_errors (
319
- impl_m . def_id . expect_local ( ) ,
320
- & outlives_environment ,
363
+ infcx. process_registered_region_obligations (
364
+ outlives_env . region_bound_pairs ( ) ,
365
+ outlives_env . param_env ,
321
366
) ;
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
+ }
395
+ }
322
396
323
397
Ok ( ( ) )
324
398
}
325
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 ,
410
+ }
411
+
326
412
#[ instrument( skip( tcx) , level = "debug" , ret) ]
327
413
pub fn collect_trait_impl_trait_tys < ' tcx > (
328
414
tcx : TyCtxt < ' tcx > ,
0 commit comments