Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide/src/hover/tests.rs42
-rw-r--r--crates/mbe/src/expander/transcriber.rs14
2 files changed, 55 insertions, 1 deletions
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 1ea11a215f..8bc0b3f6ab 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -4797,6 +4797,48 @@ fn main() {
}
#[test]
+fn const_generic_negative_literal_macro_expansion() {
+ // Test that negative literals work correctly in const generics
+ // when used through macro expansion. This ensures the transcriber
+ // doesn't wrap negative literals in parentheses, which would create
+ // invalid syntax like Foo::<(-1)> instead of Foo::<-1>.
+ check(
+ r#"
+struct Foo<const I: i16> {
+ pub value: i16,
+}
+
+impl<const I: i16> Foo<I> {
+ pub fn new(value: i16) -> Self {
+ Self { value }
+ }
+}
+
+macro_rules! create_foo {
+ ($val:expr) => {
+ Foo::<$val>::new($val)
+ };
+}
+
+fn main() {
+ let v$0alue = create_foo!(-1);
+}
+"#,
+ expect![[r#"
+ *value*
+
+ ```rust
+ let value: Foo<-1>
+ ```
+
+ ---
+
+ size = 2, align = 2, no Drop
+ "#]],
+ );
+}
+
+#[test]
fn hover_self_param_shows_type() {
check(
r#"
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 2c046df10f..3e4ab8bdc1 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -401,7 +401,19 @@ fn expand_var(
let sub = sub.strip_invisible();
let mut span = id;
marker(&mut span);
- let wrap_in_parens = !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
+
+ // Check if this is a simple negative literal (MINUS + LITERAL)
+ // that should not be wrapped in parentheses
+ let is_negative_literal = matches!(
+ sub.flat_tokens(),
+ [
+ tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '-', .. })),
+ tt::TokenTree::Leaf(tt::Leaf::Literal(_))
+ ]
+ );
+
+ let wrap_in_parens = !is_negative_literal
+ && !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
&& sub.try_into_subtree().is_none_or(|it| {
it.top_subtree().delimiter.kind == tt::DelimiterKind::Invisible
});