1
1
//! A subset of a mir body used for const evaluatability checking.
2
2
use crate :: mir;
3
+ use crate :: ty:: visit:: TypeVisitable ;
3
4
use crate :: ty:: { self , subst:: Subst , DelaySpanBugEmitted , EarlyBinder , SubstsRef , Ty , TyCtxt } ;
4
5
use rustc_errors:: ErrorGuaranteed ;
5
- use std:: iter;
6
+ use rustc_hir:: def_id:: DefId ;
7
+ use std:: cmp;
6
8
use std:: ops:: ControlFlow ;
7
9
8
10
rustc_index:: newtype_index! {
@@ -63,6 +65,31 @@ impl<'tcx> AbstractConst<'tcx> {
63
65
Node :: Binop ( _, _, _) | Node :: UnaryOp ( _, _) | Node :: FunctionCall ( _, _) => node,
64
66
}
65
67
}
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
+ }
66
93
}
67
94
68
95
#[ derive( Debug , Clone , Copy , PartialEq , Eq , HashStable , TyEncodable , TyDecodable ) ]
@@ -104,7 +131,7 @@ impl<'tcx> TyCtxt<'tcx> {
104
131
#[ inline]
105
132
pub fn thir_abstract_const_opt_const_arg (
106
133
self ,
107
- def : ty:: WithOptConstParam < rustc_hir :: def_id :: DefId > ,
134
+ def : ty:: WithOptConstParam < DefId > ,
108
135
) -> Result < Option < & ' tcx [ Node < ' tcx > ] > , ErrorGuaranteed > {
109
136
if let Some ( ( did, param_did) ) = def. as_const_arg ( ) {
110
137
self . thir_abstract_const_of_const_arg ( ( did, param_did) )
@@ -114,28 +141,6 @@ impl<'tcx> TyCtxt<'tcx> {
114
141
}
115
142
}
116
143
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
-
139
144
#[ instrument( skip( tcx, f) , level = "debug" ) ]
140
145
pub fn walk_abstract_const < ' tcx , R , F > (
141
146
tcx : TyCtxt < ' tcx > ,
@@ -172,119 +177,6 @@ where
172
177
recurse ( tcx, ct, & mut f)
173
178
}
174
179
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
-
288
180
// We were unable to unify the abstract constant with
289
181
// a constant found in the caller bounds, there are
290
182
// now three possible cases here.
0 commit comments