@@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem;
14
14
use rustc_hir:: ItemKind ;
15
15
use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
16
16
use rustc_infer:: infer:: outlives:: obligations:: TypeOutlives ;
17
- use rustc_infer:: infer:: TyCtxtInferExt ;
18
17
use rustc_infer:: infer:: { self , RegionckMode , SubregionOrigin } ;
18
+ use rustc_infer:: infer:: { RegionResolutionError , TyCtxtInferExt } ;
19
+ use rustc_infer:: traits:: TraitEngine ;
19
20
use rustc_middle:: hir:: map as hir_map;
20
21
use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
21
22
use rustc_middle:: ty:: trait_def:: TraitSpecializationKind ;
@@ -26,7 +27,9 @@ use rustc_session::parse::feature_err;
26
27
use rustc_span:: symbol:: { sym, Ident , Symbol } ;
27
28
use rustc_span:: { Span , DUMMY_SP } ;
28
29
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
29
- use rustc_trait_selection:: traits:: { self , ObligationCause , ObligationCauseCode , WellFormedLoc } ;
30
+ use rustc_trait_selection:: traits:: {
31
+ self , ObligationCause , ObligationCauseCode , TraitEngineExt , WellFormedLoc ,
32
+ } ;
30
33
31
34
use std:: convert:: TryInto ;
32
35
use std:: iter;
@@ -426,42 +429,105 @@ fn check_gat_where_clauses(
426
429
}
427
430
}
428
431
429
- // If there are any missing clauses, emit an error
430
- let mut clauses = clauses. unwrap_or_default ( ) ;
432
+ // If there are any clauses that aren't provable , emit an error
433
+ let clauses = clauses. unwrap_or_default ( ) ;
431
434
debug ! ( ?clauses) ;
432
435
if !clauses. is_empty ( ) {
433
- let written_predicates: ty:: GenericPredicates < ' _ > =
434
- tcx. explicit_predicates_of ( trait_item. def_id ) ;
435
- let mut clauses: Vec < _ > = clauses
436
- . drain_filter ( |clause| !written_predicates. predicates . iter ( ) . any ( |p| & p. 0 == clause) )
437
- . map ( |clause| format ! ( "{}" , clause) )
438
- . collect ( ) ;
439
- // We sort so that order is predictable
440
- clauses. sort ( ) ;
441
- if !clauses. is_empty ( ) {
442
- let mut err = tcx. sess . struct_span_err (
443
- trait_item. span ,
444
- & format ! ( "Missing required bounds on {}" , trait_item. ident) ,
445
- ) ;
436
+ let param_env = tcx. param_env ( trait_item. def_id ) ;
446
437
447
- let suggestion = format ! (
448
- "{} {}" ,
449
- if !trait_item. generics. where_clause. predicates. is_empty( ) {
450
- ","
451
- } else {
452
- " where"
453
- } ,
454
- clauses. join( ", " ) ,
455
- ) ;
456
- err. span_suggestion (
457
- trait_item. generics . where_clause . tail_span_for_suggestion ( ) ,
458
- "add the required where clauses" ,
459
- suggestion,
460
- Applicability :: MachineApplicable ,
461
- ) ;
438
+ // This shouldn't really matter, but we need it
439
+ let cause = traits:: ObligationCause :: new (
440
+ trait_item. span ,
441
+ trait_item. hir_id ( ) ,
442
+ ObligationCauseCode :: MiscObligation ,
443
+ ) ;
444
+ // Create an `InferCtxt` to try to prove the clauses we require
445
+ tcx. infer_ctxt ( ) . enter ( |infcx| {
446
+ let mut fulfillment_cx = <dyn TraitEngine < ' _ > >:: new ( tcx) ;
447
+
448
+ // Register all the clauses as obligations
449
+ clauses
450
+ . clone ( )
451
+ . into_iter ( )
452
+ . map ( |predicate| {
453
+ traits:: Obligation :: new (
454
+ cause. clone ( ) ,
455
+ param_env,
456
+ predicate,
457
+ )
458
+ } )
459
+ . for_each ( |obligation| {
460
+ fulfillment_cx. register_predicate_obligation ( & infcx, obligation)
461
+ } ) ;
462
+
463
+ // Convert these obligations into constraints by selecting
464
+ let errors = fulfillment_cx. select_all_or_error ( & infcx) ;
465
+ if !errors. is_empty ( ) {
466
+ bug ! ( "should have only registered region obligations, which get registerd as constraints" ) ;
467
+ }
462
468
463
- err. emit ( )
464
- }
469
+ // FIXME(jackh726): some of this code is shared with `regionctxt`, but in a different
470
+ // flow; we could probably better extract the shared logic
471
+
472
+ // Process the region obligations
473
+ let body_id_map = infcx
474
+ . inner
475
+ . borrow ( )
476
+ . region_obligations ( )
477
+ . iter ( )
478
+ . map ( |& ( id, _) | ( id, vec ! [ ] ) )
479
+ . collect ( ) ;
480
+
481
+ infcx. process_registered_region_obligations ( & body_id_map, None , param_env) ;
482
+
483
+ // Resolve the region constraints to find any constraints that we're provable
484
+ let outlives_env = OutlivesEnvironment :: new ( param_env) ;
485
+ let errors = infcx. resolve_regions ( trait_item. def_id . to_def_id ( ) , & outlives_env, RegionckMode :: default ( ) ) ;
486
+
487
+ // Emit an error if there are non-provable constriants
488
+ if !errors. is_empty ( ) {
489
+ let mut clauses: Vec < _ > = errors. into_iter ( ) . map ( |error| match error {
490
+ RegionResolutionError :: ConcreteFailure ( _, sup, sub) => format ! ( "{}: {}" , sub, sup) ,
491
+ RegionResolutionError :: GenericBoundFailure ( _, sub, sup) => format ! ( "{}: {}" , sub, sup) ,
492
+ _ => bug ! ( "Unexpected region resolution error when resolving outlives lint" ) ,
493
+ } ) . collect ( ) ;
494
+ clauses. sort ( ) ;
495
+
496
+ let plural = if clauses. len ( ) > 1 { "s" } else { "" } ;
497
+ let mut err = tcx. sess . struct_span_err (
498
+ trait_item. span ,
499
+ & format ! ( "missing required bound{} on `{}`" , plural, trait_item. ident) ,
500
+ ) ;
501
+
502
+ let suggestion = format ! (
503
+ "{} {}" ,
504
+ if !trait_item. generics. where_clause. predicates. is_empty( ) {
505
+ ","
506
+ } else {
507
+ " where"
508
+ } ,
509
+ clauses. join( ", " ) ,
510
+ ) ;
511
+ err. span_suggestion (
512
+ trait_item. generics . where_clause . tail_span_for_suggestion ( ) ,
513
+ & format ! ( "add the required where clause{}" , plural) ,
514
+ suggestion,
515
+ Applicability :: MachineApplicable ,
516
+ ) ;
517
+
518
+ let bound = if clauses. len ( ) > 1 { "these bounds are" } else { "this bound is" } ;
519
+ err. note (
520
+ & format ! ( "{} required to ensure that impls have maximum flexibility" , bound)
521
+ ) ;
522
+ err. note (
523
+ "see issue #87479 \
524
+ <https://github.com/rust-lang/rust/issues/87479> \
525
+ for more information",
526
+ ) ;
527
+
528
+ err. emit ( )
529
+ }
530
+ } ) ;
465
531
}
466
532
}
467
533
@@ -541,7 +607,8 @@ fn region_known_to_outlive<'tcx>(
541
607
} ) ;
542
608
543
609
use rustc_infer:: infer:: outlives:: obligations:: TypeOutlivesDelegate ;
544
- ( & infcx) . push_sub_region_constraint ( origin, region_a, region_b) ;
610
+ // `region_a: region_b` -> `region_b <= region_a`
611
+ ( & infcx) . push_sub_region_constraint ( origin, region_b, region_a) ;
545
612
546
613
let errors = infcx. resolve_regions (
547
614
id. expect_owner ( ) . to_def_id ( ) ,
0 commit comments