@@ -14,8 +14,9 @@ use rustc_hir::lang_items::LangItem;
1414use rustc_hir:: ItemKind ;
1515use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
1616use rustc_infer:: infer:: outlives:: obligations:: TypeOutlives ;
17- use rustc_infer:: infer:: TyCtxtInferExt ;
1817use rustc_infer:: infer:: { self , RegionckMode , SubregionOrigin } ;
18+ use rustc_infer:: infer:: { RegionResolutionError , TyCtxtInferExt } ;
19+ use rustc_infer:: traits:: TraitEngine ;
1920use rustc_middle:: hir:: map as hir_map;
2021use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
2122use rustc_middle:: ty:: trait_def:: TraitSpecializationKind ;
@@ -26,7 +27,9 @@ use rustc_session::parse::feature_err;
2627use rustc_span:: symbol:: { sym, Ident , Symbol } ;
2728use rustc_span:: { Span , DUMMY_SP } ;
2829use 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+ } ;
3033
3134use std:: convert:: TryInto ;
3235use std:: iter;
@@ -426,42 +429,105 @@ fn check_gat_where_clauses(
426429 }
427430 }
428431
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 ( ) ;
431434 debug ! ( ?clauses) ;
432435 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 ) ;
446437
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+ }
462468
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+ } ) ;
465531 }
466532}
467533
@@ -541,7 +607,8 @@ fn region_known_to_outlive<'tcx>(
541607 } ) ;
542608
543609 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) ;
545612
546613 let errors = infcx. resolve_regions (
547614 id. expect_owner ( ) . to_def_id ( ) ,
0 commit comments