@@ -215,13 +215,23 @@ fn apply_reboxing_candidate<'db>(
215215 candidate. reboxed_var. index( )
216216 ) ;
217217
218- // TODO(eytan-starkware): Handle snapshot of box (e.g., @Box<T>).
219- // Only support MemberOfUnboxed where source is Unboxed for now.
220- let ReboxingValue :: MemberOfUnboxed { source , member } = & candidate. source else {
221- // If source is not member of unboxed, we are reboxing original value which is not supported
222- // yet.
223- return ;
218+ match & candidate . source {
219+ ReboxingValue :: Revoked => ( ) ,
220+ ReboxingValue :: Unboxed ( id ) => replace_variable_usages ( lowered , candidate. reboxed_var , * id ) ,
221+ ReboxingValue :: MemberOfUnboxed { source, member } => {
222+ replace_into_box_call ( db , lowered , candidate , source , * member )
223+ }
224224 } ;
225+ }
226+
227+ /// Replaces the call to `into_box` with a call to `struct_boxed_deconstruct`.
228+ fn replace_into_box_call < ' db > (
229+ db : & ' db dyn Database ,
230+ lowered : & mut Lowered < ' db > ,
231+ candidate : & ReboxCandidate ,
232+ source : & Rc < ReboxingValue > ,
233+ member : usize ,
234+ ) {
225235 let ReboxingValue :: Unboxed ( source_var) = * * source else {
226236 // When source of the value is not `Unboxes`, it is a nested MemberOfUnboxed, which is not
227237 // supported yet.
@@ -232,7 +242,7 @@ fn apply_reboxing_candidate<'db>(
232242 db,
233243 & mut lowered. variables ,
234244 source_var,
235- * member,
245+ member,
236246 candidate. reboxed_var ,
237247 & lowered. blocks [ candidate. into_box_location . 0 ] . statements [ candidate. into_box_location . 1 ] ,
238248 ) {
@@ -244,6 +254,59 @@ fn apply_reboxing_candidate<'db>(
244254 }
245255}
246256
257+ /// Replaces all usages of old_var with new_var throughout the lowered function.
258+ fn replace_variable_usages ( lowered : & mut Lowered < ' _ > , old_var : VariableId , new_var : VariableId ) {
259+ if old_var == new_var {
260+ return ;
261+ }
262+
263+ for block in lowered. blocks . iter_mut ( ) {
264+ for stmt in & mut block. statements {
265+ for input in stmt. inputs_mut ( ) {
266+ if input. var_id == old_var {
267+ input. var_id = new_var;
268+ }
269+ }
270+ }
271+
272+ match & mut block. end {
273+ BlockEnd :: Return ( var_usages, _) => {
274+ for return_var in var_usages. iter_mut ( ) {
275+ if return_var. var_id == old_var {
276+ return_var. var_id = new_var;
277+ }
278+ }
279+ }
280+ BlockEnd :: Goto ( _, remapping) => {
281+ // Collect all changes needed
282+ let mut changes = Vec :: new ( ) ;
283+ for ( dst, src_usage) in remapping. iter ( ) {
284+ if * dst == old_var {
285+ changes. push ( ( * dst, Some ( new_var) , * src_usage) ) ;
286+ } else if src_usage. var_id == old_var {
287+ let mut new_usage = * src_usage;
288+ new_usage. var_id = new_var;
289+ changes. push ( ( * dst, None , new_usage) ) ;
290+ }
291+ }
292+
293+ // Apply changes
294+ for ( old_key, new_key_opt, new_usage) in changes {
295+ if let Some ( new_key) = new_key_opt {
296+ // Key needs to change
297+ remapping. swap_remove ( & old_key) ;
298+ remapping. insert ( new_key, new_usage) ;
299+ } else {
300+ // Only value needs to change
301+ remapping. insert ( old_key, new_usage) ;
302+ }
303+ }
304+ }
305+ _ => { }
306+ }
307+ }
308+ }
309+
247310/// Creates a struct_boxed_deconstruct call statement.
248311/// Returns None if the call cannot be created.
249312fn create_struct_boxed_deconstruct_call < ' db > (
0 commit comments