@@ -7,7 +7,7 @@ use std::iter;
77
88use rustc_hir as hir;
99use rustc_hir:: attrs:: lang_items:: LangItem ;
10- use rustc_infer:: traits:: { ObligationCauseCode , PredicateObligations } ;
10+ use rustc_infer:: traits:: { ObligationCauseCode , PredicateObligation , PredicateObligations } ;
1111use rustc_middle:: bug;
1212use rustc_middle:: ty:: {
1313 self , DelayedSet , GenericArgsRef , Term , TermKind , Ty , TyCtxt , TypeSuperVisitable ,
@@ -16,7 +16,7 @@ use rustc_middle::ty::{
1616use rustc_session:: diagnostics:: feature_err;
1717use rustc_span:: def_id:: { DefId , LocalDefId } ;
1818use rustc_span:: { Span , sym} ;
19- use tracing:: { debug, instrument, trace } ;
19+ use tracing:: { debug, instrument} ;
2020
2121use crate :: infer:: InferCtxt ;
2222use crate :: traits;
@@ -392,10 +392,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
392392 return ;
393393 }
394394
395- // if the trait predicate is not const, the wf obligations should not be const as well.
396- let obligations = self . nominal_obligations ( trait_ref. def_id , trait_ref. args ) ;
397-
398- debug ! ( "compute_trait_pred obligations {:?}" , obligations) ;
399395 let param_env = self . param_env ;
400396 let depth = self . recursion_depth ;
401397
@@ -412,12 +408,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
412408 traits:: Obligation :: with_depth ( tcx, cause, depth, param_env, predicate)
413409 } ;
414410
411+ // if the trait predicate is not const, the wf obligations should not be const as well.
415412 if let Elaborate :: All = elaborate {
413+ let mut obligations = PredicateObligations :: new ( ) ;
414+ self . nominal_obligations ( trait_ref. def_id , trait_ref. args , |_, obligation| {
415+ obligations. push ( obligation)
416+ } ) ;
417+ debug ! ( "compute_trait_pred obligations {:?}" , obligations) ;
416418 let implied_obligations = traits:: util:: elaborate ( tcx, obligations) ;
417419 let implied_obligations = implied_obligations. map ( extend) ;
418420 self . out . extend ( implied_obligations) ;
419421 } else {
420- self . out . extend ( obligations) ;
422+ self . nominal_obligations ( trait_ref. def_id , trait_ref. args , |this, obligation| {
423+ this. out . push ( obligation)
424+ } ) ;
421425 }
422426
423427 self . out . extend (
@@ -481,8 +485,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
481485 // `i32: Clone`
482486 // `i32: Copy`
483487 // ]
484- let obligations = self . nominal_obligations ( data. expect_projection_def_id ( ) , data. args ) ;
485- self . out . extend ( obligations) ;
488+ self . nominal_obligations ( data. expect_projection_def_id ( ) , data. args , |this, obligation| {
489+ this. out . push ( obligation)
490+ } ) ;
486491
487492 self . add_wf_preds_for_projection_args ( data. args ) ;
488493 }
@@ -511,8 +516,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
511516 & mut self . out ,
512517 ) ;
513518 let def_id = data. expect_inherent_def_id ( ) ;
514- let obligations = self . nominal_obligations ( def_id, args) ;
515- self . out . extend ( obligations) ;
519+ self . nominal_obligations ( def_id, args, |this, obligation| this. out . push ( obligation) ) ;
516520 }
517521
518522 data. args . visit_with ( self ) ;
@@ -565,51 +569,51 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
565569 debug ! ( ?self . out) ;
566570 }
567571
568- #[ instrument( level = "debug" , skip( self ) ) ]
572+ #[ instrument( level = "debug" , skip( self , push_obligation ) ) ]
569573 fn nominal_obligations (
570574 & mut self ,
571575 def_id : DefId ,
572576 args : GenericArgsRef < ' tcx > ,
573- ) -> PredicateObligations < ' tcx > {
577+ mut push_obligation : impl FnMut ( & mut Self , PredicateObligation < ' tcx > ) ,
578+ ) {
574579 // PERF: `Sized`'s predicates include `MetaSized`, but both are compiler implemented marker
575580 // traits, so `MetaSized` will always be WF if `Sized` is WF and vice-versa. Determining
576581 // the nominal obligations of `Sized` would in-effect just elaborate `MetaSized` and make
577582 // the compiler do a bunch of work needlessly.
578583 if self . tcx ( ) . is_lang_item ( def_id, LangItem :: Sized ) {
579- return Default :: default ( ) ;
584+ return ;
580585 }
581586 if self . tcx ( ) . is_lang_item ( def_id, LangItem :: ConstParamTy )
582587 && self . tcx ( ) . features ( ) . const_param_ty_unchecked ( )
583588 {
584- return Default :: default ( ) ;
589+ return ;
585590 }
586591
587- let gen_clauses = self . tcx ( ) . clauses_of ( def_id ) ;
588- let mut origins = vec ! [ def_id; gen_clauses . clauses . len ( ) ] ;
589- let mut head = gen_clauses ;
590- while let Some ( parent) = head. parent {
591- head = self . tcx ( ) . clauses_of ( parent ) ;
592- origins . extend ( iter :: repeat ( parent) . take ( head . clauses . len ( ) ) ) ;
592+ let tcx = self . tcx ( ) ;
593+ let mut head = ( def_id, tcx . clauses_of ( def_id ) ) ;
594+ let mut inner_levels = Vec :: new ( ) ; // only allocates if a parent chain exists
595+ while let Some ( parent) = head. 1 . parent {
596+ inner_levels . push ( head ) ;
597+ head = ( parent, tcx . clauses_of ( parent ) ) ;
593598 }
594599
595- let gen_clauses = gen_clauses. instantiate ( self . tcx ( ) , args) ;
596- trace ! ( "{:#?}" , gen_clauses) ;
597- debug_assert_eq ! ( gen_clauses. clauses. len( ) , origins. len( ) ) ;
598-
599- iter:: zip ( gen_clauses, origins. into_iter ( ) . rev ( ) )
600- . map ( |( ( clause, span) , origin_def_id) | {
601- let code = ObligationCauseCode :: WhereClause ( origin_def_id, span) ;
602- let cause = self . cause ( code) ;
603- traits:: Obligation :: with_depth (
604- self . tcx ( ) ,
605- cause,
606- self . recursion_depth ,
607- self . param_env ,
608- clause. skip_norm_wip ( ) ,
609- )
610- } )
611- . filter ( |clause| !clause. has_escaping_bound_vars ( ) )
612- . collect ( )
600+ // Emit outermost first, as diagnostics rely on that order.
601+ for & ( origin_def_id, clauses) in iter:: once ( & head) . chain ( inner_levels. iter ( ) . rev ( ) ) {
602+ for ( clause, span) in clauses. instantiate_own ( tcx, args) {
603+ if !clause. has_escaping_bound_vars ( ) {
604+ let code = ObligationCauseCode :: WhereClause ( origin_def_id, span) ;
605+ let cause = self . cause ( code) ;
606+ let obligation = traits:: Obligation :: with_depth (
607+ tcx,
608+ cause,
609+ self . recursion_depth ,
610+ self . param_env ,
611+ clause. skip_norm_wip ( ) ,
612+ ) ;
613+ push_obligation ( self , obligation) ;
614+ }
615+ }
616+ }
613617 }
614618
615619 fn add_wf_preds_for_dyn_ty (
@@ -818,8 +822,9 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
818822 ..
819823 } ,
820824 ) => {
821- let obligations = self . nominal_obligations ( def_id, args) ;
822- self . out . extend ( obligations) ;
825+ self . nominal_obligations ( def_id, args, |this, obligation| {
826+ this. out . push ( obligation)
827+ } ) ;
823828 }
824829 ty:: Alias ( _, data @ ty:: AliasTy { kind : ty:: Inherent { .. } , .. } ) => {
825830 self . add_wf_preds_for_inherent_projection ( data. into ( ) ) ;
@@ -828,8 +833,9 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
828833
829834 ty:: Adt ( def, args) => {
830835 // WfNominalType
831- let obligations = self . nominal_obligations ( def. did ( ) , args) ;
832- self . out . extend ( obligations) ;
836+ self . nominal_obligations ( def. did ( ) , args, |this, obligation| {
837+ this. out . push ( obligation)
838+ } ) ;
833839 }
834840
835841 ty:: FnDef ( did, args) => {
@@ -842,8 +848,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
842848 let fn_sig = tcx. fn_sig ( did) . instantiate ( tcx, args) . skip_norm_wip ( ) ;
843849 fn_sig. output ( ) . skip_binder ( ) . visit_with ( self ) ;
844850
845- let obligations = self . nominal_obligations ( did, args) ;
846- self . out . extend ( obligations) ;
851+ self . nominal_obligations ( did, args, |this, obligation| this. out . push ( obligation) ) ;
847852 }
848853
849854 ty:: Ref ( r, rty, _) => {
@@ -870,8 +875,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
870875 // about the signature of the closure. We don't
871876 // have the problem of implied bounds here since
872877 // coroutines don't take arguments.
873- let obligations = self . nominal_obligations ( did, args) ;
874- self . out . extend ( obligations) ;
878+ self . nominal_obligations ( did, args, |this, obligation| this. out . push ( obligation) ) ;
875879 }
876880
877881 ty:: Closure ( did, args) => {
@@ -890,8 +894,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
890894 // can cause compiler crashes when the user abuses unsafe
891895 // code to procure such a closure.
892896 // See tests/ui/type-alias-impl-trait/wf_check_closures.rs
893- let obligations = self . nominal_obligations ( did, args) ;
894- self . out . extend ( obligations) ;
897+ self . nominal_obligations ( did, args, |this, obligation| this. out . push ( obligation) ) ;
895898 // Only check the upvar types for WF, not the rest
896899 // of the types within. This is needed because we
897900 // capture the signature and it may not be WF
@@ -918,8 +921,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
918921
919922 ty:: CoroutineClosure ( did, args) => {
920923 // See the above comments. The same apply to coroutine-closures.
921- let obligations = self . nominal_obligations ( did, args) ;
922- self . out . extend ( obligations) ;
924+ self . nominal_obligations ( did, args, |this, obligation| this. out . push ( obligation) ) ;
923925 let upvars = args. as_coroutine_closure ( ) . tupled_upvars_ty ( ) ;
924926 return upvars. visit_with ( self ) ;
925927 }
@@ -988,27 +990,27 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
988990 //
989991 // See also: https://rustc-dev-guide.rust-lang.org/const-generics.html
990992 let args = principal. skip_binder ( ) . with_self_ty ( self . tcx ( ) , t) . args ;
991- let obligations =
992- self . nominal_obligations ( principal_def_id, args) . into_iter ( ) . filter ( |o| {
993- let kind = o. predicate . kind ( ) . skip_binder ( ) ;
994- match kind {
995- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType (
996- ct,
997- _,
998- ) ) if matches ! ( ct. kind( ) , ty:: ConstKind :: Param ( ..) ) => {
999- // ConstArgHasType clauses are not higher kinded. Assert as
1000- // such so we can fix this up if that ever changes.
1001- assert ! ( o. predicate. kind( ) . bound_vars( ) . is_empty( ) ) ;
1002- // In stable rust, variables from the trait object binder
1003- // cannot be referenced by a ConstArgHasType clause. However,
1004- // under `generic_const_parameter_types`, it can. Ignore those
1005- // predicates for now, to not have HKT-ConstArgHasTypes.
1006- !kind. has_escaping_bound_vars ( )
1007- }
1008- _ => false ,
993+ self . nominal_obligations ( principal_def_id, args, |this, obligation| {
994+ let kind = obligation. predicate . kind ( ) . skip_binder ( ) ;
995+ let keep = match kind {
996+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ct, _) )
997+ if matches ! ( ct. kind( ) , ty:: ConstKind :: Param ( ..) ) =>
998+ {
999+ // ConstArgHasType clauses are not higher kinded. Assert as
1000+ // such so we can fix this up if that ever changes.
1001+ assert ! ( obligation. predicate. kind( ) . bound_vars( ) . is_empty( ) ) ;
1002+ // In stable rust, variables from the trait object binder
1003+ // cannot be referenced by a ConstArgHasType clause. However,
1004+ // under `generic_const_parameter_types`, it can. Ignore those
1005+ // predicates for now, to not have HKT-ConstArgHasTypes.
1006+ !kind. has_escaping_bound_vars ( )
10091007 }
1010- } ) ;
1011- self . out . extend ( obligations) ;
1008+ _ => false ,
1009+ } ;
1010+ if keep {
1011+ this. out . push ( obligation) ;
1012+ }
1013+ } ) ;
10121014 }
10131015
10141016 if !t. has_escaping_bound_vars ( ) {
@@ -1100,8 +1102,11 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
11001102 ty:: AliasConstKind :: Projection { def_id }
11011103 | ty:: AliasConstKind :: Free { def_id }
11021104 | ty:: AliasConstKind :: Anon { def_id } => {
1103- let obligations = self . nominal_obligations ( def_id, alias_const. args ) ;
1104- self . out . extend ( obligations) ;
1105+ self . nominal_obligations (
1106+ def_id,
1107+ alias_const. args ,
1108+ |this, obligation| this. out . push ( obligation) ,
1109+ ) ;
11051110 }
11061111 }
11071112 }
0 commit comments