@@ -786,10 +786,28 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
786
786
ExprAddrOf ( m, ref ohs) => {
787
787
hir:: ExprAddrOf ( lower_mutability ( lctx, m) , lower_expr ( lctx, ohs) )
788
788
}
789
- ExprIf ( ref cond, ref tr, ref fl) => {
789
+ // More complicated than you might expect because the else branch
790
+ // might be `if let`.
791
+ ExprIf ( ref cond, ref blk, ref else_opt) => {
792
+ let else_opt = else_opt. as_ref ( ) . map ( |els| match els. node {
793
+ ExprIfLet ( ..) => {
794
+ // wrap the if-let expr in a block
795
+ let span = els. span ;
796
+ let blk = P ( hir:: Block {
797
+ stmts : vec ! [ ] ,
798
+ expr : Some ( lower_expr ( lctx, els) ) ,
799
+ id : lctx. next_id ( ) ,
800
+ rules : hir:: DefaultBlock ,
801
+ span : span
802
+ } ) ;
803
+ expr_block ( lctx, blk)
804
+ }
805
+ _ => lower_expr ( lctx, els)
806
+ } ) ;
807
+
790
808
hir:: ExprIf ( lower_expr ( lctx, cond) ,
791
- lower_block ( lctx, tr ) ,
792
- fl . as_ref ( ) . map ( |x| lower_expr ( lctx , x ) ) )
809
+ lower_block ( lctx, blk ) ,
810
+ else_opt )
793
811
}
794
812
ExprWhile ( ref cond, ref body, opt_ident) => {
795
813
hir:: ExprWhile ( lower_expr ( lctx, cond) ,
@@ -880,16 +898,123 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
880
898
ExprInPlace ( ..) => {
881
899
panic ! ( "todo" ) ;
882
900
}
883
- ExprIfLet ( ..) => {
884
- panic ! ( "todo" ) ;
901
+
902
+ // Desugar ExprIfLet
903
+ // From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
904
+ ExprIfLet ( ref pat, ref sub_expr, ref body, ref else_opt) => {
905
+ // to:
906
+ //
907
+ // match <sub_expr> {
908
+ // <pat> => <body>,
909
+ // [_ if <else_opt_if_cond> => <else_opt_if_body>,]
910
+ // _ => [<else_opt> | ()]
911
+ // }
912
+
913
+ // `<pat> => <body>`
914
+ let pat_arm = {
915
+ let body_expr = expr_block ( lctx, lower_block ( lctx, body) ) ;
916
+ arm ( vec ! [ lower_pat( lctx, pat) ] , body_expr)
917
+ } ;
918
+
919
+ // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
920
+ let mut else_opt = else_opt. as_ref ( ) . map ( |e| lower_expr ( lctx, e) ) ;
921
+ let else_if_arms = {
922
+ let mut arms = vec ! [ ] ;
923
+ loop {
924
+ let else_opt_continue = else_opt
925
+ . and_then ( |els| els. and_then ( |els| match els. node {
926
+ // else if
927
+ hir:: ExprIf ( cond, then, else_opt) => {
928
+ let pat_under = pat_wild ( lctx, e. span ) ;
929
+ arms. push ( hir:: Arm {
930
+ attrs : vec ! [ ] ,
931
+ pats : vec ! [ pat_under] ,
932
+ guard : Some ( cond) ,
933
+ body : expr_block ( lctx, then)
934
+ } ) ;
935
+ else_opt. map ( |else_opt| ( else_opt, true ) )
936
+ }
937
+ _ => Some ( ( P ( els) , false ) )
938
+ } ) ) ;
939
+ match else_opt_continue {
940
+ Some ( ( e, true ) ) => {
941
+ else_opt = Some ( e) ;
942
+ }
943
+ Some ( ( e, false ) ) => {
944
+ else_opt = Some ( e) ;
945
+ break ;
946
+ }
947
+ None => {
948
+ else_opt = None ;
949
+ break ;
950
+ }
951
+ }
952
+ }
953
+ arms
954
+ } ;
955
+
956
+ let contains_else_clause = else_opt. is_some ( ) ;
957
+
958
+ // `_ => [<else_opt> | ()]`
959
+ let else_arm = {
960
+ let pat_under = pat_wild ( lctx, e. span ) ;
961
+ let else_expr = else_opt. unwrap_or_else ( || expr_tuple ( lctx, e. span , vec ! [ ] ) ) ;
962
+ arm ( vec ! [ pat_under] , else_expr)
963
+ } ;
964
+
965
+ let mut arms = Vec :: with_capacity ( else_if_arms. len ( ) + 2 ) ;
966
+ arms. push ( pat_arm) ;
967
+ arms. extend ( else_if_arms) ;
968
+ arms. push ( else_arm) ;
969
+
970
+ let match_expr = expr ( lctx,
971
+ e. span ,
972
+ hir:: ExprMatch ( lower_expr ( lctx, sub_expr) , arms,
973
+ hir:: MatchSource :: IfLetDesugar {
974
+ contains_else_clause : contains_else_clause,
975
+ } ) ) ;
976
+ return match_expr;
885
977
}
886
- ExprWhileLet ( ..) => {
887
- panic ! ( "todo" ) ;
978
+
979
+ // Desugar ExprWhileLet
980
+ // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
981
+ ExprWhileLet ( ref pat, ref sub_expr, ref body, opt_ident) => {
982
+ // to:
983
+ //
984
+ // [opt_ident]: loop {
985
+ // match <sub_expr> {
986
+ // <pat> => <body>,
987
+ // _ => break
988
+ // }
989
+ // }
990
+
991
+ // `<pat> => <body>`
992
+ let pat_arm = {
993
+ let body_expr = expr_block ( lctx, lower_block ( lctx, body) ) ;
994
+ arm ( vec ! [ lower_pat( lctx, pat) ] , body_expr)
995
+ } ;
996
+
997
+ // `_ => break`
998
+ let break_arm = {
999
+ let pat_under = pat_wild ( lctx, e. span ) ;
1000
+ let break_expr = expr_break ( lctx, e. span ) ;
1001
+ arm ( vec ! [ pat_under] , break_expr)
1002
+ } ;
1003
+
1004
+ // // `match <sub_expr> { ... }`
1005
+ let arms = vec ! [ pat_arm, break_arm] ;
1006
+ let match_expr = expr ( lctx,
1007
+ e. span ,
1008
+ hir:: ExprMatch ( lower_expr ( lctx, sub_expr) , arms, hir:: MatchSource :: WhileLetDesugar ) ) ;
1009
+
1010
+ // `[opt_ident]: loop { ... }`
1011
+ let loop_block = block_expr ( lctx, match_expr) ;
1012
+ return expr ( lctx, e. span , hir:: ExprLoop ( loop_block, opt_ident) ) ;
888
1013
}
889
1014
890
1015
// Desugar ExprForLoop
891
1016
// From: `[opt_ident]: for <pat> in <head> <body>`
892
- ExprForLoop ( ref pat, ref head, ref body, ref opt_ident) => {
1017
+ ExprForLoop ( ref pat, ref head, ref body, opt_ident) => {
893
1018
// to:
894
1019
//
895
1020
// {
@@ -952,7 +1077,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
952
1077
953
1078
// `[opt_ident]: loop { ... }`
954
1079
let loop_block = block_expr ( lctx, match_expr) ;
955
- let loop_expr = expr ( lctx, e. span , hir:: ExprLoop ( loop_block, opt_ident. clone ( ) ) ) ;
1080
+ let loop_expr = expr ( lctx, e. span , hir:: ExprLoop ( loop_block, opt_ident) ) ;
956
1081
957
1082
// `mut iter => { ... }`
958
1083
let iter_arm = {
@@ -976,16 +1101,14 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
976
1101
977
1102
// `{ let result = ...; result }`
978
1103
let result_ident = token:: gensym_ident ( "result" ) ;
979
- let result = expr_block ( lctx,
980
- block_all ( lctx,
981
- e. span ,
982
- vec ! [ stmt_let( lctx,
983
- e. span,
984
- false ,
985
- result_ident,
986
- match_expr) ] ,
987
- Some ( expr_ident ( lctx, e. span , result_ident) ) ) ) ;
988
- return result;
1104
+ return expr_block ( lctx,
1105
+ block_all ( lctx,
1106
+ e. span ,
1107
+ vec ! [ stmt_let( lctx, e. span,
1108
+ false ,
1109
+ result_ident,
1110
+ match_expr) ] ,
1111
+ Some ( expr_ident ( lctx, e. span , result_ident) ) ) )
989
1112
}
990
1113
991
1114
ExprMac ( _) => panic ! ( "Shouldn't exist here" ) ,
@@ -1137,6 +1260,10 @@ fn expr_block(lctx: &LoweringContext, b: P<hir::Block>) -> P<hir::Expr> {
1137
1260
expr ( lctx, b. span , hir:: ExprBlock ( b) )
1138
1261
}
1139
1262
1263
+ fn expr_tuple ( lctx : & LoweringContext , sp : Span , exprs : Vec < P < hir:: Expr > > ) -> P < hir:: Expr > {
1264
+ expr ( lctx, sp, hir:: ExprTup ( exprs) )
1265
+ }
1266
+
1140
1267
fn expr ( lctx : & LoweringContext , span : Span , node : hir:: Expr_ ) -> P < hir:: Expr > {
1141
1268
P ( hir:: Expr {
1142
1269
id : lctx. next_id ( ) ,
@@ -1208,6 +1335,10 @@ fn pat_ident_binding_mode(lctx: &LoweringContext,
1208
1335
pat ( lctx, span, pat_ident)
1209
1336
}
1210
1337
1338
+ fn pat_wild ( lctx : & LoweringContext , span : Span ) -> P < hir:: Pat > {
1339
+ pat ( lctx, span, hir:: PatWild ( hir:: PatWildSingle ) )
1340
+ }
1341
+
1211
1342
fn pat ( lctx : & LoweringContext , span : Span , pat : hir:: Pat_ ) -> P < hir:: Pat > {
1212
1343
P ( hir:: Pat { id : lctx. next_id ( ) , node : pat, span : span } )
1213
1344
}
0 commit comments