1- use std:: collections:: { HashMap , HashSet } ;
2-
31use crate :: analyzer:: Analyzer ;
42use crate :: diagnostic:: { Diagnostic , code} ;
53use crate :: hir:: {
@@ -8,6 +6,8 @@ use crate::hir::{
86} ;
97use crate :: syntax:: ast:: { Block , Callee , DataEffect , Expr , FunctionDecl , Item , LetKind , Stmt } ;
108
9+ use super :: local:: { BodyState , merge_if_state, merge_loop_state} ;
10+
1111pub ( crate ) fn check ( analyzer : & mut Analyzer < ' _ > ) {
1212 let functions: Vec < FunctionDecl > = analyzer
1313 . syntax_program
@@ -26,15 +26,6 @@ pub(crate) fn check(analyzer: &mut Analyzer<'_>) {
2626 }
2727}
2828
29- #[ derive( Debug , Clone , Default ) ]
30- struct BodyState {
31- locals : HashSet < String > ,
32- clean_locals : HashSet < String > ,
33- managed : HashSet < String > ,
34- moved : HashMap < String , crate :: diagnostic:: Span > ,
35- value_types : HashMap < String , String > ,
36- }
37-
3829fn seed_function_bindings ( analyzer : & Analyzer < ' _ > , function : & FunctionDecl , state : & mut BodyState ) {
3930 let Some ( body) = analyzer. hir . function_body ( & function. name ) else {
4031 return ;
@@ -44,15 +35,13 @@ fn seed_function_bindings(analyzer: &Analyzer<'_>, function: &FunctionDecl, stat
4435 continue ;
4536 }
4637 if let Some ( type_name) = & binding. type_name {
47- state
48- . value_types
49- . insert ( binding. name . clone ( ) , type_name. clone ( ) ) ;
38+ state. record_type ( binding. name . clone ( ) , type_name. clone ( ) ) ;
5039 }
5140 }
5241}
5342
5443#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
55- enum Flow {
44+ pub ( crate ) enum Flow {
5645 Fallthrough ,
5746 Return ,
5847 Break ,
@@ -180,18 +169,17 @@ fn apply_stmt_effects(analyzer: &mut Analyzer<'_>, statement: &Stmt, state: &mut
180169 Stmt :: Let ( stmt) => {
181170 match stmt. kind {
182171 LetKind :: Managed => {
183- state. managed . insert ( stmt. name . clone ( ) ) ;
172+ state. bind_managed ( stmt. name . clone ( ) ) ;
184173 }
185174 LetKind :: Local => {
186- state. locals . insert ( stmt. name . clone ( ) ) ;
187- state. clean_locals . insert ( stmt. name . clone ( ) ) ;
175+ state. bind_local ( stmt. name . clone ( ) ) ;
188176 }
189177 }
190178 if let Some ( value) = & stmt. value {
191179 if let Some ( type_name) = hir_binding_type ( analyzer, & stmt. span )
192180 . or_else ( || infer_expr_type ( analyzer, value, state) )
193181 {
194- state. value_types . insert ( stmt. name . clone ( ) , type_name) ;
182+ state. record_type ( stmt. name . clone ( ) , type_name) ;
195183 }
196184 apply_expr_effects ( analyzer, value, state) ;
197185 }
@@ -219,127 +207,6 @@ fn hir_binding_type(analyzer: &Analyzer<'_>, span: &crate::diagnostic::Span) ->
219207 . and_then ( |binding| binding. type_name . clone ( ) )
220208}
221209
222- fn merge_if_state (
223- state : & mut BodyState ,
224- base : & BodyState ,
225- then_state : BodyState ,
226- then_flow : Flow ,
227- else_branch : Option < ( BodyState , Flow ) > ,
228- ) -> Flow {
229- let ( else_state, else_flow) = else_branch. unwrap_or_else ( || ( base. clone ( ) , Flow :: Fallthrough ) ) ;
230- let mut fallthrough_states = Vec :: new ( ) ;
231- if then_flow == Flow :: Fallthrough {
232- fallthrough_states. push ( then_state. clone ( ) ) ;
233- }
234- if else_flow == Flow :: Fallthrough {
235- fallthrough_states. push ( else_state. clone ( ) ) ;
236- }
237-
238- match fallthrough_states. as_slice ( ) {
239- [ ] => {
240- * state = base. clone ( ) ;
241- merge_non_fallthrough ( then_flow, else_flow)
242- }
243- [ only] => {
244- * state = fallthrough_projection ( base, only) ;
245- Flow :: Fallthrough
246- }
247- [ left, right] => {
248- * state = merge_fallthrough_states ( base, left, right) ;
249- Flow :: Fallthrough
250- }
251- _ => unreachable ! ( "if has at most two branches" ) ,
252- }
253- }
254-
255- fn merge_loop_state (
256- state : & mut BodyState ,
257- base : & BodyState ,
258- body_state : BodyState ,
259- body_flow : Flow ,
260- may_skip : bool ,
261- ) -> Flow {
262- if !may_skip && body_flow == Flow :: Return {
263- * state = base. clone ( ) ;
264- return Flow :: Return ;
265- }
266- if !may_skip && body_flow == Flow :: Break {
267- * state = fallthrough_projection ( base, & body_state) ;
268- return Flow :: Fallthrough ;
269- }
270-
271- let mut moved = base. moved . clone ( ) ;
272- if body_flow != Flow :: Return {
273- for ( name, span) in & body_state. moved {
274- if base. locals . contains ( name) || base. moved . contains_key ( name) {
275- moved. entry ( name. clone ( ) ) . or_insert_with ( || span. clone ( ) ) ;
276- }
277- }
278- }
279-
280- state. locals = base. locals . clone ( ) ;
281- state. managed = base. managed . clone ( ) ;
282- state. value_types = base. value_types . clone ( ) ;
283- state. moved = moved;
284- state. clean_locals = base
285- . clean_locals
286- . intersection ( & body_state. clean_locals )
287- . filter ( |name| base. locals . contains ( * name) )
288- . cloned ( )
289- . collect ( ) ;
290- Flow :: Fallthrough
291- }
292-
293- fn merge_non_fallthrough ( left : Flow , right : Flow ) -> Flow {
294- if left == right { left } else { Flow :: Return }
295- }
296-
297- fn fallthrough_projection ( base : & BodyState , branch : & BodyState ) -> BodyState {
298- let mut moved = base. moved . clone ( ) ;
299- for ( name, span) in & branch. moved {
300- if base. locals . contains ( name) || base. moved . contains_key ( name) {
301- moved. entry ( name. clone ( ) ) . or_insert_with ( || span. clone ( ) ) ;
302- }
303- }
304-
305- BodyState {
306- locals : base. locals . clone ( ) ,
307- managed : base. managed . clone ( ) ,
308- value_types : base. value_types . clone ( ) ,
309- moved,
310- clean_locals : branch
311- . clean_locals
312- . intersection ( & base. clean_locals )
313- . filter ( |name| base. locals . contains ( * name) )
314- . cloned ( )
315- . collect ( ) ,
316- }
317- }
318-
319- fn merge_fallthrough_states ( base : & BodyState , left : & BodyState , right : & BodyState ) -> BodyState {
320- let mut moved = base. moved . clone ( ) ;
321- for branch in [ left, right] {
322- for ( name, span) in & branch. moved {
323- if base. locals . contains ( name) || base. moved . contains_key ( name) {
324- moved. entry ( name. clone ( ) ) . or_insert_with ( || span. clone ( ) ) ;
325- }
326- }
327- }
328-
329- BodyState {
330- locals : base. locals . clone ( ) ,
331- managed : base. managed . clone ( ) ,
332- value_types : base. value_types . clone ( ) ,
333- moved,
334- clean_locals : left
335- . clean_locals
336- . intersection ( & right. clean_locals )
337- . filter ( |name| base. locals . contains ( * name) )
338- . cloned ( )
339- . collect ( ) ,
340- }
341- }
342-
343210fn apply_expr_effects ( analyzer : & mut Analyzer < ' _ > , expr : & Expr , state : & mut BodyState ) {
344211 match expr {
345212 Expr :: Manage { value, span } => {
@@ -383,10 +250,7 @@ fn apply_move_events(
383250 continue ;
384251 }
385252 if state. locals . contains ( & event. binding_name ) {
386- state
387- . moved
388- . insert ( event. binding_name . clone ( ) , event. span . clone ( ) ) ;
389- state. clean_locals . remove ( & event. binding_name ) ;
253+ state. mark_moved ( & event. binding_name , event. span . clone ( ) ) ;
390254 }
391255 }
392256}
@@ -403,7 +267,7 @@ fn apply_retention_events(
403267 if !state. locals . contains ( & event. binding_name ) {
404268 continue ;
405269 }
406- state. clean_locals . remove ( & event. binding_name ) ;
270+ state. mark_retained ( & event. binding_name ) ;
407271 }
408272}
409273
0 commit comments