Repository: gleam-lang/gleam (Rust)

Issue:
In a list destructuring (using `..`), LSP is not able to report correct types
I found a small issue in the LSP.

If I write this:
```gleam
fn test_() {
  [1, 2, 3, {
    let x = "bloup"
    let y = "bloup bloup"
    x <> y
    1
  }]
}
```

I can correctly hover over `x`, `y` or anything in the `{}` block. The LSP correctly gives types hint. 
But if I type:

```gleam
fn test_() {
  [1, 2, 3, ..{
    let x = "bloup"
    let y = "bloup bloup"
    x <> y
    [1]
  }]
}
```

Suddenly I cannot hover over anything in the `{}` block, the LSP only highlights the entire list and says `List(Int)`.

An example in Zed when I'm trying to hover over `y`:
![image](https://github.com/user-attachments/assets/c83a6ff1-9442-4f34-ad56-8586cc6335f1)



Discussion:
Thank you!



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 568d6b52a2e..45e89776377 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -297,6 +297,10 @@
   no arguments.
   ([Louis Pilfold](https://github.com/lpil))
 
+- Fixed a bug where the language server wouldn't show hints when hovering over
+  the tail of a list.
+  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
+
 ## v1.5.1 - 2024-09-26
 
 ### Bug Fixes
diff --git a/compiler-core/src/ast/typed.rs b/compiler-core/src/ast/typed.rs
index 7830660d073..aaf3240517c 100644
--- a/compiler-core/src/ast/typed.rs
+++ b/compiler-core/src/ast/typed.rs
@@ -221,9 +221,23 @@ impl TypedExpr {
             // beyond the index under search.
             Self::Tuple {
                 elems: expressions, ..
+            } => {
+                for expression in expressions {
+                    if expression.location().start > byte_index {
+                        break;
+                    }
+
+                    if let Some(located) = expression.find_node(byte_index) {
+                        return Some(located);
+                    }
+                }
+
+                self.self_if_contains_location(byte_index)
             }
-            | Self::List {
+
+            Self::List {
                 elements: expressions,
+                tail,
                 ..
             } => {
                 for expression in expressions {
@@ -236,6 +250,11 @@ impl TypedExpr {
                     }
                 }
 
+                if let Some(tail) = tail {
+                    if let Some(node) = tail.find_node(byte_index) {
+                        return Some(node);
+                    }
+                }
                 self.self_if_contains_location(byte_index)
             }
 


Test patch:
diff --git a/compiler-core/src/language_server/tests/hover.rs b/compiler-core/src/language_server/tests/hover.rs
index 9bc98cc6404..bd003c2d1c0 100644
--- a/compiler-core/src/language_server/tests/hover.rs
+++ b/compiler-core/src/language_server/tests/hover.rs
@@ -1241,3 +1241,18 @@ const value = True
         find_position_of("value").under_char('v')
     );
 }
+
+// https://github.com/gleam-lang/gleam/issues/3761
+#[test]
+fn hover_over_block_in_list_spread() {
+    let code = "
+pub fn main() {
+  [1, 2, ..{
+    let x = 1
+    [x]
+  }]
+}
+";
+
+    assert_hover!(TestProject::for_source(code), find_position_of("x"));
+}
diff --git a/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__hover__hover_over_block_in_list_spread.snap b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__hover__hover_over_block_in_list_spread.snap
new file mode 100644
index 00000000000..4b2751e0b9e
--- /dev/null
+++ b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__hover__hover_over_block_in_list_spread.snap
@@ -0,0 +1,19 @@
+---
+source: compiler-core/src/language_server/tests/hover.rs
+expression: "\npub fn main() {\n  [1, 2, ..{\n    let x = 1\n    [x]\n  }]\n}\n"
+---
+pub fn main() {
+  [1, 2, ..{
+    let x = 1
+        ↑    
+    [x]
+  }]
+}
+
+
+----- Hover content -----
+Scalar(
+    String(
+        "```gleam\nInt\n```\n",
+    ),
+)