@@ -35,6 +35,7 @@ pub(crate) struct BodyIrGenerator<'a, 'b, D: IrDatabase> {
35
35
function_map : & ' a HashMap < mun_hir:: Function , FunctionValue > ,
36
36
dispatch_table : & ' b DispatchTable ,
37
37
active_loop : Option < LoopInfo > ,
38
+ hir_function : hir:: Function ,
38
39
}
39
40
40
41
impl < ' a , ' b , D : IrDatabase > BodyIrGenerator < ' a , ' b , D > {
@@ -69,6 +70,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
69
70
function_map,
70
71
dispatch_table,
71
72
active_loop : None ,
73
+ hir_function,
72
74
}
73
75
}
74
76
@@ -107,11 +109,20 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
107
109
// Construct a return statement from the returned value of the body if a return is expected
108
110
// in the first place. If the return type of the body is `never` there is no need to
109
111
// generate a return statement.
110
- let ret_type = & self . infer [ self . body . body_expr ( ) ] ;
111
- if let Some ( value) = ret_value {
112
- self . builder . build_return ( Some ( & value) ) ;
113
- } else if !ret_type. is_never ( ) {
114
- self . builder . build_return ( None ) ;
112
+ let block_ret_type = & self . infer [ self . body . body_expr ( ) ] ;
113
+ let fn_ret_type = self
114
+ . hir_function
115
+ . ty ( self . db )
116
+ . callable_sig ( self . db )
117
+ . unwrap ( )
118
+ . ret ( )
119
+ . clone ( ) ;
120
+ if !block_ret_type. is_never ( ) {
121
+ if fn_ret_type. is_empty ( ) {
122
+ self . builder . build_return ( None ) ;
123
+ } else if let Some ( value) = ret_value {
124
+ self . builder . build_return ( Some ( & value) ) ;
125
+ }
115
126
}
116
127
}
117
128
@@ -143,6 +154,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
143
154
} => self . gen_if ( expr, * condition, * then_branch, * else_branch) ,
144
155
Expr :: Return { expr : ret_expr } => self . gen_return ( expr, * ret_expr) ,
145
156
Expr :: Loop { body } => self . gen_loop ( expr, * body) ,
157
+ Expr :: While { condition, body } => self . gen_while ( expr, * condition, * body) ,
146
158
Expr :: Break { expr : break_expr } => self . gen_break ( expr, * break_expr) ,
147
159
_ => unimplemented ! ( "unimplemented expr type {:?}" , & body[ expr] ) ,
148
160
}
@@ -178,6 +190,11 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
178
190
}
179
191
}
180
192
193
+ /// Constructs an empty struct value e.g. `{}`
194
+ fn gen_empty ( & mut self ) -> BasicValueEnum {
195
+ self . module . get_context ( ) . const_struct ( & [ ] , false ) . into ( )
196
+ }
197
+
181
198
/// Generates IR for the specified block expression.
182
199
fn gen_block (
183
200
& mut self ,
@@ -193,16 +210,13 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
193
210
self . gen_let_statement ( * pat, * initializer) ;
194
211
}
195
212
Statement :: Expr ( expr) => {
196
- self . gen_expr ( * expr) ;
197
-
198
213
// No need to generate code after a statement that has a `never` return type.
199
- if self . infer [ * expr] . is_never ( ) {
200
- return None ;
201
- }
214
+ self . gen_expr ( * expr) ?;
202
215
}
203
216
} ;
204
217
}
205
218
tail. and_then ( |expr| self . gen_expr ( expr) )
219
+ . or_else ( || Some ( self . gen_empty ( ) ) )
206
220
}
207
221
208
222
/// Constructs a builder that should be used to emit an `alloca` instruction. These instructions
@@ -365,7 +379,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
365
379
} ;
366
380
let place = self . gen_place_expr ( lhs_expr) ;
367
381
self . builder . build_store ( place, rhs) ;
368
- None
382
+ Some ( self . gen_empty ( ) )
369
383
}
370
384
_ => unimplemented ! ( "Operator {:?} is not implemented for float" , op) ,
371
385
}
@@ -422,7 +436,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
422
436
} ;
423
437
let place = self . gen_place_expr ( lhs_expr) ;
424
438
self . builder . build_store ( place, rhs) ;
425
- None
439
+ Some ( self . gen_empty ( ) )
426
440
}
427
441
_ => unreachable ! ( format!( "Operator {:?} is not implemented for integer" , op) ) ,
428
442
}
@@ -507,10 +521,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
507
521
else_branch : Option < ExprId > ,
508
522
) -> Option < inkwell:: values:: BasicValueEnum > {
509
523
// Generate IR for the condition
510
- let condition_ir = self
511
- . gen_expr ( condition)
512
- . expect ( "condition must have a value" )
513
- . into_int_value ( ) ;
524
+ let condition_ir = self . gen_expr ( condition) ?. into_int_value ( ) ;
514
525
515
526
// Generate the code blocks to branch to
516
527
let context = self . module . get_context ( ) ;
@@ -570,7 +581,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
570
581
Some ( then_block_ir)
571
582
}
572
583
} else {
573
- None
584
+ Some ( self . gen_empty ( ) )
574
585
}
575
586
}
576
587
@@ -600,34 +611,92 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
600
611
None
601
612
}
602
613
603
- fn gen_loop ( & mut self , _expr : ExprId , body_expr : ExprId ) -> Option < BasicValueEnum > {
604
- let context = self . module . get_context ( ) ;
605
- let loop_block = context. append_basic_block ( & self . fn_value , "loop" ) ;
606
- let exit_block = context. append_basic_block ( & self . fn_value , "exit" ) ;
607
-
614
+ fn gen_loop_block_expr (
615
+ & mut self ,
616
+ block : ExprId ,
617
+ exit_block : BasicBlock ,
618
+ ) -> (
619
+ BasicBlock ,
620
+ Vec < ( BasicValueEnum , BasicBlock ) > ,
621
+ Option < BasicValueEnum > ,
622
+ ) {
608
623
// Build a new loop info struct
609
624
let loop_info = LoopInfo {
610
625
exit_block,
611
626
break_values : Vec :: new ( ) ,
612
627
} ;
613
628
629
+ // Replace previous loop info
614
630
let prev_loop = std:: mem:: replace ( & mut self . active_loop , Some ( loop_info) ) ;
615
631
616
- // Insert an explicit fall through from the current block to the loop
617
- self . builder . build_unconditional_branch ( & loop_block) ;
618
-
619
632
// Start generating code inside the loop
620
- self . builder . position_at_end ( & loop_block) ;
621
- let _ = self . gen_expr ( body_expr) ;
622
-
623
- // Jump to the start of the loop
624
- self . builder . build_unconditional_branch ( & loop_block) ;
633
+ let value = self . gen_expr ( block) ;
625
634
626
635
let LoopInfo {
627
636
exit_block,
628
637
break_values,
629
638
} = std:: mem:: replace ( & mut self . active_loop , prev_loop) . unwrap ( ) ;
630
639
640
+ ( exit_block, break_values, value)
641
+ }
642
+
643
+ fn gen_while (
644
+ & mut self ,
645
+ _expr : ExprId ,
646
+ condition_expr : ExprId ,
647
+ body_expr : ExprId ,
648
+ ) -> Option < BasicValueEnum > {
649
+ let context = self . module . get_context ( ) ;
650
+ let cond_block = context. append_basic_block ( & self . fn_value , "whilecond" ) ;
651
+ let loop_block = context. append_basic_block ( & self . fn_value , "while" ) ;
652
+ let exit_block = context. append_basic_block ( & self . fn_value , "afterwhile" ) ;
653
+
654
+ // Insert an explicit fall through from the current block to the condition check
655
+ self . builder . build_unconditional_branch ( & cond_block) ;
656
+
657
+ // Generate condition block
658
+ self . builder . position_at_end ( & cond_block) ;
659
+ let condition_ir = self . gen_expr ( condition_expr) ;
660
+ if let Some ( condition_ir) = condition_ir {
661
+ self . builder . build_conditional_branch (
662
+ condition_ir. into_int_value ( ) ,
663
+ & loop_block,
664
+ & exit_block,
665
+ ) ;
666
+ } else {
667
+ // If the condition doesn't return a value, we also immediately return without a value.
668
+ // This can happen if the expression is a `never` expression.
669
+ return None ;
670
+ }
671
+
672
+ // Generate loop block
673
+ self . builder . position_at_end ( & loop_block) ;
674
+ let ( exit_block, _, value) = self . gen_loop_block_expr ( body_expr, exit_block) ;
675
+ if value. is_some ( ) {
676
+ self . builder . build_unconditional_branch ( & cond_block) ;
677
+ }
678
+
679
+ // Generate exit block
680
+ self . builder . position_at_end ( & exit_block) ;
681
+
682
+ Some ( self . gen_empty ( ) )
683
+ }
684
+
685
+ fn gen_loop ( & mut self , _expr : ExprId , body_expr : ExprId ) -> Option < BasicValueEnum > {
686
+ let context = self . module . get_context ( ) ;
687
+ let loop_block = context. append_basic_block ( & self . fn_value , "loop" ) ;
688
+ let exit_block = context. append_basic_block ( & self . fn_value , "exit" ) ;
689
+
690
+ // Insert an explicit fall through from the current block to the loop
691
+ self . builder . build_unconditional_branch ( & loop_block) ;
692
+
693
+ // Generate the body of the loop
694
+ self . builder . position_at_end ( & loop_block) ;
695
+ let ( exit_block, break_values, value) = self . gen_loop_block_expr ( body_expr, exit_block) ;
696
+ if value. is_some ( ) {
697
+ self . builder . build_unconditional_branch ( & loop_block) ;
698
+ }
699
+
631
700
// Move the builder to the exit block
632
701
self . builder . position_at_end ( & exit_block) ;
633
702
0 commit comments