@@ -3,11 +3,11 @@ use std::sync::Arc;
33use rustc_ast:: ptr:: P ;
44use rustc_ast:: * ;
55use rustc_data_structures:: stack:: ensure_sufficient_stack;
6- use rustc_hir as hir ;
7- use rustc_hir:: def :: Res ;
6+ use rustc_hir:: def :: { DefKind , Res } ;
7+ use rustc_hir:: { self as hir , LangItem } ;
88use rustc_middle:: span_bug;
99use rustc_span:: source_map:: { Spanned , respan} ;
10- use rustc_span:: { Ident , Span } ;
10+ use rustc_span:: { DesugaringKind , Ident , Span , kw } ;
1111
1212use super :: errors:: {
1313 ArbitraryExpressionInPattern , ExtraDoubleDot , MisplacedDoubleDot , SubTupleBinding ,
@@ -430,22 +430,124 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
430430 self . arena . alloc ( hir:: PatExpr { hir_id : self . lower_node_id ( expr. id ) , span, kind } )
431431 }
432432
433- pub ( crate ) fn lower_ty_pat ( & mut self , pattern : & TyPat ) -> & ' hir hir:: TyPat < ' hir > {
434- self . arena . alloc ( self . lower_ty_pat_mut ( pattern) )
433+ pub ( crate ) fn lower_ty_pat (
434+ & mut self ,
435+ pattern : & TyPat ,
436+ base_type : Span ,
437+ ) -> & ' hir hir:: TyPat < ' hir > {
438+ self . arena . alloc ( self . lower_ty_pat_mut ( pattern, base_type) )
435439 }
436440
437- fn lower_ty_pat_mut ( & mut self , pattern : & TyPat ) -> hir:: TyPat < ' hir > {
441+ fn lower_ty_pat_mut ( & mut self , pattern : & TyPat , base_type : Span ) -> hir:: TyPat < ' hir > {
438442 // loop here to avoid recursion
439443 let pat_hir_id = self . lower_node_id ( pattern. id ) ;
440444 let node = match & pattern. kind {
441- TyPatKind :: Range ( e1, e2, Spanned { node : end, .. } ) => hir:: TyPatKind :: Range (
442- e1. as_deref ( ) . map ( |e| self . lower_anon_const_to_const_arg ( e) ) ,
443- e2. as_deref ( ) . map ( |e| self . lower_anon_const_to_const_arg ( e) ) ,
444- self . lower_range_end ( end, e2. is_some ( ) ) ,
445+ TyPatKind :: Range ( e1, e2, Spanned { node : end, span } ) => hir:: TyPatKind :: Range (
446+ e1. as_deref ( ) . map ( |e| self . lower_anon_const_to_const_arg ( e) ) . unwrap_or_else ( || {
447+ self . lower_ty_pat_range_end (
448+ hir:: LangItem :: RangeMin ,
449+ span. shrink_to_lo ( ) ,
450+ base_type,
451+ )
452+ } ) ,
453+ e2. as_deref ( )
454+ . map ( |e| match end {
455+ RangeEnd :: Included ( ..) => self . lower_anon_const_to_const_arg ( e) ,
456+ RangeEnd :: Excluded => self . lower_excluded_range_end ( e) ,
457+ } )
458+ . unwrap_or_else ( || {
459+ self . lower_ty_pat_range_end (
460+ hir:: LangItem :: RangeMax ,
461+ span. shrink_to_hi ( ) ,
462+ base_type,
463+ )
464+ } ) ,
445465 ) ,
446466 TyPatKind :: Err ( guar) => hir:: TyPatKind :: Err ( * guar) ,
447467 } ;
448468
449469 hir:: TyPat { hir_id : pat_hir_id, kind : node, span : self . lower_span ( pattern. span ) }
450470 }
471+
472+ /// Lowers the range end of an exclusive range (`2..5`) to an inclusive range 2..=(5 - 1).
473+ /// This way the type system doesn't have to handle the distinction between inclusive/exclusive ranges.
474+ fn lower_excluded_range_end ( & mut self , e : & AnonConst ) -> & ' hir hir:: ConstArg < ' hir > {
475+ let span = self . lower_span ( e. value . span ) ;
476+ let unstable_span = self . mark_span_with_reason (
477+ DesugaringKind :: PatTyRange ,
478+ span,
479+ Some ( Arc :: clone ( & self . allow_pattern_type ) ) ,
480+ ) ;
481+ let anon_const = self . with_new_scopes ( span, |this| {
482+ let def_id = this. local_def_id ( e. id ) ;
483+ let hir_id = this. lower_node_id ( e. id ) ;
484+ let body = this. lower_body ( |this| {
485+ // Need to use a custom function as we can't just subtract `1` from a `char`.
486+ let kind = hir:: ExprKind :: Path ( this. make_lang_item_qpath (
487+ hir:: LangItem :: RangeSub ,
488+ unstable_span,
489+ None ,
490+ ) ) ;
491+ let fn_def = this. arena . alloc ( hir:: Expr { hir_id : this. next_id ( ) , kind, span } ) ;
492+ let args = this. arena . alloc ( [ this. lower_expr_mut ( & e. value ) ] ) ;
493+ (
494+ & [ ] ,
495+ hir:: Expr {
496+ hir_id : this. next_id ( ) ,
497+ kind : hir:: ExprKind :: Call ( fn_def, args) ,
498+ span,
499+ } ,
500+ )
501+ } ) ;
502+ hir:: AnonConst { def_id, hir_id, body, span }
503+ } ) ;
504+ self . arena . alloc ( hir:: ConstArg {
505+ hir_id : self . next_id ( ) ,
506+ kind : hir:: ConstArgKind :: Anon ( self . arena . alloc ( anon_const) ) ,
507+ } )
508+ }
509+
510+ /// When a range has no end specified (`1..` or `1..=`) or no start specified (`..5` or `..=5`),
511+ /// we instead use a constant of the MAX/MIN of the type.
512+ /// This way the type system does not have to handle the lack of a start/end.
513+ fn lower_ty_pat_range_end (
514+ & mut self ,
515+ lang_item : LangItem ,
516+ span : Span ,
517+ base_type : Span ,
518+ ) -> & ' hir hir:: ConstArg < ' hir > {
519+ let parent_def_id = self . current_hir_id_owner . def_id ;
520+ let node_id = self . next_node_id ( ) ;
521+
522+ // Add a definition for the in-band const def.
523+ // We're generating a range end that didn't exist in the AST,
524+ // so the def collector didn't create the def ahead of time. That's why we have to do
525+ // it here.
526+ let def_id = self . create_def ( parent_def_id, node_id, kw:: Empty , DefKind :: AnonConst , span) ;
527+ let hir_id = self . lower_node_id ( node_id) ;
528+
529+ let unstable_span = self . mark_span_with_reason (
530+ DesugaringKind :: PatTyRange ,
531+ self . lower_span ( span) ,
532+ Some ( Arc :: clone ( & self . allow_pattern_type ) ) ,
533+ ) ;
534+ let span = self . lower_span ( base_type) ;
535+
536+ let path_expr = hir:: Expr {
537+ hir_id : self . next_id ( ) ,
538+ kind : hir:: ExprKind :: Path ( self . make_lang_item_qpath ( lang_item, unstable_span, None ) ) ,
539+ span,
540+ } ;
541+
542+ let ct = self . with_new_scopes ( span, |this| {
543+ self . arena . alloc ( hir:: AnonConst {
544+ def_id,
545+ hir_id,
546+ body : this. lower_body ( |_this| ( & [ ] , path_expr) ) ,
547+ span,
548+ } )
549+ } ) ;
550+ let hir_id = self . next_id ( ) ;
551+ self . arena . alloc ( hir:: ConstArg { kind : hir:: ConstArgKind :: Anon ( ct) , hir_id } )
552+ }
451553}
0 commit comments