@@ -188,6 +188,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
188188 }
189189}
190190
191+ #[ instrument( skip( tcx) , level = "debug" ) ]
191192fn satisfied_from_param_env < ' tcx > (
192193 tcx : TyCtxt < ' tcx > ,
193194 ct : AbstractConst < ' tcx > ,
@@ -197,14 +198,17 @@ fn satisfied_from_param_env<'tcx>(
197198 match pred. kind ( ) . skip_binder ( ) {
198199 ty:: PredicateKind :: ConstEvaluatable ( uv) => {
199200 if let Some ( b_ct) = AbstractConst :: new ( tcx, uv) ? {
201+ let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env } ;
202+
200203 // Try to unify with each subtree in the AbstractConst to allow for
201204 // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
202205 // predicate for `(N + 1) * 2`
203- let result =
204- walk_abstract_const ( tcx , b_ct , |b_ct| match try_unify ( tcx , ct, b_ct) {
206+ let result = walk_abstract_const ( tcx , b_ct , |b_ct| {
207+ match const_unify_ctxt . try_unify ( ct, b_ct) {
205208 true => ControlFlow :: BREAK ,
206209 false => ControlFlow :: CONTINUE ,
207- } ) ;
210+ }
211+ } ) ;
208212
209213 if let ControlFlow :: Break ( ( ) ) = result {
210214 debug ! ( "is_const_evaluatable: abstract_const ~~> ok" ) ;
@@ -637,11 +641,13 @@ pub(super) fn thir_abstract_const<'tcx>(
637641pub ( super ) fn try_unify_abstract_consts < ' tcx > (
638642 tcx : TyCtxt < ' tcx > ,
639643 ( a, b) : ( ty:: Unevaluated < ' tcx , ( ) > , ty:: Unevaluated < ' tcx , ( ) > ) ,
644+ param_env : ty:: ParamEnv < ' tcx > ,
640645) -> bool {
641646 ( || {
642647 if let Some ( a) = AbstractConst :: new ( tcx, a) ? {
643648 if let Some ( b) = AbstractConst :: new ( tcx, b) ? {
644- return Ok ( try_unify ( tcx, a, b) ) ;
649+ let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env } ;
650+ return Ok ( const_unify_ctxt. try_unify ( a, b) ) ;
645651 }
646652 }
647653
@@ -689,88 +695,115 @@ where
689695 recurse ( tcx, ct, & mut f)
690696}
691697
692- /// Tries to unify two abstract constants using structural equality.
693- pub ( super ) fn try_unify < ' tcx > (
698+ struct ConstUnifyCtxt < ' tcx > {
694699 tcx : TyCtxt < ' tcx > ,
695- mut a : AbstractConst < ' tcx > ,
696- mut b : AbstractConst < ' tcx > ,
697- ) -> bool {
698- // We substitute generics repeatedly to allow AbstractConsts to unify where a
700+ param_env : ty:: ParamEnv < ' tcx > ,
701+ }
702+
703+ impl < ' tcx > ConstUnifyCtxt < ' tcx > {
704+ // Substitutes generics repeatedly to allow AbstractConsts to unify where a
699705 // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
700706 // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
701- while let Node :: Leaf ( a_ct ) = a . root ( tcx ) {
702- match AbstractConst :: from_const ( tcx , a_ct ) {
703- Ok ( Some ( a_act ) ) => a = a_act ,
704- Ok ( None ) => break ,
705- Err ( _ ) => return true ,
706- }
707- }
708- while let Node :: Leaf ( b_ct ) = b . root ( tcx) {
709- match AbstractConst :: from_const ( tcx , b_ct ) {
710- Ok ( Some ( b_act ) ) => b = b_act ,
711- Ok ( None ) => break ,
712- Err ( _ ) => return true ,
707+ # [ inline ]
708+ # [ instrument ( skip ( self ) , level = "debug" ) ]
709+ fn try_replace_substs_in_root (
710+ & self ,
711+ mut abstr_const : AbstractConst < ' tcx > ,
712+ ) -> Option < AbstractConst < ' tcx > > {
713+ while let Node :: Leaf ( ct ) = abstr_const . root ( self . tcx ) {
714+ match AbstractConst :: from_const ( self . tcx , ct ) {
715+ Ok ( Some ( act ) ) => abstr_const = act ,
716+ Ok ( None ) => break ,
717+ Err ( _ ) => return None ,
718+ }
713719 }
714- }
715720
716- match ( a. root ( tcx) , b. root ( tcx) ) {
717- ( Node :: Leaf ( a_ct) , Node :: Leaf ( b_ct) ) => {
718- if a_ct. ty ( ) != b_ct. ty ( ) {
719- return false ;
720- }
721+ Some ( abstr_const)
722+ }
721723
722- match ( a_ct. val ( ) , b_ct. val ( ) ) {
723- // We can just unify errors with everything to reduce the amount of
724- // emitted errors here.
725- ( ty:: ConstKind :: Error ( _) , _) | ( _, ty:: ConstKind :: Error ( _) ) => true ,
726- ( ty:: ConstKind :: Param ( a_param) , ty:: ConstKind :: Param ( b_param) ) => {
727- a_param == b_param
724+ /// Tries to unify two abstract constants using structural equality.
725+ #[ instrument( skip( self ) , level = "debug" ) ]
726+ fn try_unify ( & self , a : AbstractConst < ' tcx > , b : AbstractConst < ' tcx > ) -> bool {
727+ let a = if let Some ( a) = self . try_replace_substs_in_root ( a) {
728+ a
729+ } else {
730+ return true ;
731+ } ;
732+
733+ let b = if let Some ( b) = self . try_replace_substs_in_root ( b) {
734+ b
735+ } else {
736+ return true ;
737+ } ;
738+
739+ let a_root = a. root ( self . tcx ) ;
740+ let b_root = b. root ( self . tcx ) ;
741+ debug ! ( ?a_root, ?b_root) ;
742+
743+ match ( a_root, b_root) {
744+ ( Node :: Leaf ( a_ct) , Node :: Leaf ( b_ct) ) => {
745+ let a_ct = a_ct. eval ( self . tcx , self . param_env ) ;
746+ debug ! ( "a_ct evaluated: {:?}" , a_ct) ;
747+ let b_ct = b_ct. eval ( self . tcx , self . param_env ) ;
748+ debug ! ( "b_ct evaluated: {:?}" , b_ct) ;
749+
750+ if a_ct. ty ( ) != b_ct. ty ( ) {
751+ return false ;
728752 }
729- ( ty:: ConstKind :: Value ( a_val) , ty:: ConstKind :: Value ( b_val) ) => a_val == b_val,
730- // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
731- // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
732- // means that we only allow inference variables if they are equal.
733- ( ty:: ConstKind :: Infer ( a_val) , ty:: ConstKind :: Infer ( b_val) ) => a_val == b_val,
734- // We expand generic anonymous constants at the start of this function, so this
735- // branch should only be taking when dealing with associated constants, at
736- // which point directly comparing them seems like the desired behavior.
737- //
738- // FIXME(generic_const_exprs): This isn't actually the case.
739- // We also take this branch for concrete anonymous constants and
740- // expand generic anonymous constants with concrete substs.
741- ( ty:: ConstKind :: Unevaluated ( a_uv) , ty:: ConstKind :: Unevaluated ( b_uv) ) => {
742- a_uv == b_uv
753+
754+ match ( a_ct. val ( ) , b_ct. val ( ) ) {
755+ // We can just unify errors with everything to reduce the amount of
756+ // emitted errors here.
757+ ( ty:: ConstKind :: Error ( _) , _) | ( _, ty:: ConstKind :: Error ( _) ) => true ,
758+ ( ty:: ConstKind :: Param ( a_param) , ty:: ConstKind :: Param ( b_param) ) => {
759+ a_param == b_param
760+ }
761+ ( ty:: ConstKind :: Value ( a_val) , ty:: ConstKind :: Value ( b_val) ) => a_val == b_val,
762+ // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
763+ // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
764+ // means that we only allow inference variables if they are equal.
765+ ( ty:: ConstKind :: Infer ( a_val) , ty:: ConstKind :: Infer ( b_val) ) => a_val == b_val,
766+ // We expand generic anonymous constants at the start of this function, so this
767+ // branch should only be taking when dealing with associated constants, at
768+ // which point directly comparing them seems like the desired behavior.
769+ //
770+ // FIXME(generic_const_exprs): This isn't actually the case.
771+ // We also take this branch for concrete anonymous constants and
772+ // expand generic anonymous constants with concrete substs.
773+ ( ty:: ConstKind :: Unevaluated ( a_uv) , ty:: ConstKind :: Unevaluated ( b_uv) ) => {
774+ a_uv == b_uv
775+ }
776+ // FIXME(generic_const_exprs): We may want to either actually try
777+ // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
778+ // this, for now we just return false here.
779+ _ => false ,
743780 }
744- // FIXME(generic_const_exprs): We may want to either actually try
745- // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
746- // this, for now we just return false here.
747- _ => false ,
748781 }
782+ ( Node :: Binop ( a_op, al, ar) , Node :: Binop ( b_op, bl, br) ) if a_op == b_op => {
783+ self . try_unify ( a. subtree ( al) , b. subtree ( bl) )
784+ && self . try_unify ( a. subtree ( ar) , b. subtree ( br) )
785+ }
786+ ( Node :: UnaryOp ( a_op, av) , Node :: UnaryOp ( b_op, bv) ) if a_op == b_op => {
787+ self . try_unify ( a. subtree ( av) , b. subtree ( bv) )
788+ }
789+ ( Node :: FunctionCall ( a_f, a_args) , Node :: FunctionCall ( b_f, b_args) )
790+ if a_args. len ( ) == b_args. len ( ) =>
791+ {
792+ self . try_unify ( a. subtree ( a_f) , b. subtree ( b_f) )
793+ && iter:: zip ( a_args, b_args)
794+ . all ( |( & an, & bn) | self . try_unify ( a. subtree ( an) , b. subtree ( bn) ) )
795+ }
796+ ( Node :: Cast ( a_kind, a_operand, a_ty) , Node :: Cast ( b_kind, b_operand, b_ty) )
797+ if ( a_ty == b_ty) && ( a_kind == b_kind) =>
798+ {
799+ self . try_unify ( a. subtree ( a_operand) , b. subtree ( b_operand) )
800+ }
801+ // use this over `_ => false` to make adding variants to `Node` less error prone
802+ ( Node :: Cast ( ..) , _)
803+ | ( Node :: FunctionCall ( ..) , _)
804+ | ( Node :: UnaryOp ( ..) , _)
805+ | ( Node :: Binop ( ..) , _)
806+ | ( Node :: Leaf ( ..) , _) => false ,
749807 }
750- ( Node :: Binop ( a_op, al, ar) , Node :: Binop ( b_op, bl, br) ) if a_op == b_op => {
751- try_unify ( tcx, a. subtree ( al) , b. subtree ( bl) )
752- && try_unify ( tcx, a. subtree ( ar) , b. subtree ( br) )
753- }
754- ( Node :: UnaryOp ( a_op, av) , Node :: UnaryOp ( b_op, bv) ) if a_op == b_op => {
755- try_unify ( tcx, a. subtree ( av) , b. subtree ( bv) )
756- }
757- ( Node :: FunctionCall ( a_f, a_args) , Node :: FunctionCall ( b_f, b_args) )
758- if a_args. len ( ) == b_args. len ( ) =>
759- {
760- try_unify ( tcx, a. subtree ( a_f) , b. subtree ( b_f) )
761- && iter:: zip ( a_args, b_args)
762- . all ( |( & an, & bn) | try_unify ( tcx, a. subtree ( an) , b. subtree ( bn) ) )
763- }
764- ( Node :: Cast ( a_kind, a_operand, a_ty) , Node :: Cast ( b_kind, b_operand, b_ty) )
765- if ( a_ty == b_ty) && ( a_kind == b_kind) =>
766- {
767- try_unify ( tcx, a. subtree ( a_operand) , b. subtree ( b_operand) )
768- }
769- // use this over `_ => false` to make adding variants to `Node` less error prone
770- ( Node :: Cast ( ..) , _)
771- | ( Node :: FunctionCall ( ..) , _)
772- | ( Node :: UnaryOp ( ..) , _)
773- | ( Node :: Binop ( ..) , _)
774- | ( Node :: Leaf ( ..) , _) => false ,
775808 }
776809}
0 commit comments