@@ -31,8 +31,8 @@ use crate::{
3131 expander:: Expander ,
3232 hir:: {
3333 dummy_expr_id, Array , Binding , BindingAnnotation , BindingId , CaptureBy , ClosureKind , Expr ,
34- ExprId , Label , LabelId , Literal , MatchArm , Movability , Pat , PatId , RecordFieldPat ,
35- RecordLitField , Statement ,
34+ ExprId , Label , LabelId , Literal , LiteralOrConst , MatchArm , Movability , Pat , PatId ,
35+ RecordFieldPat , RecordLitField , Statement ,
3636 } ,
3737 item_scope:: BuiltinShadowMode ,
3838 lang_item:: LangItem ,
@@ -295,13 +295,7 @@ impl ExprCollector<'_> {
295295
296296 self . alloc_expr ( Expr :: While { condition, body, label } , syntax_ptr)
297297 }
298- ast:: Expr :: ForExpr ( e) => {
299- let label = e. label ( ) . map ( |label| self . collect_label ( label) ) ;
300- let iterable = self . collect_expr_opt ( e. iterable ( ) ) ;
301- let pat = self . collect_pat_top ( e. pat ( ) ) ;
302- let body = self . collect_labelled_block_opt ( label, e. loop_body ( ) ) ;
303- self . alloc_expr ( Expr :: For { iterable, pat, body, label } , syntax_ptr)
304- }
298+ ast:: Expr :: ForExpr ( e) => self . collect_for_loop ( syntax_ptr, e) ,
305299 ast:: Expr :: CallExpr ( e) => {
306300 let is_rustc_box = {
307301 let attrs = e. attrs ( ) ;
@@ -703,6 +697,91 @@ impl ExprCollector<'_> {
703697 expr_id
704698 }
705699
700+ /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
701+ /// ```ignore (pseudo-rust)
702+ /// match IntoIterator::into_iter(<head>) {
703+ /// mut iter => {
704+ /// [opt_ident]: loop {
705+ /// match Iterator::next(&mut iter) {
706+ /// None => break,
707+ /// Some(<pat>) => <body>,
708+ /// };
709+ /// }
710+ /// }
711+ /// }
712+ /// ```
713+ fn collect_for_loop ( & mut self , syntax_ptr : AstPtr < ast:: Expr > , e : ast:: ForExpr ) -> ExprId {
714+ let ( into_iter_fn, iter_next_fn, option_some, option_none) = ' if_chain: {
715+ if let Some ( into_iter_fn) = LangItem :: IntoIterIntoIter . path ( self . db , self . krate ) {
716+ if let Some ( iter_next_fn) = LangItem :: IteratorNext . path ( self . db , self . krate ) {
717+ if let Some ( option_some) = LangItem :: OptionSome . path ( self . db , self . krate ) {
718+ if let Some ( option_none) = LangItem :: OptionNone . path ( self . db , self . krate ) {
719+ break ' if_chain ( into_iter_fn, iter_next_fn, option_some, option_none) ;
720+ }
721+ }
722+ }
723+ }
724+ // Some of the needed lang items are missing, so we can't desugar
725+ return self . alloc_expr ( Expr :: Missing , syntax_ptr) ;
726+ } ;
727+ let head = self . collect_expr_opt ( e. iterable ( ) ) ;
728+ let into_iter_fn_expr = self . alloc_expr ( Expr :: Path ( into_iter_fn) , syntax_ptr. clone ( ) ) ;
729+ let iterator = self . alloc_expr (
730+ Expr :: Call {
731+ callee : into_iter_fn_expr,
732+ args : Box :: new ( [ head] ) ,
733+ is_assignee_expr : false ,
734+ } ,
735+ syntax_ptr. clone ( ) ,
736+ ) ;
737+ let none_arm = MatchArm {
738+ pat : self . alloc_pat_desugared ( Pat :: Path ( Box :: new ( option_none) ) ) ,
739+ guard : None ,
740+ expr : self . alloc_expr ( Expr :: Break { expr : None , label : None } , syntax_ptr. clone ( ) ) ,
741+ } ;
742+ let some_pat = Pat :: TupleStruct {
743+ path : Some ( Box :: new ( option_some) ) ,
744+ args : Box :: new ( [ self . collect_pat_top ( e. pat ( ) ) ] ) ,
745+ ellipsis : None ,
746+ } ;
747+ let some_arm = MatchArm {
748+ pat : self . alloc_pat_desugared ( some_pat) ,
749+ guard : None ,
750+ expr : self . collect_expr_opt ( e. loop_body ( ) . map ( |x| x. into ( ) ) ) ,
751+ } ;
752+ let iter_name = Name :: generate_new_name ( ) ;
753+ let iter_binding = self . alloc_binding ( iter_name. clone ( ) , BindingAnnotation :: Mutable ) ;
754+ let iter_expr = self . alloc_expr ( Expr :: Path ( Path :: from ( iter_name) ) , syntax_ptr. clone ( ) ) ;
755+ let iter_expr_mut = self . alloc_expr (
756+ Expr :: Ref { expr : iter_expr, rawness : Rawness :: Ref , mutability : Mutability :: Mut } ,
757+ syntax_ptr. clone ( ) ,
758+ ) ;
759+ let iter_next_fn_expr = self . alloc_expr ( Expr :: Path ( iter_next_fn) , syntax_ptr. clone ( ) ) ;
760+ let iter_next_expr = self . alloc_expr (
761+ Expr :: Call {
762+ callee : iter_next_fn_expr,
763+ args : Box :: new ( [ iter_expr_mut] ) ,
764+ is_assignee_expr : false ,
765+ } ,
766+ syntax_ptr. clone ( ) ,
767+ ) ;
768+ let loop_inner = self . alloc_expr (
769+ Expr :: Match { expr : iter_next_expr, arms : Box :: new ( [ none_arm, some_arm] ) } ,
770+ syntax_ptr. clone ( ) ,
771+ ) ;
772+ let label = e. label ( ) . map ( |label| self . collect_label ( label) ) ;
773+ let loop_outer =
774+ self . alloc_expr ( Expr :: Loop { body : loop_inner, label } , syntax_ptr. clone ( ) ) ;
775+ let iter_pat = self . alloc_pat_desugared ( Pat :: Bind { id : iter_binding, subpat : None } ) ;
776+ self . alloc_expr (
777+ Expr :: Match {
778+ expr : iterator,
779+ arms : Box :: new ( [ MatchArm { pat : iter_pat, guard : None , expr : loop_outer } ] ) ,
780+ } ,
781+ syntax_ptr. clone ( ) ,
782+ )
783+ }
784+
706785 /// Desugar `ast::TryExpr` from: `<expr>?` into:
707786 /// ```ignore (pseudo-rust)
708787 /// match Try::branch(<expr>) {
@@ -1159,22 +1238,12 @@ impl ExprCollector<'_> {
11591238 }
11601239 #[ rustfmt:: skip] // https://github.com/rust-lang/rustfmt/issues/5676
11611240 ast:: Pat :: LiteralPat ( lit) => ' b: {
1162- if let Some ( ast_lit) = lit. literal ( ) {
1163- let mut hir_lit: Literal = ast_lit. kind ( ) . into ( ) ;
1164- if lit. minus_token ( ) . is_some ( ) {
1165- let Some ( h) = hir_lit. negate ( ) else {
1166- break ' b Pat :: Missing ;
1167- } ;
1168- hir_lit = h;
1169- }
1170- let expr = Expr :: Literal ( hir_lit) ;
1171- let expr_ptr = AstPtr :: new ( & ast:: Expr :: Literal ( ast_lit) ) ;
1172- let expr_id = self . alloc_expr ( expr, expr_ptr) ;
1173- Pat :: Lit ( expr_id)
1174- } else {
1175- Pat :: Missing
1176- }
1177- } ,
1241+ let Some ( ( hir_lit, ast_lit) ) = pat_literal_to_hir ( lit) else { break ' b Pat :: Missing } ;
1242+ let expr = Expr :: Literal ( hir_lit) ;
1243+ let expr_ptr = AstPtr :: new ( & ast:: Expr :: Literal ( ast_lit) ) ;
1244+ let expr_id = self . alloc_expr ( expr, expr_ptr) ;
1245+ Pat :: Lit ( expr_id)
1246+ }
11781247 ast:: Pat :: RestPat ( _) => {
11791248 // `RestPat` requires special handling and should not be mapped
11801249 // to a Pat. Here we are using `Pat::Missing` as a fallback for
@@ -1215,8 +1284,30 @@ impl ExprCollector<'_> {
12151284 }
12161285 None => Pat :: Missing ,
12171286 } ,
1218- // FIXME: implement
1219- ast:: Pat :: RangePat ( _) => Pat :: Missing ,
1287+ // FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference.
1288+ ast:: Pat :: RangePat ( p) => {
1289+ let mut range_part_lower = |p : Option < ast:: Pat > | {
1290+ p. and_then ( |x| match & x {
1291+ ast:: Pat :: LiteralPat ( x) => {
1292+ Some ( Box :: new ( LiteralOrConst :: Literal ( pat_literal_to_hir ( x) ?. 0 ) ) )
1293+ }
1294+ ast:: Pat :: IdentPat ( p) => {
1295+ let name =
1296+ p. name ( ) . map ( |nr| nr. as_name ( ) ) . unwrap_or_else ( Name :: missing) ;
1297+ Some ( Box :: new ( LiteralOrConst :: Const ( name. into ( ) ) ) )
1298+ }
1299+ ast:: Pat :: PathPat ( p) => p
1300+ . path ( )
1301+ . and_then ( |path| self . expander . parse_path ( self . db , path) )
1302+ . map ( LiteralOrConst :: Const )
1303+ . map ( Box :: new) ,
1304+ _ => None ,
1305+ } )
1306+ } ;
1307+ let start = range_part_lower ( p. start ( ) ) ;
1308+ let end = range_part_lower ( p. end ( ) ) ;
1309+ Pat :: Range { start, end }
1310+ }
12201311 } ;
12211312 let ptr = AstPtr :: new ( & pat) ;
12221313 self . alloc_pat ( pattern, Either :: Left ( ptr) )
@@ -1338,6 +1429,18 @@ impl ExprCollector<'_> {
13381429 // endregion: labels
13391430}
13401431
1432+ fn pat_literal_to_hir ( lit : & ast:: LiteralPat ) -> Option < ( Literal , ast:: Literal ) > {
1433+ let ast_lit = lit. literal ( ) ?;
1434+ let mut hir_lit: Literal = ast_lit. kind ( ) . into ( ) ;
1435+ if lit. minus_token ( ) . is_some ( ) {
1436+ let Some ( h) = hir_lit. negate ( ) else {
1437+ return None ;
1438+ } ;
1439+ hir_lit = h;
1440+ }
1441+ Some ( ( hir_lit, ast_lit) )
1442+ }
1443+
13411444impl ExprCollector < ' _ > {
13421445 fn alloc_expr ( & mut self , expr : Expr , ptr : ExprPtr ) -> ExprId {
13431446 let src = self . expander . to_source ( ptr) ;
0 commit comments