@@ -25,7 +25,8 @@ 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
@@ -585,43 +586,71 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
585
586
id : hir:: HirId ,
586
587
span : Span ,
587
588
) -> PatKind < ' tcx > {
588
- let value = mir:: ConstantKind :: from_inline_const ( self . tcx , anon_const. def_id ) ;
589
- let value = match value {
590
- mir:: ConstantKind :: Ty ( _) => value,
591
- // Evaluate early like we do in `lower_path`.
592
- mir:: ConstantKind :: Unevaluated ( ct, ty) => {
593
- let ct = ty:: UnevaluatedConst { def : ct. def , substs : ct. substs } ;
594
- if let Ok ( Some ( valtree) ) =
595
- self . tcx . const_eval_resolve_for_typeck ( self . param_env , ct, Some ( span) )
596
- {
597
- mir:: ConstantKind :: Ty ( self . tcx . mk_const ( valtree, ty) )
598
- } else {
599
- value. eval ( self . tcx , self . param_env )
600
- }
601
- }
602
- mir:: ConstantKind :: Val ( _, _) => unreachable ! ( ) ,
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
+ ) ,
603
598
} ;
604
-
605
- match value {
606
- mir:: ConstantKind :: Ty ( c) => match c. kind ( ) {
607
- ConstKind :: Param ( _) => {
608
- self . tcx . sess . emit_err ( ConstParamInPattern { span } ) ;
609
- return PatKind :: Wild ;
610
- }
611
- ConstKind :: Error ( _) => {
612
- return PatKind :: Wild ;
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 } )
613
611
}
614
- _ => { }
612
+ _ => None ,
615
613
} ,
616
- mir:: ConstantKind :: Val ( _, _) => { }
617
- mir:: ConstantKind :: Unevaluated ( ..) => {
618
- // If we land here it means the const can't be evaluated because it's `TooGeneric`.
619
- self . tcx . sess . emit_err ( ConstPatternDependsOnGenericParameter { span } ) ;
620
- 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 ( _) => { }
621
623
}
622
624
}
623
625
624
- self . const_to_pat ( value, id, span, None ) . kind
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 ,
652
+ }
653
+ }
625
654
}
626
655
627
656
/// Converts literals, paths and negation of literals to patterns.
0 commit comments