@@ -165,12 +165,17 @@ impl<'a> FunctionContext<'a> {
165
165
166
166
// This helper is needed because we need to take f by mutable reference,
167
167
// otherwise we cannot move it multiple times each loop of vecmap.
168
- fn map_type_helper < T > ( typ : & ast:: Type , f : & mut impl FnMut ( Type ) -> T ) -> Tree < T > {
168
+ fn map_type_helper < T > ( typ : & ast:: Type , f : & mut dyn FnMut ( Type ) -> T ) -> Tree < T > {
169
169
match typ {
170
170
ast:: Type :: Tuple ( fields) => {
171
171
Tree :: Branch ( vecmap ( fields, |field| Self :: map_type_helper ( field, f) ) )
172
172
}
173
173
ast:: Type :: Unit => Tree :: empty ( ) ,
174
+ // A mutable reference wraps each element into a reference.
175
+ // This can be multiple values if the element type is a tuple.
176
+ ast:: Type :: MutableReference ( element) => {
177
+ Self :: map_type_helper ( element, & mut |_| f ( Type :: Reference ) )
178
+ }
174
179
other => Tree :: Leaf ( f ( Self :: convert_non_tuple_type ( other) ) ) ,
175
180
}
176
181
}
@@ -201,6 +206,11 @@ impl<'a> FunctionContext<'a> {
201
206
ast:: Type :: Unit => panic ! ( "convert_non_tuple_type called on a unit type" ) ,
202
207
ast:: Type :: Tuple ( _) => panic ! ( "convert_non_tuple_type called on a tuple: {typ}" ) ,
203
208
ast:: Type :: Function ( _, _) => Type :: Function ,
209
+ ast:: Type :: MutableReference ( element) => {
210
+ // Recursive call to panic if element is a tuple
211
+ Self :: convert_non_tuple_type ( element) ;
212
+ Type :: Reference
213
+ }
204
214
205
215
// How should we represent Vecs?
206
216
// Are they a struct of array + length + capacity?
@@ -473,9 +483,21 @@ impl<'a> FunctionContext<'a> {
473
483
let object_lvalue = Box :: new ( object_lvalue) ;
474
484
LValue :: MemberAccess { old_object, object_lvalue, index : * field_index }
475
485
}
486
+ ast:: LValue :: Dereference { reference, .. } => {
487
+ let ( reference, _) = self . extract_current_value_recursive ( reference) ;
488
+ LValue :: Dereference { reference }
489
+ }
476
490
}
477
491
}
478
492
493
+ pub ( super ) fn dereference ( & mut self , values : & Values , element_type : & ast:: Type ) -> Values {
494
+ let element_types = Self :: convert_type ( element_type) ;
495
+ values. map_both ( element_types, |value, element_type| {
496
+ let reference = value. eval ( self ) ;
497
+ self . builder . insert_load ( reference, element_type) . into ( )
498
+ } )
499
+ }
500
+
479
501
/// Compile the given identifier as a reference - ie. avoid calling .eval()
480
502
fn ident_lvalue ( & self , ident : & ast:: Ident ) -> Values {
481
503
match & ident. definition {
@@ -516,16 +538,19 @@ impl<'a> FunctionContext<'a> {
516
538
let element = Self :: get_field_ref ( & old_object, * index) . clone ( ) ;
517
539
( element, LValue :: MemberAccess { old_object, object_lvalue, index : * index } )
518
540
}
541
+ ast:: LValue :: Dereference { reference, element_type } => {
542
+ let ( reference, _) = self . extract_current_value_recursive ( reference) ;
543
+ let dereferenced = self . dereference ( & reference, element_type) ;
544
+ ( dereferenced, LValue :: Dereference { reference } )
545
+ }
519
546
}
520
547
}
521
548
522
549
/// Assigns a new value to the given LValue.
523
550
/// The LValue can be created via a previous call to extract_current_value.
524
551
/// This method recurs on the given LValue to create a new value to assign an allocation
525
- /// instruction within an LValue::Ident - see the comment on `extract_current_value` for more
526
- /// details.
527
- /// When first-class references are supported the nearest reference may be in any LValue
528
- /// variant rather than just LValue::Ident.
552
+ /// instruction within an LValue::Ident or LValue::Dereference - see the comment on
553
+ /// `extract_current_value` for more details.
529
554
pub ( super ) fn assign_new_value ( & mut self , lvalue : LValue , new_value : Values ) {
530
555
match lvalue {
531
556
LValue :: Ident ( references) => self . assign ( references, new_value) ,
@@ -538,6 +563,9 @@ impl<'a> FunctionContext<'a> {
538
563
let new_object = Self :: replace_field ( old_object, index, new_value) ;
539
564
self . assign_new_value ( * object_lvalue, new_object) ;
540
565
}
566
+ LValue :: Dereference { reference } => {
567
+ self . assign ( reference, new_value) ;
568
+ }
541
569
}
542
570
}
543
571
@@ -705,8 +733,10 @@ impl SharedContext {
705
733
}
706
734
707
735
/// Used to remember the results of each step of extracting a value from an ast::LValue
736
+ #[ derive( Debug ) ]
708
737
pub ( super ) enum LValue {
709
738
Ident ( Values ) ,
710
739
Index { old_array : ValueId , index : ValueId , array_lvalue : Box < LValue > } ,
711
740
MemberAccess { old_object : Values , index : usize , object_lvalue : Box < LValue > } ,
741
+ Dereference { reference : Values } ,
712
742
}
0 commit comments