11//! A subset of a mir body used for const evaluatability checking.
22use crate :: mir;
3+ use crate :: ty:: visit:: TypeVisitable ;
34use crate :: ty:: { self , subst:: Subst , DelaySpanBugEmitted , EarlyBinder , SubstsRef , Ty , TyCtxt } ;
45use rustc_errors:: ErrorGuaranteed ;
5- use std:: iter;
6+ use rustc_hir:: def_id:: DefId ;
7+ use std:: cmp;
68use std:: ops:: ControlFlow ;
79
810rustc_index:: newtype_index! {
@@ -63,6 +65,31 @@ impl<'tcx> AbstractConst<'tcx> {
6365 Node :: Binop ( _, _, _) | Node :: UnaryOp ( _, _) | Node :: FunctionCall ( _, _) => node,
6466 }
6567 }
68+
69+ pub fn unify_failure_kind ( self , tcx : TyCtxt < ' tcx > ) -> FailureKind {
70+ let mut failure_kind = FailureKind :: Concrete ;
71+ walk_abstract_const :: < !, _ > ( tcx, self , |node| {
72+ match node. root ( tcx) {
73+ Node :: Leaf ( leaf) => {
74+ if leaf. has_infer_types_or_consts ( ) {
75+ failure_kind = FailureKind :: MentionsInfer ;
76+ } else if leaf. has_param_types_or_consts ( ) {
77+ failure_kind = cmp:: min ( failure_kind, FailureKind :: MentionsParam ) ;
78+ }
79+ }
80+ Node :: Cast ( _, _, ty) => {
81+ if ty. has_infer_types_or_consts ( ) {
82+ failure_kind = FailureKind :: MentionsInfer ;
83+ } else if ty. has_param_types_or_consts ( ) {
84+ failure_kind = cmp:: min ( failure_kind, FailureKind :: MentionsParam ) ;
85+ }
86+ }
87+ Node :: Binop ( _, _, _) | Node :: UnaryOp ( _, _) | Node :: FunctionCall ( _, _) => { }
88+ }
89+ ControlFlow :: CONTINUE
90+ } ) ;
91+ failure_kind
92+ }
6693}
6794
6895#[ derive( Debug , Clone , Copy , PartialEq , Eq , HashStable , TyEncodable , TyDecodable ) ]
@@ -104,7 +131,7 @@ impl<'tcx> TyCtxt<'tcx> {
104131 #[ inline]
105132 pub fn thir_abstract_const_opt_const_arg (
106133 self ,
107- def : ty:: WithOptConstParam < rustc_hir :: def_id :: DefId > ,
134+ def : ty:: WithOptConstParam < DefId > ,
108135 ) -> Result < Option < & ' tcx [ Node < ' tcx > ] > , ErrorGuaranteed > {
109136 if let Some ( ( did, param_did) ) = def. as_const_arg ( ) {
110137 self . thir_abstract_const_of_const_arg ( ( did, param_did) )
@@ -114,28 +141,6 @@ impl<'tcx> TyCtxt<'tcx> {
114141 }
115142}
116143
117- #[ instrument( skip( tcx) , level = "debug" ) ]
118- pub fn try_unify_abstract_consts < ' tcx > (
119- tcx : TyCtxt < ' tcx > ,
120- ( a, b) : ( ty:: Unevaluated < ' tcx , ( ) > , ty:: Unevaluated < ' tcx , ( ) > ) ,
121- param_env : ty:: ParamEnv < ' tcx > ,
122- ) -> bool {
123- ( || {
124- if let Some ( a) = AbstractConst :: new ( tcx, a) ? {
125- if let Some ( b) = AbstractConst :: new ( tcx, b) ? {
126- let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env } ;
127- return Ok ( const_unify_ctxt. try_unify ( a, b) ) ;
128- }
129- }
130-
131- Ok ( false )
132- } ) ( )
133- . unwrap_or_else ( |_: ErrorGuaranteed | true )
134- // FIXME(generic_const_exprs): We should instead have this
135- // method return the resulting `ty::Const` and return `ConstKind::Error`
136- // on `ErrorGuaranteed`.
137- }
138-
139144#[ instrument( skip( tcx, f) , level = "debug" ) ]
140145pub fn walk_abstract_const < ' tcx , R , F > (
141146 tcx : TyCtxt < ' tcx > ,
@@ -172,119 +177,6 @@ where
172177 recurse ( tcx, ct, & mut f)
173178}
174179
175- pub struct ConstUnifyCtxt < ' tcx > {
176- pub tcx : TyCtxt < ' tcx > ,
177- pub param_env : ty:: ParamEnv < ' tcx > ,
178- }
179-
180- impl < ' tcx > ConstUnifyCtxt < ' tcx > {
181- // Substitutes generics repeatedly to allow AbstractConsts to unify where a
182- // ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g.
183- // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
184- #[ inline]
185- #[ instrument( skip( self ) , level = "debug" ) ]
186- fn try_replace_substs_in_root (
187- & self ,
188- mut abstr_const : AbstractConst < ' tcx > ,
189- ) -> Option < AbstractConst < ' tcx > > {
190- while let Node :: Leaf ( ct) = abstr_const. root ( self . tcx ) {
191- match AbstractConst :: from_const ( self . tcx , ct) {
192- Ok ( Some ( act) ) => abstr_const = act,
193- Ok ( None ) => break ,
194- Err ( _) => return None ,
195- }
196- }
197-
198- Some ( abstr_const)
199- }
200-
201- /// Tries to unify two abstract constants using structural equality.
202- #[ instrument( skip( self ) , level = "debug" ) ]
203- pub fn try_unify ( & self , a : AbstractConst < ' tcx > , b : AbstractConst < ' tcx > ) -> bool {
204- let a = if let Some ( a) = self . try_replace_substs_in_root ( a) {
205- a
206- } else {
207- return true ;
208- } ;
209-
210- let b = if let Some ( b) = self . try_replace_substs_in_root ( b) {
211- b
212- } else {
213- return true ;
214- } ;
215-
216- let a_root = a. root ( self . tcx ) ;
217- let b_root = b. root ( self . tcx ) ;
218- debug ! ( ?a_root, ?b_root) ;
219-
220- match ( a_root, b_root) {
221- ( Node :: Leaf ( a_ct) , Node :: Leaf ( b_ct) ) => {
222- let a_ct = a_ct. eval ( self . tcx , self . param_env ) ;
223- debug ! ( "a_ct evaluated: {:?}" , a_ct) ;
224- let b_ct = b_ct. eval ( self . tcx , self . param_env ) ;
225- debug ! ( "b_ct evaluated: {:?}" , b_ct) ;
226-
227- if a_ct. ty ( ) != b_ct. ty ( ) {
228- return false ;
229- }
230-
231- match ( a_ct. kind ( ) , b_ct. kind ( ) ) {
232- // We can just unify errors with everything to reduce the amount of
233- // emitted errors here.
234- ( ty:: ConstKind :: Error ( _) , _) | ( _, ty:: ConstKind :: Error ( _) ) => true ,
235- ( ty:: ConstKind :: Param ( a_param) , ty:: ConstKind :: Param ( b_param) ) => {
236- a_param == b_param
237- }
238- ( ty:: ConstKind :: Value ( a_val) , ty:: ConstKind :: Value ( b_val) ) => a_val == b_val,
239- // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
240- // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
241- // means that we only allow inference variables if they are equal.
242- ( ty:: ConstKind :: Infer ( a_val) , ty:: ConstKind :: Infer ( b_val) ) => a_val == b_val,
243- // We expand generic anonymous constants at the start of this function, so this
244- // branch should only be taking when dealing with associated constants, at
245- // which point directly comparing them seems like the desired behavior.
246- //
247- // FIXME(generic_const_exprs): This isn't actually the case.
248- // We also take this branch for concrete anonymous constants and
249- // expand generic anonymous constants with concrete substs.
250- ( ty:: ConstKind :: Unevaluated ( a_uv) , ty:: ConstKind :: Unevaluated ( b_uv) ) => {
251- a_uv == b_uv
252- }
253- // FIXME(generic_const_exprs): We may want to either actually try
254- // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
255- // this, for now we just return false here.
256- _ => false ,
257- }
258- }
259- ( Node :: Binop ( a_op, al, ar) , Node :: Binop ( b_op, bl, br) ) if a_op == b_op => {
260- self . try_unify ( a. subtree ( al) , b. subtree ( bl) )
261- && self . try_unify ( a. subtree ( ar) , b. subtree ( br) )
262- }
263- ( Node :: UnaryOp ( a_op, av) , Node :: UnaryOp ( b_op, bv) ) if a_op == b_op => {
264- self . try_unify ( a. subtree ( av) , b. subtree ( bv) )
265- }
266- ( Node :: FunctionCall ( a_f, a_args) , Node :: FunctionCall ( b_f, b_args) )
267- if a_args. len ( ) == b_args. len ( ) =>
268- {
269- self . try_unify ( a. subtree ( a_f) , b. subtree ( b_f) )
270- && iter:: zip ( a_args, b_args)
271- . all ( |( & an, & bn) | self . try_unify ( a. subtree ( an) , b. subtree ( bn) ) )
272- }
273- ( Node :: Cast ( a_kind, a_operand, a_ty) , Node :: Cast ( b_kind, b_operand, b_ty) )
274- if ( a_ty == b_ty) && ( a_kind == b_kind) =>
275- {
276- self . try_unify ( a. subtree ( a_operand) , b. subtree ( b_operand) )
277- }
278- // use this over `_ => false` to make adding variants to `Node` less error prone
279- ( Node :: Cast ( ..) , _)
280- | ( Node :: FunctionCall ( ..) , _)
281- | ( Node :: UnaryOp ( ..) , _)
282- | ( Node :: Binop ( ..) , _)
283- | ( Node :: Leaf ( ..) , _) => false ,
284- }
285- }
286- }
287-
288180// We were unable to unify the abstract constant with
289181// a constant found in the caller bounds, there are
290182// now three possible cases here.
0 commit comments