@@ -18,14 +18,15 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
18
18
use rustc_hir:: RangeEnd ;
19
19
use rustc_index:: Idx ;
20
20
use rustc_middle:: mir:: interpret:: {
21
- ConstValue , ErrorHandled , LitToConstError , LitToConstInput , Scalar ,
21
+ ConstValue , ErrorHandled , GlobalId , LitToConstError , LitToConstInput , Scalar ,
22
22
} ;
23
- use rustc_middle:: mir:: { self , UserTypeProjection } ;
23
+ use rustc_middle:: mir:: { self , ConstantKind , UserTypeProjection } ;
24
24
use rustc_middle:: mir:: { BorrowKind , Mutability } ;
25
25
use rustc_middle:: thir:: { Ascription , BindingMode , FieldPat , LocalVarId , Pat , PatKind , PatRange } ;
26
26
use rustc_middle:: ty:: subst:: { GenericArg , SubstsRef } ;
27
27
use rustc_middle:: ty:: CanonicalUserTypeAnnotation ;
28
- use rustc_middle:: ty:: { self , AdtDef , ConstKind , Region , Ty , TyCtxt , UserType } ;
28
+ use rustc_middle:: ty:: TypeVisitableExt ;
29
+ use rustc_middle:: ty:: { self , AdtDef , Region , Ty , TyCtxt , UserType } ;
29
30
use rustc_span:: { Span , Symbol } ;
30
31
use rustc_target:: abi:: FieldIdx ;
31
32
@@ -518,16 +519,24 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
518
519
}
519
520
} ;
520
521
521
- // `mir_const_qualif` must be called with the `DefId` of the item where the const is
522
- // defined, not where it is declared. The difference is significant for associated
523
- // constants.
524
- let mir_structural_match_violation = self . tcx . mir_const_qualif ( instance. def_id ( ) ) . custom_eq ;
525
- debug ! ( "mir_structural_match_violation({:?}) -> {}" , qpath, mir_structural_match_violation) ;
526
-
527
- match self . tcx . const_eval_instance ( param_env_reveal_all, instance, Some ( span) ) {
528
- Ok ( literal) => {
529
- let const_ = mir:: ConstantKind :: Val ( literal, ty) ;
530
- let pattern = self . const_to_pat ( const_, id, span, mir_structural_match_violation) ;
522
+ let cid = GlobalId { instance, promoted : None } ;
523
+ // Prefer valtrees over opaque constants.
524
+ let const_value = self
525
+ . tcx
526
+ . const_eval_global_id_for_typeck ( param_env_reveal_all, cid, Some ( span) )
527
+ . map ( |val| match val {
528
+ Some ( valtree) => mir:: ConstantKind :: Ty ( self . tcx . mk_const ( valtree, ty) ) ,
529
+ None => mir:: ConstantKind :: Val (
530
+ self . tcx
531
+ . const_eval_global_id ( param_env_reveal_all, cid, Some ( span) )
532
+ . expect ( "const_eval_global_id_for_typeck should have already failed" ) ,
533
+ ty,
534
+ ) ,
535
+ } ) ;
536
+
537
+ match const_value {
538
+ Ok ( const_) => {
539
+ let pattern = self . const_to_pat ( const_, id, span, Some ( instance. def_id ( ) ) ) ;
531
540
532
541
if !is_associated_const {
533
542
return pattern;
@@ -577,27 +586,69 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
577
586
id : hir:: HirId ,
578
587
span : Span ,
579
588
) -> PatKind < ' tcx > {
580
- let value = mir:: ConstantKind :: from_inline_const ( self . tcx , anon_const. def_id ) ;
581
-
582
- // Evaluate early like we do in `lower_path`.
583
- let value = value. eval ( self . tcx , self . param_env ) ;
584
-
585
- match value {
586
- mir:: ConstantKind :: Ty ( c) => match c. kind ( ) {
587
- ConstKind :: Param ( _) => {
588
- self . tcx . sess . emit_err ( ConstParamInPattern { span } ) ;
589
- return PatKind :: Wild ;
590
- }
591
- ConstKind :: Error ( _) => {
592
- return PatKind :: Wild ;
589
+ let tcx = self . tcx ;
590
+ let def_id = anon_const. def_id ;
591
+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
592
+ let body_id = match tcx. hir ( ) . get ( hir_id) {
593
+ hir:: Node :: AnonConst ( ac) => ac. body ,
594
+ _ => span_bug ! (
595
+ tcx. def_span( def_id. to_def_id( ) ) ,
596
+ "from_inline_const can only process anonymous constants"
597
+ ) ,
598
+ } ;
599
+ let expr = & tcx. hir ( ) . body ( body_id) . value ;
600
+ let ty = tcx. typeck ( def_id) . node_type ( hir_id) ;
601
+
602
+ // Special case inline consts that are just literals. This is solely
603
+ // a performance optimization, as we could also just go through the regular
604
+ // const eval path below.
605
+ // FIXME: investigate the performance impact of removing this.
606
+ let lit_input = match expr. kind {
607
+ hir:: ExprKind :: Lit ( ref lit) => Some ( LitToConstInput { lit : & lit. node , ty, neg : false } ) ,
608
+ hir:: ExprKind :: Unary ( hir:: UnOp :: Neg , ref expr) => match expr. kind {
609
+ hir:: ExprKind :: Lit ( ref lit) => {
610
+ Some ( LitToConstInput { lit : & lit. node , ty, neg : true } )
593
611
}
594
- _ => bug ! ( "Expected ConstKind::Param" ) ,
612
+ _ => None ,
595
613
} ,
596
- mir:: ConstantKind :: Val ( _, _) => self . const_to_pat ( value, id, span, false ) . kind ,
597
- mir:: ConstantKind :: Unevaluated ( ..) => {
598
- // If we land here it means the const can't be evaluated because it's `TooGeneric`.
599
- self . tcx . sess . emit_err ( ConstPatternDependsOnGenericParameter { span } ) ;
600
- return PatKind :: Wild ;
614
+ _ => None ,
615
+ } ;
616
+ if let Some ( lit_input) = lit_input {
617
+ match tcx. at ( expr. span ) . lit_to_const ( lit_input) {
618
+ Ok ( c) => return self . const_to_pat ( ConstantKind :: Ty ( c) , id, span, None ) . kind ,
619
+ // If an error occurred, ignore that it's a literal
620
+ // and leave reporting the error up to const eval of
621
+ // the unevaluated constant below.
622
+ Err ( _) => { }
623
+ }
624
+ }
625
+
626
+ let typeck_root_def_id = tcx. typeck_root_def_id ( def_id. to_def_id ( ) ) ;
627
+ let parent_substs =
628
+ tcx. erase_regions ( ty:: InternalSubsts :: identity_for_item ( tcx, typeck_root_def_id) ) ;
629
+ let substs =
630
+ ty:: InlineConstSubsts :: new ( tcx, ty:: InlineConstSubstsParts { parent_substs, ty } )
631
+ . substs ;
632
+
633
+ let uneval = mir:: UnevaluatedConst { def : def_id. to_def_id ( ) , substs, promoted : None } ;
634
+ debug_assert ! ( !substs. has_free_regions( ) ) ;
635
+
636
+ let ct = ty:: UnevaluatedConst { def : def_id. to_def_id ( ) , substs : substs } ;
637
+ // First try using a valtree in order to destructure the constant into a pattern.
638
+ if let Ok ( Some ( valtree) ) =
639
+ self . tcx . const_eval_resolve_for_typeck ( self . param_env , ct, Some ( span) )
640
+ {
641
+ self . const_to_pat ( ConstantKind :: Ty ( self . tcx . mk_const ( valtree, ty) ) , id, span, None ) . kind
642
+ } else {
643
+ // If that fails, convert it to an opaque constant pattern.
644
+ match tcx. const_eval_resolve ( self . param_env , uneval, None ) {
645
+ Ok ( val) => self . const_to_pat ( mir:: ConstantKind :: Val ( val, ty) , id, span, None ) . kind ,
646
+ Err ( ErrorHandled :: TooGeneric ) => {
647
+ // If we land here it means the const can't be evaluated because it's `TooGeneric`.
648
+ self . tcx . sess . emit_err ( ConstPatternDependsOnGenericParameter { span } ) ;
649
+ PatKind :: Wild
650
+ }
651
+ Err ( ErrorHandled :: Reported ( _) ) => PatKind :: Wild ,
601
652
}
602
653
}
603
654
}
@@ -626,8 +677,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
626
677
627
678
let lit_input =
628
679
LitToConstInput { lit : & lit. node , ty : self . typeck_results . expr_ty ( expr) , neg } ;
629
- match self . tcx . at ( expr. span ) . lit_to_mir_constant ( lit_input) {
630
- Ok ( constant) => self . const_to_pat ( constant, expr. hir_id , lit. span , false ) . kind ,
680
+ match self . tcx . at ( expr. span ) . lit_to_const ( lit_input) {
681
+ Ok ( constant) => {
682
+ self . const_to_pat ( ConstantKind :: Ty ( constant) , expr. hir_id , lit. span , None ) . kind
683
+ }
631
684
Err ( LitToConstError :: Reported ( _) ) => PatKind :: Wild ,
632
685
Err ( LitToConstError :: TypeError ) => bug ! ( "lower_lit: had type error" ) ,
633
686
}
@@ -806,6 +859,9 @@ pub(crate) fn compare_const_vals<'tcx>(
806
859
mir:: ConstantKind :: Val ( ConstValue :: Scalar ( Scalar :: Int ( a) ) , _a_ty) ,
807
860
mir:: ConstantKind :: Val ( ConstValue :: Scalar ( Scalar :: Int ( b) ) , _b_ty) ,
808
861
) => return Some ( a. cmp ( & b) ) ,
862
+ ( mir:: ConstantKind :: Ty ( a) , mir:: ConstantKind :: Ty ( b) ) => {
863
+ return Some ( a. kind ( ) . cmp ( & b. kind ( ) ) ) ;
864
+ }
809
865
_ => { }
810
866
} ,
811
867
}
0 commit comments