@@ -25,7 +25,8 @@ use rustc_middle::mir::{BorrowKind, Mutability};
2525use rustc_middle:: thir:: { Ascription , BindingMode , FieldPat , LocalVarId , Pat , PatKind , PatRange } ;
2626use rustc_middle:: ty:: subst:: { GenericArg , SubstsRef } ;
2727use 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 } ;
2930use rustc_span:: { Span , Symbol } ;
3031use rustc_target:: abi:: FieldIdx ;
3132
@@ -585,43 +586,71 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
585586 id : hir:: HirId ,
586587 span : Span ,
587588 ) -> 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+ ) ,
603598 } ;
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 } )
613611 }
614- _ => { }
612+ _ => None ,
615613 } ,
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 ( _) => { }
621623 }
622624 }
623625
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+ }
625654 }
626655
627656 /// Converts literals, paths and negation of literals to patterns.
0 commit comments