@@ -498,7 +498,7 @@ pub(crate) fn eval_up_to(
498
498
// destructuring tuple, we want to return the tuple element and
499
499
// position.
500
500
501
- match item {
501
+ let mut res = match item {
502
502
ToplevelItem :: Def ( def) => match & def. 2 {
503
503
Definition_ :: Fun ( name_sym, fun_info) => {
504
504
eval_toplevel_defs ( & [ item. clone ( ) ] , env) ;
@@ -564,7 +564,79 @@ pub(crate) fn eval_up_to(
564
564
Err ( e) => Some ( Err ( e) ) ,
565
565
}
566
566
}
567
+ } ;
568
+
569
+ // If the user asked for a single position in a tuple
570
+ // destructuring, handle it here.
571
+ if let Some ( Ok ( ( value, pos) ) ) = & mut res {
572
+ if let Some ( ( var_value, var_pos) ) = let_var_pos ( value, items, & syn_ids) {
573
+ * value = var_value;
574
+ * pos = var_pos;
575
+ }
576
+ }
577
+
578
+ res
579
+ }
580
+
581
+ /// If the AstId corresponded to a let variable or a destructuring let
582
+ /// variable, return the inner value and position.
583
+ ///
584
+ /// ```garden
585
+ /// let (x, y) = (1, 2)
586
+ /// // ^
587
+ /// ```
588
+ ///
589
+ /// In this example, we want the position to be the position of `y`,
590
+ /// and the value to be `2`, not `(1, 2)`.
591
+ fn let_var_pos (
592
+ value : & Value ,
593
+ items : & [ ToplevelItem ] ,
594
+ ast_ids : & [ AstId ] ,
595
+ ) -> Option < ( Value , Position ) > {
596
+ let innermost_id = ast_ids. last ( ) ?;
597
+
598
+ for syn_id in ast_ids. iter ( ) . rev ( ) {
599
+ let Some ( expr) = find_expr_of_id ( items, syn_id. id ( ) ) else {
600
+ continue ;
601
+ } ;
602
+
603
+ let Expression_ :: Let ( let_dest, _, _) = & expr. expr_ else {
604
+ continue ;
605
+ } ;
606
+
607
+ match let_dest {
608
+ LetDestination :: Symbol ( symbol) => {
609
+ if & AstId :: Sym ( symbol. id ) != innermost_id {
610
+ return None ;
611
+ }
612
+
613
+ return Some ( ( value. clone ( ) , symbol. position . clone ( ) ) ) ;
614
+ }
615
+ LetDestination :: Destructure ( symbols) => {
616
+ let mut matching_sym_i: Option < usize > = None ;
617
+ for ( i, symbol) in symbols. iter ( ) . enumerate ( ) {
618
+ if & AstId :: Sym ( symbol. id ) == innermost_id {
619
+ matching_sym_i = Some ( i) ;
620
+ break ;
621
+ }
622
+ }
623
+ let matching_sym_i = matching_sym_i?;
624
+
625
+ match value {
626
+ Value :: Tuple { items, .. } => {
627
+ let tuple_item = items. get ( matching_sym_i) ?;
628
+ return Some ( (
629
+ tuple_item. clone ( ) ,
630
+ symbols[ matching_sym_i] . position . clone ( ) ,
631
+ ) ) ;
632
+ }
633
+ _ => return None ,
634
+ }
635
+ }
636
+ } ;
567
637
}
638
+
639
+ None
568
640
}
569
641
570
642
/// Helper for starting evaluation with a function call. Used when
0 commit comments