1
1
use crate :: middle:: resolve_bound_vars as rbv;
2
- use crate :: mir:: interpret:: LitToConstInput ;
3
- use crate :: ty:: { self , InternalSubsts , ParamEnv , ParamEnvAnd , Ty , TyCtxt } ;
2
+ use crate :: mir:: interpret:: { AllocId , ConstValue , LitToConstInput , Scalar } ;
3
+ use crate :: ty:: { self , InternalSubsts , ParamEnv , ParamEnvAnd , Ty , TyCtxt , TypeVisitableExt } ;
4
4
use rustc_data_structures:: intern:: Interned ;
5
5
use rustc_error_messages:: MultiSpan ;
6
6
use rustc_hir as hir;
@@ -14,9 +14,13 @@ mod valtree;
14
14
15
15
pub use int:: * ;
16
16
pub use kind:: * ;
17
+ use rustc_span:: ErrorGuaranteed ;
17
18
use rustc_span:: DUMMY_SP ;
19
+ use rustc_target:: abi:: Size ;
18
20
pub use valtree:: * ;
19
21
22
+ use super :: sty:: ConstKind ;
23
+
20
24
/// Use this rather than `ConstData`, whenever possible.
21
25
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , HashStable ) ]
22
26
#[ rustc_pass_by_value]
@@ -32,6 +36,16 @@ pub struct ConstData<'tcx> {
32
36
#[ cfg( all( target_arch = "x86_64" , target_pointer_width = "64" ) ) ]
33
37
static_assert_size ! ( ConstData <' _>, 40 ) ;
34
38
39
+ enum EvalMode {
40
+ Typeck ,
41
+ Mir ,
42
+ }
43
+
44
+ enum EvalResult < ' tcx > {
45
+ ValTree ( ty:: ValTree < ' tcx > ) ,
46
+ ConstVal ( ConstValue < ' tcx > ) ,
47
+ }
48
+
35
49
impl < ' tcx > Const < ' tcx > {
36
50
#[ inline]
37
51
pub fn ty ( self ) -> Ty < ' tcx > {
@@ -40,7 +54,7 @@ impl<'tcx> Const<'tcx> {
40
54
41
55
#[ inline]
42
56
pub fn kind ( self ) -> ConstKind < ' tcx > {
43
- self . 0 . kind
57
+ self . 0 . kind . clone ( )
44
58
}
45
59
46
60
#[ inline]
@@ -293,12 +307,12 @@ impl<'tcx> Const<'tcx> {
293
307
assert_eq ! ( self . ty( ) , ty) ;
294
308
let size = tcx. layout_of ( param_env. with_reveal_all_normalized ( tcx) . and ( ty) ) . ok ( ) ?. size ;
295
309
// if `ty` does not depend on generic parameters, use an empty param_env
296
- self . kind ( ) . eval ( tcx, param_env) . try_to_bits ( size)
310
+ self . eval ( tcx, param_env) . try_to_bits ( size)
297
311
}
298
312
299
313
#[ inline]
300
314
pub fn try_eval_bool ( self , tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > ) -> Option < bool > {
301
- self . kind ( ) . eval ( tcx, param_env) . try_to_bool ( )
315
+ self . eval ( tcx, param_env) . try_to_bool ( )
302
316
}
303
317
304
318
#[ inline]
@@ -307,14 +321,14 @@ impl<'tcx> Const<'tcx> {
307
321
tcx : TyCtxt < ' tcx > ,
308
322
param_env : ParamEnv < ' tcx > ,
309
323
) -> Option < u64 > {
310
- self . kind ( ) . eval ( tcx, param_env) . try_to_target_usize ( tcx)
324
+ self . eval ( tcx, param_env) . try_to_target_usize ( tcx)
311
325
}
312
326
313
327
#[ inline]
314
328
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
315
329
/// unevaluated constant.
316
330
pub fn eval ( self , tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > ) -> Const < ' tcx > {
317
- if let Some ( val) = self . kind ( ) . try_eval_for_typeck ( tcx, param_env) {
331
+ if let Some ( val) = self . try_eval_for_typeck ( tcx, param_env) {
318
332
match val {
319
333
Ok ( val) => ty:: Const :: new_value ( tcx, val, self . ty ( ) ) ,
320
334
Err ( guar) => ty:: Const :: new_error ( tcx, guar, self . ty ( ) ) ,
@@ -339,6 +353,138 @@ impl<'tcx> Const<'tcx> {
339
353
. unwrap_or_else ( || bug ! ( "expected usize, got {:#?}" , self ) )
340
354
}
341
355
356
+ #[ inline]
357
+ /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
358
+ /// return `None`.
359
+ // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
360
+ pub fn try_eval_for_mir (
361
+ self ,
362
+ tcx : TyCtxt < ' tcx > ,
363
+ param_env : ParamEnv < ' tcx > ,
364
+ ) -> Option < Result < ConstValue < ' tcx > , ErrorGuaranteed > > {
365
+ match self . try_eval_inner ( tcx, param_env, EvalMode :: Mir ) {
366
+ Some ( Ok ( EvalResult :: ValTree ( _) ) ) => unreachable ! ( ) ,
367
+ Some ( Ok ( EvalResult :: ConstVal ( v) ) ) => Some ( Ok ( v) ) ,
368
+ Some ( Err ( e) ) => Some ( Err ( e) ) ,
369
+ None => None ,
370
+ }
371
+ }
372
+
373
+ #[ inline]
374
+ /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
375
+ /// return `None`.
376
+ // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
377
+ pub fn try_eval_for_typeck (
378
+ self ,
379
+ tcx : TyCtxt < ' tcx > ,
380
+ param_env : ParamEnv < ' tcx > ,
381
+ ) -> Option < Result < ty:: ValTree < ' tcx > , ErrorGuaranteed > > {
382
+ match self . try_eval_inner ( tcx, param_env, EvalMode :: Typeck ) {
383
+ Some ( Ok ( EvalResult :: ValTree ( v) ) ) => Some ( Ok ( v) ) ,
384
+ Some ( Ok ( EvalResult :: ConstVal ( _) ) ) => unreachable ! ( ) ,
385
+ Some ( Err ( e) ) => Some ( Err ( e) ) ,
386
+ None => None ,
387
+ }
388
+ }
389
+
390
+ #[ inline]
391
+ fn try_eval_inner (
392
+ self ,
393
+ tcx : TyCtxt < ' tcx > ,
394
+ param_env : ParamEnv < ' tcx > ,
395
+ eval_mode : EvalMode ,
396
+ ) -> Option < Result < EvalResult < ' tcx > , ErrorGuaranteed > > {
397
+ assert ! ( !self . has_escaping_bound_vars( ) , "escaping vars in {self:?}" ) ;
398
+ if let ConstKind :: Unevaluated ( unevaluated) = self . kind ( ) {
399
+ use crate :: mir:: interpret:: ErrorHandled ;
400
+
401
+ // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
402
+ // also does later, but we want to do it before checking for
403
+ // inference variables.
404
+ // Note that we erase regions *before* calling `with_reveal_all_normalized`,
405
+ // so that we don't try to invoke this query with
406
+ // any region variables.
407
+
408
+ // HACK(eddyb) when the query key would contain inference variables,
409
+ // attempt using identity substs and `ParamEnv` instead, that will succeed
410
+ // when the expression doesn't depend on any parameters.
411
+ // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
412
+ // we can call `infcx.const_eval_resolve` which handles inference variables.
413
+ let param_env_and = if ( param_env, unevaluated) . has_non_region_infer ( ) {
414
+ tcx. param_env ( unevaluated. def ) . and ( ty:: UnevaluatedConst {
415
+ def : unevaluated. def ,
416
+ substs : InternalSubsts :: identity_for_item ( tcx, unevaluated. def ) ,
417
+ } )
418
+ } else {
419
+ tcx. erase_regions ( param_env)
420
+ . with_reveal_all_normalized ( tcx)
421
+ . and ( tcx. erase_regions ( unevaluated) )
422
+ } ;
423
+
424
+ // FIXME(eddyb) maybe the `const_eval_*` methods should take
425
+ // `ty::ParamEnvAnd` instead of having them separate.
426
+ let ( param_env, unevaluated) = param_env_and. into_parts ( ) ;
427
+ // try to resolve e.g. associated constants to their definition on an impl, and then
428
+ // evaluate the const.
429
+ match eval_mode {
430
+ EvalMode :: Typeck => {
431
+ match tcx. const_eval_resolve_for_typeck ( param_env, unevaluated, None ) {
432
+ // NOTE(eddyb) `val` contains no lifetimes/types/consts,
433
+ // and we use the original type, so nothing from `substs`
434
+ // (which may be identity substs, see above),
435
+ // can leak through `val` into the const we return.
436
+ Ok ( val) => Some ( Ok ( EvalResult :: ValTree ( val?) ) ) ,
437
+ Err ( ErrorHandled :: TooGeneric ) => None ,
438
+ Err ( ErrorHandled :: Reported ( e) ) => Some ( Err ( e. into ( ) ) ) ,
439
+ }
440
+ }
441
+ EvalMode :: Mir => {
442
+ match tcx. const_eval_resolve ( param_env, unevaluated. expand ( ) , None ) {
443
+ // NOTE(eddyb) `val` contains no lifetimes/types/consts,
444
+ // and we use the original type, so nothing from `substs`
445
+ // (which may be identity substs, see above),
446
+ // can leak through `val` into the const we return.
447
+ Ok ( val) => Some ( Ok ( EvalResult :: ConstVal ( val) ) ) ,
448
+ Err ( ErrorHandled :: TooGeneric ) => None ,
449
+ Err ( ErrorHandled :: Reported ( e) ) => Some ( Err ( e. into ( ) ) ) ,
450
+ }
451
+ }
452
+ }
453
+ } else {
454
+ None
455
+ }
456
+ }
457
+
458
+ #[ inline]
459
+ pub fn try_to_value ( self ) -> Option < ty:: ValTree < ' tcx > > {
460
+ if let ConstKind :: Value ( val) = self . kind ( ) { Some ( val) } else { None }
461
+ }
462
+
463
+ #[ inline]
464
+ pub fn try_to_scalar ( self ) -> Option < Scalar < AllocId > > {
465
+ self . try_to_value ( ) ?. try_to_scalar ( )
466
+ }
467
+
468
+ #[ inline]
469
+ pub fn try_to_scalar_int ( self ) -> Option < ScalarInt > {
470
+ self . try_to_value ( ) ?. try_to_scalar_int ( )
471
+ }
472
+
473
+ #[ inline]
474
+ pub fn try_to_bits ( self , size : Size ) -> Option < u128 > {
475
+ self . try_to_scalar_int ( ) ?. to_bits ( size) . ok ( )
476
+ }
477
+
478
+ #[ inline]
479
+ pub fn try_to_bool ( self ) -> Option < bool > {
480
+ self . try_to_scalar_int ( ) ?. try_into ( ) . ok ( )
481
+ }
482
+
483
+ #[ inline]
484
+ pub fn try_to_target_usize ( self , tcx : TyCtxt < ' tcx > ) -> Option < u64 > {
485
+ self . try_to_value ( ) ?. try_to_target_usize ( tcx)
486
+ }
487
+
342
488
pub fn is_ct_infer ( self ) -> bool {
343
489
matches ! ( self . kind( ) , ty:: ConstKind :: Infer ( _) )
344
490
}
0 commit comments