@@ -563,6 +563,108 @@ where
563563 WontMakeProgress ( stalled_certainty)
564564 }
565565
566+ /// This is a fast path optimization:
567+ /// If *all* the self types of all the where clauses in the goals `ParamEnv` are a
568+ /// generic arg (this is common if for example the `ParamEnv` only contains `T: Clone`
569+ /// for some generic function `fn foo<T: Clone>(t: T)`)
570+ /// And the goal does not mention any generic args, then we already know for certain that
571+ /// the evaluation of the goal doesn't depend on the `ParamEnv` in any way. That means that
572+ /// it's equivalent to evaluating the goal with an *empty* `ParamEnv`.
573+ ///
574+ /// This is desirable because the `ParamEnv` is part of the cache key, so more cache keys will
575+ /// match if they all mention the same empty `ParamEnv`.
576+ fn try_strip_param_env ( & self , goal : Goal < I , I :: Predicate > ) -> Goal < I , I :: Predicate > {
577+ let goal_may_mention_any_params =
578+ goal. predicate . has_any_type_params ( ) || goal. predicate . has_any_const_params ( ) ;
579+
580+ let is_clause_relevant_for_goal = |clause : ClauseKind < I > | -> bool {
581+ match clause {
582+ ClauseKind :: Trait ( trait_predicate) => {
583+ let irrelevant =
584+ // If the self type of this clause mentions a generic parameter
585+ // i.e. T: Clone as opposed to i32: Clone
586+ trait_predicate. self_ty ( ) . has_any_type_params ( ) &&
587+ // And the goal can never in any way use this clause because it
588+ // doesn't mention generic args, or variables that could unify with
589+ // the generic arg because of the one impl rule
590+ !goal_may_mention_any_params
591+ // then the clause is irrelevant to the outcome of the goal
592+ ;
593+
594+ !irrelevant
595+ }
596+ // FIXME: atm never relevant for goal evaluation, but might be in the future so `true`
597+ // to avoid future performance cliffs
598+ ClauseKind :: RegionOutlives ( _) => true ,
599+ ClauseKind :: TypeOutlives ( _) => true ,
600+ ClauseKind :: Projection ( projection_predicate) => {
601+ let irrelevant =
602+ // If the self type of this clause mentions a generic parameter,
603+ // i.e. T: Clone as opposed to i32: Clone
604+ projection_predicate. self_ty ( ) . has_any_type_params ( ) &&
605+ // And the goal can never in any way use this clause because it
606+ // doesn't mention generic args, or variables that could unify with
607+ // the generic arg because of the one impl rule
608+ !goal_may_mention_any_params
609+ // then the clause is irrelevant to the outcome of the goal
610+ ;
611+
612+ !irrelevant
613+ }
614+ ClauseKind :: ConstArgHasType ( c, _) => {
615+ let irrelevant =
616+ // If the const this clause bounds, mentions a generic parameter,
617+ // i.e. N: usize as opposed to 4: usize
618+ c. has_any_const_params ( ) &&
619+ // and the goal can never in any way use this clause because it
620+ // doesn't mention const generic args, or variables that could unify with
621+ // the generic arg because of the one impl rule
622+ !goal_may_mention_any_params
623+ // then the clause is irrelevant to the outcome of the goal
624+ ;
625+
626+ !irrelevant
627+ }
628+ ClauseKind :: WellFormed ( _) => true ,
629+ ClauseKind :: ConstEvaluatable ( c) => {
630+ let irrelevant =
631+ // If the const this clause bounds, mentions a generic parameter,
632+ // i.e. N is evaluatable as opposed to 3 is evaluatable
633+ c. has_any_const_params ( ) &&
634+ // and the goal can never in any way use this clause because it
635+ // doesn't mention const generic args, or variables that could unify with
636+ // the generic arg because of the one impl rule
637+ !goal_may_mention_any_params
638+ // then the clause is irrelevant to the outcome of the goal
639+ ;
640+
641+ !irrelevant
642+ }
643+ ClauseKind :: HostEffect ( _) => true ,
644+ ClauseKind :: UnstableFeature ( _) => true ,
645+ }
646+ } ;
647+
648+ let any_clause_relevant_for_goal = goal
649+ . param_env
650+ . caller_bounds ( )
651+ . iter ( )
652+ . any ( |i| is_clause_relevant_for_goal ( i. kind ( ) . skip_binder ( ) ) ) ;
653+
654+ if !any_clause_relevant_for_goal {
655+ if !goal. param_env . caller_bounds ( ) . is_empty ( ) {
656+ tracing:: debug!(
657+ "stripping param env {:?} because it is irrelevant to prove {:?}" ,
658+ goal. param_env,
659+ goal. predicate
660+ ) ;
661+ }
662+ Goal { param_env : ParamEnv :: empty ( ) , predicate : goal. predicate }
663+ } else {
664+ goal
665+ }
666+ }
667+
566668 /// Recursively evaluates `goal`, returning the nested goals in case
567669 /// the nested goal is a `NormalizesTo` goal.
568670 ///
@@ -605,6 +707,7 @@ where
605707 // duplicate entries.
606708 let opaque_types = self . delegate . clone_opaque_types_lookup_table ( ) ;
607709 let ( goal, opaque_types) = eager_resolve_vars ( self . delegate , ( goal, opaque_types) ) ;
710+ let goal = self . try_strip_param_env ( goal) ;
608711 let typing_mode = self . typing_mode ( ) ;
609712 let step_kind = self . step_kind_for_source ( source) ;
610713
0 commit comments