@@ -31,8 +31,8 @@ use crate::{
31
31
expander:: Expander ,
32
32
hir:: {
33
33
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 ,
36
36
} ,
37
37
item_scope:: BuiltinShadowMode ,
38
38
lang_item:: LangItem ,
@@ -295,13 +295,7 @@ impl ExprCollector<'_> {
295
295
296
296
self . alloc_expr ( Expr :: While { condition, body, label } , syntax_ptr)
297
297
}
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) ,
305
299
ast:: Expr :: CallExpr ( e) => {
306
300
let is_rustc_box = {
307
301
let attrs = e. attrs ( ) ;
@@ -703,6 +697,91 @@ impl ExprCollector<'_> {
703
697
expr_id
704
698
}
705
699
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
+
706
785
/// Desugar `ast::TryExpr` from: `<expr>?` into:
707
786
/// ```ignore (pseudo-rust)
708
787
/// match Try::branch(<expr>) {
@@ -1159,22 +1238,12 @@ impl ExprCollector<'_> {
1159
1238
}
1160
1239
#[ rustfmt:: skip] // https://github.com/rust-lang/rustfmt/issues/5676
1161
1240
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
+ }
1178
1247
ast:: Pat :: RestPat ( _) => {
1179
1248
// `RestPat` requires special handling and should not be mapped
1180
1249
// to a Pat. Here we are using `Pat::Missing` as a fallback for
@@ -1215,8 +1284,30 @@ impl ExprCollector<'_> {
1215
1284
}
1216
1285
None => Pat :: Missing ,
1217
1286
} ,
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
+ }
1220
1311
} ;
1221
1312
let ptr = AstPtr :: new ( & pat) ;
1222
1313
self . alloc_pat ( pattern, Either :: Left ( ptr) )
@@ -1338,6 +1429,18 @@ impl ExprCollector<'_> {
1338
1429
// endregion: labels
1339
1430
}
1340
1431
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
+
1341
1444
impl ExprCollector < ' _ > {
1342
1445
fn alloc_expr ( & mut self , expr : Expr , ptr : ExprPtr ) -> ExprId {
1343
1446
let src = self . expander . to_source ( ptr) ;
0 commit comments