diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:29 +0000 |
commit | 631cd5845e8de329d0e227aaa707d7ea228b8f8f (patch) | |
tree | a1b87c8f8cad01cf18f7c5f57a08f102771ed303 /src/tools/rust-analyzer/crates/ide | |
parent | Adding debian version 1.69.0+dfsg1-1. (diff) | |
download | rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.tar.xz rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide')
29 files changed, 1145 insertions, 297 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index b4a7f2b91..fae25f310 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -107,7 +107,18 @@ pub(crate) fn remove_links(markdown: &str) -> String { out } -/// Retrieve a link to documentation for the given symbol. +// Feature: Open Docs +// +// Retrieve a link to documentation for the given symbol. +// +// The simplest way to use this feature is via the context menu. Right-click on +// the selected item. The context menu opens. Select **Open Docs**. +// +// |=== +// | Editor | Action Name +// +// | VS Code | **rust-analyzer: Open Docs** +// |=== pub(crate) fn external_docs( db: &RootDatabase, position: &FilePosition, @@ -181,6 +192,7 @@ pub(crate) fn resolve_doc_path_for_def( Definition::Const(it) => it.resolve_doc_path(db, link, ns), Definition::Static(it) => it.resolve_doc_path(db, link, ns), Definition::Trait(it) => it.resolve_doc_path(db, link, ns), + Definition::TraitAlias(it) => it.resolve_doc_path(db, link, ns), Definition::TypeAlias(it) => it.resolve_doc_path(db, link, ns), Definition::Macro(it) => it.resolve_doc_path(db, link, ns), Definition::Field(it) => it.resolve_doc_path(db, link, ns), @@ -493,6 +505,7 @@ fn filename_and_frag_for_def( None => String::from("index.html"), }, Definition::Trait(t) => format!("trait.{}.html", t.name(db)), + Definition::TraitAlias(t) => format!("traitalias.{}.html", t.name(db)), Definition::TypeAlias(t) => format!("type.{}.html", t.name(db)), Definition::BuiltinType(t) => format!("primitive.{}.html", t.name()), Definition::Function(f) => format!("fn.{}.html", f.name(db)), diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index b23763dce..a32ac3549 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -149,6 +149,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { ast::Enum(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Enum)), ast::Variant(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Variant)), ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)), + ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)), ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)), ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)), ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)), @@ -262,6 +263,8 @@ enum E { X, Y(i32) } type T = (); static S: i32 = 92; const C: i32 = 92; +trait Tr {} +trait Alias = Tr; impl E {} @@ -459,9 +462,31 @@ fn g() {} }, StructureNode { parent: None, + label: "Tr", + navigation_range: 239..241, + node_range: 233..244, + kind: SymbolKind( + Trait, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "Alias", + navigation_range: 251..256, + node_range: 245..262, + kind: SymbolKind( + TraitAlias, + ), + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, label: "impl E", - navigation_range: 239..240, - node_range: 234..243, + navigation_range: 269..270, + node_range: 264..273, kind: SymbolKind( Impl, ), @@ -471,8 +496,8 @@ fn g() {} StructureNode { parent: None, label: "impl fmt::Debug for E", - navigation_range: 265..266, - node_range: 245..269, + navigation_range: 295..296, + node_range: 275..299, kind: SymbolKind( Impl, ), @@ -482,8 +507,8 @@ fn g() {} StructureNode { parent: None, label: "mc", - navigation_range: 284..286, - node_range: 271..303, + navigation_range: 314..316, + node_range: 301..333, kind: SymbolKind( Macro, ), @@ -493,8 +518,8 @@ fn g() {} StructureNode { parent: None, label: "mcexp", - navigation_range: 334..339, - node_range: 305..356, + navigation_range: 364..369, + node_range: 335..386, kind: SymbolKind( Macro, ), @@ -504,8 +529,8 @@ fn g() {} StructureNode { parent: None, label: "mcexp", - navigation_range: 387..392, - node_range: 358..409, + navigation_range: 417..422, + node_range: 388..439, kind: SymbolKind( Macro, ), @@ -515,8 +540,8 @@ fn g() {} StructureNode { parent: None, label: "obsolete", - navigation_range: 428..436, - node_range: 411..441, + navigation_range: 458..466, + node_range: 441..471, kind: SymbolKind( Function, ), @@ -528,8 +553,8 @@ fn g() {} StructureNode { parent: None, label: "very_obsolete", - navigation_range: 481..494, - node_range: 443..499, + navigation_range: 511..524, + node_range: 473..529, kind: SymbolKind( Function, ), @@ -541,8 +566,8 @@ fn g() {} StructureNode { parent: None, label: "Some region name", - navigation_range: 501..528, - node_range: 501..528, + navigation_range: 531..558, + node_range: 531..558, kind: Region, detail: None, deprecated: false, @@ -550,8 +575,8 @@ fn g() {} StructureNode { parent: None, label: "m", - navigation_range: 568..569, - node_range: 543..606, + navigation_range: 598..599, + node_range: 573..636, kind: SymbolKind( Module, ), @@ -560,22 +585,22 @@ fn g() {} }, StructureNode { parent: Some( - 20, + 22, ), label: "dontpanic", - navigation_range: 543..563, - node_range: 543..563, + navigation_range: 573..593, + node_range: 573..593, kind: Region, detail: None, deprecated: false, }, StructureNode { parent: Some( - 20, + 22, ), label: "f", - navigation_range: 575..576, - node_range: 572..581, + navigation_range: 605..606, + node_range: 602..611, kind: SymbolKind( Function, ), @@ -586,11 +611,11 @@ fn g() {} }, StructureNode { parent: Some( - 20, + 22, ), label: "g", - navigation_range: 598..599, - node_range: 582..604, + navigation_range: 628..629, + node_range: 612..634, kind: SymbolKind( Function, ), diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 93019527f..cf0819a25 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -766,6 +766,13 @@ trait Foo$0 { } check( r#" +trait Foo$0 = ; + //^^^ +"#, + ); + + check( + r#" mod bar$0 { } //^^^ "#, @@ -1066,6 +1073,23 @@ fn f() -> impl Sub<Item$0 = u8> {} } #[test] + fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() { + check( + r#" +mod bar { + pub struct Foo {} + //^^^ + pub fn Foo() {} +} + +fn baz() { + let _foo_enum: bar::Foo$0 = bar::Foo {}; +} + "#, + ) + } + + #[test] fn unknown_assoc_ty() { check_unresolved( r#" @@ -1406,7 +1430,6 @@ include!("included.rs$0"); ); } - #[cfg(test)] mod goto_impl_of_trait_fn { use super::check; #[test] diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index 190ab80ba..a1a119629 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -297,6 +297,7 @@ impl Foo<str> {} //- /lib.rs crate:main deps:core fn foo(_: bool$0) {{}} //- /libcore.rs crate:core +#![rustc_coherence_is_core] #[lang = "bool"] impl bool {} //^^^^ diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index 55cdb3200..6d2d0bd63 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -55,7 +55,7 @@ pub(crate) fn goto_type_definition( ty } else { let record_field = ast::RecordPatField::for_field_name_ref(&it)?; - sema.resolve_record_pat_field(&record_field)?.ty(db) + sema.resolve_record_pat_field(&record_field)?.1 } }, _ => return None, diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index c889eb930..d88ffd25c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -14,7 +14,7 @@ use syntax::{ SyntaxNode, SyntaxToken, TextRange, T, }; -use crate::{references, NavigationTarget, TryToNav}; +use crate::{navigation_target::ToNav, references, NavigationTarget, TryToNav}; #[derive(PartialEq, Eq, Hash)] pub struct HighlightedRange { @@ -98,32 +98,39 @@ fn highlight_references( category: access, }); let mut res = FxHashSet::default(); - - let mut def_to_hl_range = |def| { - let hl_range = match def { - Definition::Module(module) => { - Some(NavigationTarget::from_module_to_decl(sema.db, module)) - } - def => def.try_to_nav(sema.db), - } - .filter(|decl| decl.file_id == file_id) - .and_then(|decl| decl.focus_range) - .map(|range| { - let category = - references::decl_mutability(&def, node, range).then_some(ReferenceCategory::Write); - HighlightedRange { range, category } - }); - if let Some(hl_range) = hl_range { - res.insert(hl_range); - } - }; for &def in &defs { match def { - Definition::Local(local) => local - .associated_locals(sema.db) - .iter() - .for_each(|&local| def_to_hl_range(Definition::Local(local))), - def => def_to_hl_range(def), + Definition::Local(local) => { + let category = local.is_mut(sema.db).then_some(ReferenceCategory::Write); + local + .sources(sema.db) + .into_iter() + .map(|x| x.to_nav(sema.db)) + .filter(|decl| decl.file_id == file_id) + .filter_map(|decl| decl.focus_range) + .map(|range| HighlightedRange { range, category }) + .for_each(|x| { + res.insert(x); + }); + } + def => { + let hl_range = match def { + Definition::Module(module) => { + Some(NavigationTarget::from_module_to_decl(sema.db, module)) + } + def => def.try_to_nav(sema.db), + } + .filter(|decl| decl.file_id == file_id) + .and_then(|decl| decl.focus_range) + .map(|range| { + let category = references::decl_mutability(&def, node, range) + .then_some(ReferenceCategory::Write); + HighlightedRange { range, category } + }); + if let Some(hl_range) = hl_range { + res.insert(hl_range); + } + } } } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 5f2c61f5b..64b2221bd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -30,6 +30,7 @@ pub struct HoverConfig { pub documentation: bool, pub keywords: bool, pub format: HoverDocFormat, + pub interpret_tests: bool, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 22611cfb8..da725ce50 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -3,7 +3,8 @@ use std::fmt::Display; use either::Either; use hir::{ - Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo, + db::DefDatabase, Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, + MirEvalError, Semantics, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, @@ -402,7 +403,20 @@ pub(super) fn definition( )) }), Definition::Module(it) => label_and_docs(db, it), - Definition::Function(it) => label_and_docs(db, it), + Definition::Function(it) => label_and_layout_info_and_docs(db, it, |_| { + if !config.interpret_tests { + return None; + } + match it.eval(db) { + Ok(()) => Some("pass".into()), + Err(MirEvalError::Panic) => Some("fail".into()), + Err(MirEvalError::MirLowerError(f, e)) => { + let name = &db.function_data(f).name; + Some(format!("error: fail to lower {name} due {e:?}")) + } + Err(e) => Some(format!("error: {e:?}")), + } + }), Definition::Adt(it) => label_and_layout_info_and_docs(db, it, |&it| { let layout = it.layout(db).ok()?; Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes())) @@ -410,7 +424,7 @@ pub(super) fn definition( Definition::Variant(it) => label_value_and_docs(db, it, |&it| { if !it.parent_enum(db).is_data_carrying(db) { match it.eval(db) { - Ok(x) => Some(format!("{x}")), + Ok(x) => Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }), Err(_) => it.value(db).map(|x| format!("{x:?}")), } } else { @@ -418,9 +432,9 @@ pub(super) fn definition( } }), Definition::Const(it) => label_value_and_docs(db, it, |it| { - let body = it.eval(db); + let body = it.render_eval(db); match body { - Ok(x) => Some(format!("{x}")), + Ok(x) => Some(x), Err(_) => { let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); @@ -440,6 +454,7 @@ pub(super) fn definition( Some(body.to_string()) }), Definition::Trait(it) => label_and_docs(db, it), + Definition::TraitAlias(it) => label_and_docs(db, it), Definition::TypeAlias(it) => label_and_docs(db, it), Definition::BuiltinType(it) => { return famous_defs @@ -620,8 +635,8 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> { let ty = it.ty(db); let ty = ty.display_truncated(db, None); let is_mut = if it.is_mut(db) { "mut " } else { "" }; - let desc = match it.source(db).value { - Either::Left(ident) => { + let desc = match it.primary_source(db).into_ident_pat() { + Some(ident) => { let name = it.name(db); let let_kw = if ident .syntax() @@ -634,7 +649,7 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> { }; format!("{let_kw}{is_mut}{name}: {ty}") } - Either::Right(_) => format!("{is_mut}self: {ty}"), + None => format!("{is_mut}self: {ty}"), }; markup(None, desc, None) } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index bd7ce2f1d..57bf0f9ad 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -4,16 +4,19 @@ use syntax::TextRange; use crate::{fixture, HoverConfig, HoverDocFormat}; +const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { + links_in_hover: false, + documentation: true, + format: HoverDocFormat::Markdown, + keywords: true, + interpret_tests: false, +}; + fn check_hover_no_result(ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { - links_in_hover: true, - documentation: true, - keywords: true, - format: HoverDocFormat::Markdown, - }, + &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap(); @@ -25,12 +28,7 @@ fn check(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { - links_in_hover: true, - documentation: true, - keywords: true, - format: HoverDocFormat::Markdown, - }, + &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -47,12 +45,7 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( - &HoverConfig { - links_in_hover: false, - documentation: true, - keywords: true, - format: HoverDocFormat::Markdown, - }, + &HOVER_BASE_CONFIG, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) .unwrap() @@ -71,9 +64,8 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { .hover( &HoverConfig { links_in_hover: true, - documentation: true, - keywords: true, format: HoverDocFormat::PlainText, + ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, ) @@ -91,12 +83,7 @@ fn check_actions(ra_fixture: &str, expect: Expect) { let (analysis, file_id, position) = fixture::range_or_position(ra_fixture); let hover = analysis .hover( - &HoverConfig { - links_in_hover: true, - documentation: true, - keywords: true, - format: HoverDocFormat::Markdown, - }, + &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, FileRange { file_id, range: position.range_or_empty() }, ) .unwrap() @@ -106,34 +93,13 @@ fn check_actions(ra_fixture: &str, expect: Expect) { fn check_hover_range(ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { - links_in_hover: false, - documentation: true, - keywords: true, - format: HoverDocFormat::Markdown, - }, - range, - ) - .unwrap() - .unwrap(); + let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap().unwrap(); expect.assert_eq(hover.info.markup.as_str()) } fn check_hover_range_no_results(ra_fixture: &str) { let (analysis, range) = fixture::range(ra_fixture); - let hover = analysis - .hover( - &HoverConfig { - links_in_hover: false, - documentation: true, - keywords: true, - format: HoverDocFormat::Markdown, - }, - range, - ) - .unwrap(); + let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap(); assert!(hover.is_none()); } @@ -490,7 +456,6 @@ fn hover_field_offset() { // Hovering over the field when instantiating check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 } "#, expect![[r#" @@ -512,7 +477,6 @@ fn hover_shows_struct_field_info() { // Hovering over the field when instantiating check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 struct Foo { field_a: u32 } fn main() { @@ -535,7 +499,6 @@ fn main() { // Hovering over the field in the definition check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 struct Foo { field_a$0: u32 } fn main() { @@ -611,6 +574,27 @@ const foo$0: u32 = { } #[test] +fn hover_eval_complex_constants() { + check( + r#" + struct X { f1: (), f2: i32 } + const foo$0: (i8, X, i64) = (1, X { f2: 5 - 1, f1: () }, 1 - 2); + "#, + expect![[r#" + *foo* + + ```rust + test + ``` + + ```rust + const foo: (i8, X, i64) = (1, X { f1: (), f2: 4 }, -1) + ``` + "#]], + ); +} + +#[test] fn hover_default_generic_types() { check( r#" @@ -1467,8 +1451,6 @@ fn my() {} fn test_hover_struct_doc_comment() { check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 - /// This is an example /// multiline doc /// @@ -1527,7 +1509,7 @@ fn foo() { let bar = Ba$0r; } ``` ```rust - struct Bar + struct Bar // size = 0, align = 1 ``` --- @@ -1556,7 +1538,7 @@ fn foo() { let bar = Ba$0r; } ``` ```rust - struct Bar + struct Bar // size = 0, align = 1 ``` --- @@ -1584,7 +1566,7 @@ pub struct B$0ar ``` ```rust - pub struct Bar + pub struct Bar // size = 0, align = 1 ``` --- @@ -1611,7 +1593,7 @@ pub struct B$0ar ``` ```rust - pub struct Bar + pub struct Bar // size = 0, align = 1 ``` --- @@ -2913,8 +2895,6 @@ fn main() { let foo_test = name_with_dashes::wrapper::Thing::new$0(); } fn hover_field_pat_shorthand_ref_match_ergonomics() { check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 - struct S { f: i32, } @@ -3506,8 +3486,8 @@ impl<const LEN: usize> Foo<LEN$0> {} } #[test] -fn hover_const_eval_variant() { - // show hex for <10 +fn hover_const_eval_discriminant() { + // Don't show hex for <10 check( r#" #[repr(u8)] @@ -3532,7 +3512,7 @@ enum E { This is a doc "#]], ); - // show hex for >10 + // Show hex for >10 check( r#" #[repr(u8)] @@ -3656,7 +3636,7 @@ trait T { } impl T for i32 { const AA: A = A { - i: 2 + i: 2 + 3 } } fn main() { @@ -3671,9 +3651,7 @@ fn main() { ``` ```rust - const AA: A = A { - i: 2 - } + const AA: A = A { i: 5 } ``` "#]], ); @@ -3792,7 +3770,6 @@ const FOO$0: usize = 1 << 3; This is a doc "#]], ); - // show hex for >10 check( r#" /// This is a doc @@ -3850,7 +3827,7 @@ const FOO$0: i32 = 2 - 3; ``` ```rust - const FOO: i32 = -1 + const FOO: i32 = -1 (0xFFFFFFFF) ``` --- @@ -4011,6 +3988,28 @@ const FOO$0: f32 = 1f32; This is a doc "#]], ); + // Don't show `<ref-not-supported>` in const hover + check( + r#" +/// This is a doc +const FOO$0: &i32 = &2; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: &i32 = &2 + ``` + + --- + + This is a doc + "#]], + ); //show f64 typecasted from float check( r#" @@ -4354,8 +4353,6 @@ fn main() { fn hover_intra_doc_links() { check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 - pub mod theitem { /// This is the item. Cool! pub struct TheItem; @@ -4496,7 +4493,7 @@ trait A where fn string_shadowed_with_inner_items() { check( r#" -//- /main.rs crate:main deps:alloc target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 +//- /main.rs crate:main deps:alloc /// Custom `String` type. struct String; @@ -5191,7 +5188,7 @@ foo_macro!( ``` ```rust - pub struct Foo + pub struct Foo // size = 0, align = 1 ``` --- @@ -5205,8 +5202,6 @@ foo_macro!( fn hover_intra_in_attr() { check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 - #[doc = "Doc comment for [`Foo$0`]"] pub struct Foo(i32); "#, @@ -5295,7 +5290,7 @@ pub struct Type; ``` ```rust - const KONST: dep::Type = $crate::Type + const KONST: dep::Type = Type ``` "#]], ); @@ -5327,8 +5322,6 @@ enum Enum { fn hover_record_variant_field() { check( r#" -//- /main.rs target_data_layout:e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128 - enum Enum { RecordV { field$0: u32 } } @@ -5647,3 +5640,204 @@ fn main() { "#]], ); } + +#[test] +fn assoc_fn_in_block_local_impl() { + check( + r#" +struct S; +mod m { + const _: () = { + impl crate::S { + pub(crate) fn foo() {} + } + }; +} +fn test() { + S::foo$0(); +} +"#, + expect![[r#" + *foo* + + ```rust + test::S + ``` + + ```rust + pub(crate) fn foo() + ``` + "#]], + ); + + check( + r#" +struct S; +mod m { + const _: () = { + const _: () = { + impl crate::S { + pub(crate) fn foo() {} + } + }; + }; +} +fn test() { + S::foo$0(); +} +"#, + expect![[r#" + *foo* + + ```rust + test::S + ``` + + ```rust + pub(crate) fn foo() + ``` + "#]], + ); + + check( + r#" +struct S; +mod m { + mod inner { + const _: () = { + impl crate::S { + pub(super) fn foo() {} + } + }; + } + + fn test() { + crate::S::foo$0(); + } +} +"#, + expect![[r#" + *foo* + + ```rust + test::S + ``` + + ```rust + pub(super) fn foo() + ``` + "#]], + ); +} + +#[test] +fn assoc_const_in_block_local_impl() { + check( + r#" +struct S; +mod m { + const _: () = { + impl crate::S { + pub(crate) const A: () = (); + } + }; +} +fn test() { + S::A$0; +} +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + pub(crate) const A: () = () + ``` + "#]], + ); + + check( + r#" +struct S; +mod m { + const _: () = { + const _: () = { + impl crate::S { + pub(crate) const A: () = (); + } + }; + }; +} +fn test() { + S::A$0; +} +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + pub(crate) const A: () = () + ``` + "#]], + ); + + check( + r#" +struct S; +mod m { + mod inner { + const _: () = { + impl crate::S { + pub(super) const A: () = (); + } + }; + } + + fn test() { + crate::S::A$0; + } +} +"#, + expect![[r#" + *A* + + ```rust + test + ``` + + ```rust + pub(super) const A: () = () + ``` + "#]], + ); +} + +#[test] +fn field_as_method_call_fallback() { + check( + r#" +struct S { f: u32 } +fn test() { + S { f: 0 }.f$0(); +} +"#, + expect![[r#" + *f* + + ```rust + test::S + ``` + + ```rust + f: u32 // size = 4, align = 4, offset = 0 + ``` + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 188eb7f97..46505b304 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -31,19 +31,31 @@ pub(super) fn hints( return None; } - // These inherit from the inner expression which would result in duplicate hints - if let ast::Expr::ParenExpr(_) - | ast::Expr::IfExpr(_) - | ast::Expr::BlockExpr(_) - | ast::Expr::MatchExpr(_) = expr - { + // ParenExpr resolve to their contained expressions HIR so they will dupe these hints + if let ast::Expr::ParenExpr(_) = expr { return None; } + if let ast::Expr::BlockExpr(b) = expr { + if !b.is_standalone() { + return None; + } + } let descended = sema.descend_node_into_attributes(expr.clone()).pop(); let desc_expr = descended.as_ref().unwrap_or(expr); let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; + if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr { + if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] = + &*adjustments + { + // Don't show unnecessary reborrows for these, they will just repeat the inner ones again + if source == target { + return None; + } + } + } + let (postfix, needs_outer_parens, needs_inner_parens) = mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode); @@ -67,6 +79,7 @@ pub(super) fn hints( for Adjustment { source, target, kind } in iter { if source == target { + cov_mark::hit!(same_type_adjustment); continue; } @@ -251,7 +264,7 @@ mod tests { check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn +//- minicore: coerce_unsized, fn, eq fn main() { let _: u32 = loop {}; //^^^^^^^<never-to-any> @@ -332,7 +345,7 @@ fn main() { loop {} //^^^^^^^<never-to-any> }; - let _: &mut [u32] = match () { () => &mut [] } + let _: &mut [u32] = match () { () => &mut [] }; //^^^^^^^<unsize> //^^^^^^^&mut $ //^^^^^^^* @@ -341,6 +354,12 @@ fn main() { //^^^^^^^^^^<unsize> //^^^^^^^^^^&mut $ //^^^^^^^^^^* + () == (); + // ^^& + // ^^& + (()) == {()}; + // ^^& + // ^^^^& } #[derive(Copy, Clone)] @@ -363,7 +382,7 @@ impl Struct { ..DISABLED_CONFIG }, r#" -//- minicore: coerce_unsized, fn +//- minicore: coerce_unsized, fn, eq fn main() { Struct.consume(); @@ -419,7 +438,7 @@ fn main() { loop {} //^^^^^^^.<never-to-any> }; - let _: &mut [u32] = match () { () => &mut [] } + let _: &mut [u32] = match () { () => &mut [] }; //^^^^^^^( //^^^^^^^) //^^^^^^^.* @@ -432,6 +451,12 @@ fn main() { //^^^^^^^^^^.* //^^^^^^^^^^.&mut //^^^^^^^^^^.<unsize> + () == (); + // ^^.& + // ^^.& + (()) == {()}; + // ^^.& + // ^^^^.& } #[derive(Copy, Clone)] @@ -499,6 +524,7 @@ fn main() { #[test] fn never_to_never_is_never_shown() { + cov_mark::check!(same_type_adjustment); check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" @@ -606,14 +632,13 @@ fn a() { } #[test] - fn bug() { + fn let_stmt_explicit_ty() { check_with_config( InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, r#" fn main() { - // These should be identical, but they are not... - let () = return; + //^^^^^^<never-to-any> let (): () = return; //^^^^^^<never-to-any> } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 4af7f9bdb..6a5092733 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -176,15 +176,12 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir mod tests { // This module also contains tests for super::closure_ret - use expect_test::expect; use syntax::{TextRange, TextSize}; use test_utils::extract_annotations; use crate::{fixture, inlay_hints::InlayHintsConfig}; - use crate::inlay_hints::tests::{ - check, check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG, - }; + use crate::inlay_hints::tests::{check, check_with_config, DISABLED_CONFIG, TEST_CONFIG}; use crate::ClosureReturnTypeHints; #[track_caller] @@ -278,8 +275,7 @@ fn main() { #[test] fn iterator_hint_regression_issue_12674() { // Ensure we don't crash while solving the projection type of iterators. - check_expect( - InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, + let (analysis, file_id) = fixture::file( r#" //- minicore: iterators struct S<T>(T); @@ -302,107 +298,18 @@ impl<'a, T> Iterator for SliceIter<'a, T> { fn main(a: SliceIter<'_, Container>) { a - .filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v)))) - .map(|e| e); + .filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v)))) + .map(|e| e); } - "#, - expect![[r#" - [ - InlayHint { - range: 484..554, - kind: Chaining, - label: [ - "impl ", - InlayHintLabelPart { - text: "Iterator", - linked_location: Some( - FileRange { - file_id: FileId( - 1, - ), - range: 2611..2619, - }, - ), - tooltip: "", - }, - "<", - InlayHintLabelPart { - text: "Item", - linked_location: Some( - FileRange { - file_id: FileId( - 1, - ), - range: 2643..2647, - }, - ), - tooltip: "", - }, - " = impl ", - InlayHintLabelPart { - text: "Iterator", - linked_location: Some( - FileRange { - file_id: FileId( - 1, - ), - range: 2611..2619, - }, - ), - tooltip: "", - }, - "<", - InlayHintLabelPart { - text: "Item", - linked_location: Some( - FileRange { - file_id: FileId( - 1, - ), - range: 2643..2647, - }, - ), - tooltip: "", - }, - " = &&str>>", - ], - }, - InlayHint { - range: 484..485, - kind: Chaining, - label: [ - "", - InlayHintLabelPart { - text: "SliceIter", - linked_location: Some( - FileRange { - file_id: FileId( - 0, - ), - range: 289..298, - }, - ), - tooltip: "", - }, - "<", - InlayHintLabelPart { - text: "Container", - linked_location: Some( - FileRange { - file_id: FileId( - 0, - ), - range: 238..247, - }, - ), - tooltip: "", - }, - ">", - ], - }, - ] - "#]], +"#, ); + analysis + .inlay_hints( + &InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, + file_id, + None, + ) + .unwrap(); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index 0c54f084c..1e1771259 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -435,7 +435,7 @@ fn main() { file_id: FileId( 1, ), - range: 2611..2619, + range: 3415..3423, }, ), tooltip: "", @@ -448,7 +448,7 @@ fn main() { file_id: FileId( 1, ), - range: 2643..2647, + range: 3447..3451, }, ), tooltip: "", @@ -468,7 +468,7 @@ fn main() { file_id: FileId( 1, ), - range: 2611..2619, + range: 3415..3423, }, ), tooltip: "", @@ -481,7 +481,7 @@ fn main() { file_id: FileId( 1, ), - range: 2643..2647, + range: 3447..3451, }, ), tooltip: "", @@ -501,7 +501,7 @@ fn main() { file_id: FileId( 1, ), - range: 2611..2619, + range: 3415..3423, }, ), tooltip: "", @@ -514,7 +514,7 @@ fn main() { file_id: FileId( 1, ), - range: 2643..2647, + range: 3447..3451, }, ), tooltip: "", diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index 5dd51ad11..67eaa553a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -59,8 +59,14 @@ fn variant_hints( }, kind: InlayKind::Discriminant, label: InlayHintLabel::simple( - match &d { - Ok(v) => format!("{}", v), + match d { + Ok(x) => { + if x >= 10 { + format!("{x} ({x:#X})") + } else { + format!("{x}") + } + } Err(_) => "?".into(), }, Some(InlayTooltip::String(match &d { diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index f2b535bdc..078b66dd3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -55,6 +55,7 @@ mod syntax_tree; mod typing; mod view_crate_graph; mod view_hir; +mod view_mir; mod view_item_tree; mod shuffle_crate_graph; @@ -308,6 +309,10 @@ impl Analysis { self.with_db(|db| view_hir::view_hir(db, position)) } + pub fn view_mir(&self, position: FilePosition) -> Cancellable<String> { + self.with_db(|db| view_mir::view_mir(db, position)) + } + pub fn view_item_tree(&self, file_id: FileId) -> Cancellable<String> { self.with_db(|db| view_item_tree::view_item_tree(db, file_id)) } diff --git a/src/tools/rust-analyzer/crates/ide/src/markup.rs b/src/tools/rust-analyzer/crates/ide/src/markup.rs index de9fef61a..411eb695f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/markup.rs +++ b/src/tools/rust-analyzer/crates/ide/src/markup.rs @@ -32,7 +32,7 @@ impl Markup { pub fn as_str(&self) -> &str { self.text.as_str() } - pub fn fenced_block(contents: &impl fmt::Display) -> Markup { + pub fn fenced_block(contents: impl fmt::Display) -> Markup { format!("```rust\n{contents}\n```").into() } } diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index af5e96d23..349e79ecf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -208,6 +208,9 @@ pub(crate) fn def_to_moniker( Definition::Trait(trait_) => { MonikerDescriptor { name: trait_.name(db), desc: MonikerDescriptorKind::Type } } + Definition::TraitAlias(ta) => { + MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::Type } + } Definition::TypeAlias(ta) => { MonikerDescriptor { name: ta.name(db), desc: MonikerDescriptorKind::TypeParameter } } diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs index ffc4bdd7d..b955ea99f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs +++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs @@ -73,6 +73,7 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) - SyntaxKind::MACRO_CALL, SyntaxKind::TYPE_ALIAS, SyntaxKind::TRAIT, + SyntaxKind::TRAIT_ALIAS, SyntaxKind::IMPL, SyntaxKind::MACRO_DEF, SyntaxKind::STRUCT, diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 3aa799d43..6aae82f98 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -5,7 +5,7 @@ use std::fmt; use either::Either; use hir::{ symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, - InFile, ModuleSource, Semantics, + InFile, LocalSource, ModuleSource, Semantics, }; use ide_db::{ base_db::{FileId, FileRange}, @@ -192,6 +192,7 @@ impl TryToNav for Definition { Definition::Const(it) => it.try_to_nav(db), Definition::Static(it) => it.try_to_nav(db), Definition::Trait(it) => it.try_to_nav(db), + Definition::TraitAlias(it) => it.try_to_nav(db), Definition::TypeAlias(it) => it.try_to_nav(db), Definition::BuiltinType(_) => None, Definition::ToolModule(_) => None, @@ -212,6 +213,7 @@ impl TryToNav for hir::ModuleDef { hir::ModuleDef::Const(it) => it.try_to_nav(db), hir::ModuleDef::Static(it) => it.try_to_nav(db), hir::ModuleDef::Trait(it) => it.try_to_nav(db), + hir::ModuleDef::TraitAlias(it) => it.try_to_nav(db), hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), hir::ModuleDef::Macro(it) => it.try_to_nav(db), hir::ModuleDef::BuiltinType(_) => None, @@ -249,6 +251,9 @@ impl ToNavFromAst for hir::TypeAlias { impl ToNavFromAst for hir::Trait { const KIND: SymbolKind = SymbolKind::Trait; } +impl ToNavFromAst for hir::TraitAlias { + const KIND: SymbolKind = SymbolKind::TraitAlias; +} impl<D> TryToNav for D where @@ -382,9 +387,11 @@ impl TryToNav for hir::GenericParam { } } -impl ToNav for hir::Local { +impl ToNav for LocalSource { fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { - let InFile { file_id, value } = self.source(db); + let InFile { file_id, value } = &self.source; + let file_id = *file_id; + let local = self.local; let (node, name) = match &value { Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()), Either::Right(it) => (it.syntax(), it.name()), @@ -393,10 +400,10 @@ impl ToNav for hir::Local { let FileRange { file_id, range: full_range } = InFile::new(file_id, node).original_file_range(db); - let name = self.name(db).to_smol_str(); - let kind = if self.is_self(db) { + let name = local.name(db).to_smol_str(); + let kind = if local.is_self(db) { SymbolKind::SelfParam - } else if self.is_param(db) { + } else if local.is_param(db) { SymbolKind::ValueParam } else { SymbolKind::Local @@ -414,6 +421,12 @@ impl ToNav for hir::Local { } } +impl ToNav for hir::Local { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + self.primary_source(db).to_nav(db) + } +} + impl ToNav for hir::Label { fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { let InFile { file_id, value } = self.source(db); @@ -544,6 +557,7 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> ast::Struct(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), ast::Enum(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), ast::Trait(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), + ast::TraitAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), ast::Module(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), ast::TypeAlias(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), ast::Const(it) => sema.to_def(&it).map(|it| it.display(db).to_string()), diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index cabbc2872..3684c1033 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -1356,6 +1356,38 @@ impl Foo { } #[test] + fn test_trait_alias() { + check( + r#" +trait Foo {} +trait Bar$0 = Foo where Self: ; +fn foo<T: Bar>(_: impl Bar, _: &dyn Bar) {} +"#, + expect![[r#" + Bar TraitAlias FileId(0) 13..42 19..22 + + FileId(0) 53..56 + FileId(0) 66..69 + FileId(0) 79..82 + "#]], + ); + } + + #[test] + fn test_trait_alias_self() { + check( + r#" +trait Foo = where Self$0: ; +"#, + expect![[r#" + Self TypeParam FileId(0) 6..9 6..9 + + FileId(0) 18..22 + "#]], + ); + } + + #[test] fn test_attr_differs_from_fn_with_same_name() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index c0237e1ed..e10c46381 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -353,6 +353,11 @@ mod tests { fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { let ra_fixture_after = &trim_indent(ra_fixture_after); let (analysis, position) = fixture::position(ra_fixture_before); + if !ra_fixture_after.starts_with("error: ") { + if let Err(err) = analysis.prepare_rename(position).unwrap() { + panic!("Prepare rename to '{new_name}' was failed: {err}") + } + } let rename_result = analysis .rename(position, new_name) .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}")); @@ -1710,6 +1715,23 @@ fn foo(bar: i32) -> Foo { } #[test] + fn test_rename_local_simple() { + check( + "i", + r#" +fn foo(bar$0: i32) -> i32 { + bar +} +"#, + r#" +fn foo(i: i32) -> i32 { + i +} +"#, + ); + } + + #[test] fn test_rename_local_put_init_shorthand() { cov_mark::check!(test_rename_local_put_init_shorthand); check( diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 5b35262aa..8a8a9151c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -2,7 +2,7 @@ use std::fmt; use ast::HasName; use cfg::CfgExpr; -use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics}; +use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; use ide_assists::utils::test_related_attribute; use ide_db::{ base_db::{FilePosition, FileRange}, @@ -195,14 +195,13 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { // // Provides a sneak peek of all tests where the current item is used. // -// The simplest way to use this feature is via the context menu: -// - Right-click on the selected item. The context menu opens. -// - Select **Peek related tests** +// The simplest way to use this feature is via the context menu. Right-click on +// the selected item. The context menu opens. Select **Peek Related Tests**. // // |=== // | Editor | Action Name // -// | VS Code | **rust-analyzer: Peek related tests** +// | VS Code | **rust-analyzer: Peek Related Tests** // |=== pub(crate) fn related_tests( db: &RootDatabase, @@ -371,9 +370,9 @@ pub(crate) fn runnable_impl( let nav = def.try_to_nav(sema.db)?; let ty = def.self_ty(sema.db); let adt_name = ty.as_adt()?.name(sema.db); - let mut ty_args = ty.type_arguments().peekable(); + let mut ty_args = ty.generic_parameters(sema.db).peekable(); let params = if ty_args.peek().is_some() { - format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db)))) + format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))) } else { String::new() }; @@ -417,6 +416,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> { Definition::Const(it) => it.attrs(db), Definition::Static(it) => it.attrs(db), Definition::Trait(it) => it.attrs(db), + Definition::TraitAlias(it) => it.attrs(db), Definition::TypeAlias(it) => it.attrs(db), Definition::Macro(it) => it.attrs(db), Definition::SelfType(it) => it.attrs(db), @@ -437,14 +437,10 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> { let ty = imp.self_ty(db); if let Some(adt) = ty.as_adt() { let name = adt.name(db); - let mut ty_args = ty.type_arguments().peekable(); + let mut ty_args = ty.generic_parameters(db).peekable(); format_to!(path, "{}", name); if ty_args.peek().is_some() { - format_to!( - path, - "<{}>", - ty_args.format_with(",", |ty, cb| cb(&ty.display(db))) - ); + format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); } format_to!(path, "::{}", def_name); path.retain(|c| c != ' '); @@ -1001,6 +997,221 @@ impl Data { } #[test] + fn test_runnables_doc_test_in_impl_with_lifetime() { + check( + r#" +//- /lib.rs +$0 +fn main() {} + +struct Data<'a>; +impl Data<'a> { + /// ``` + /// let x = 5; + /// ``` + fn foo() {} +} +"#, + &[Bin, DocTest], + expect![[r#" + [ + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 1..13, + focus_range: 4..8, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 52..106, + name: "foo", + }, + kind: DocTest { + test_id: Path( + "Data<'a>::foo", + ), + }, + cfg: None, + }, + ] + "#]], + ); + } + + #[test] + fn test_runnables_doc_test_in_impl_with_lifetime_and_types() { + check( + r#" +//- /lib.rs +$0 +fn main() {} + +struct Data<'a, T, U>; +impl<T, U> Data<'a, T, U> { + /// ``` + /// let x = 5; + /// ``` + fn foo() {} +} +"#, + &[Bin, DocTest], + expect![[r#" + [ + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 1..13, + focus_range: 4..8, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 70..124, + name: "foo", + }, + kind: DocTest { + test_id: Path( + "Data<'a,T,U>::foo", + ), + }, + cfg: None, + }, + ] + "#]], + ); + } + + #[test] + fn test_runnables_doc_test_in_impl_with_const() { + check( + r#" +//- /lib.rs +$0 +fn main() {} + +struct Data<const N: usize>; +impl<const N: usize> Data<N> { + /// ``` + /// let x = 5; + /// ``` + fn foo() {} +} +"#, + &[Bin, DocTest], + expect![[r#" + [ + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 1..13, + focus_range: 4..8, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 79..133, + name: "foo", + }, + kind: DocTest { + test_id: Path( + "Data<N>::foo", + ), + }, + cfg: None, + }, + ] + "#]], + ); + } + + #[test] + fn test_runnables_doc_test_in_impl_with_lifetime_types_and_const() { + check( + r#" +//- /lib.rs +$0 +fn main() {} + +struct Data<'a, T, const N: usize>; +impl<'a, T, const N: usize> Data<'a, T, N> { + /// ``` + /// let x = 5; + /// ``` + fn foo() {} +} +"#, + &[Bin, DocTest], + expect![[r#" + [ + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 1..13, + focus_range: 4..8, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 100..154, + name: "foo", + }, + kind: DocTest { + test_id: Path( + "Data<'a,T,N>::foo", + ), + }, + cfg: None, + }, + ] + "#]], + ); + } + #[test] fn test_runnables_module() { check( r#" @@ -2063,6 +2274,59 @@ mod tests { } #[test] + fn test_runnables_doc_test_in_impl_with_lifetime_type_const_value() { + check( + r#" +//- /lib.rs +$0 +fn main() {} + +struct Data<'a, A, const B: usize, C, const D: u32>; +impl<A, C, const D: u32> Data<'a, A, 12, C, D> { + /// ``` + /// ``` + fn foo() {} +} +"#, + &[Bin, DocTest], + expect![[r#" + [ + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 1..13, + focus_range: 4..8, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 121..156, + name: "foo", + }, + kind: DocTest { + test_id: Path( + "Data<'a,A,12,C,D>::foo", + ), + }, + cfg: None, + }, + ] + "#]], + ); + } + + #[test] fn doc_test_type_params() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index f70ca55a5..4b2c139f6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -16,7 +16,7 @@ use stdx::format_to; use syntax::{ algo, ast::{self, HasArgList}, - match_ast, AstNode, Direction, SyntaxToken, TextRange, TextSize, + match_ast, AstNode, Direction, SyntaxElementChildren, SyntaxToken, TextRange, TextSize, }; use crate::RootDatabase; @@ -102,6 +102,20 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio } return signature_help_for_record_lit(&sema, record, token); }, + ast::RecordPat(record) => { + let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token); + if cursor_outside { + continue; + } + return signature_help_for_record_pat(&sema, record, token); + }, + ast::TupleStructPat(tuple_pat) => { + let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token); + if cursor_outside { + continue; + } + return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token); + }, _ => (), } } @@ -172,7 +186,7 @@ fn signature_help_for_call( res.signature.push('('); { - if let Some(self_param) = callable.receiver_param(db) { + if let Some((self_param, _)) = callable.receiver_param(db) { format_to!(res.signature, "{}", self_param) } let mut buf = String::new(); @@ -252,6 +266,10 @@ fn signature_help_for_generics( res.doc = it.docs(db).map(|it| it.into()); format_to!(res.signature, "trait {}", it.name(db)); } + hir::GenericDef::TraitAlias(it) => { + res.doc = it.docs(db).map(|it| it.into()); + format_to!(res.signature, "trait {}", it.name(db)); + } hir::GenericDef::TypeAlias(it) => { res.doc = it.docs(db).map(|it| it.into()); format_to!(res.signature, "type {}", it.name(db)); @@ -342,11 +360,112 @@ fn signature_help_for_record_lit( record: ast::RecordExpr, token: SyntaxToken, ) -> Option<SignatureHelp> { - let active_parameter = record - .record_expr_field_list()? + signature_help_for_record_( + sema, + record.record_expr_field_list()?.syntax().children_with_tokens(), + &record.path()?, + record + .record_expr_field_list()? + .fields() + .filter_map(|field| sema.resolve_record_field(&field)) + .map(|(field, _, ty)| (field, ty)), + token, + ) +} + +fn signature_help_for_record_pat( + sema: &Semantics<'_, RootDatabase>, + record: ast::RecordPat, + token: SyntaxToken, +) -> Option<SignatureHelp> { + signature_help_for_record_( + sema, + record.record_pat_field_list()?.syntax().children_with_tokens(), + &record.path()?, + record + .record_pat_field_list()? + .fields() + .filter_map(|field| sema.resolve_record_pat_field(&field)), + token, + ) +} + +fn signature_help_for_tuple_struct_pat( + sema: &Semantics<'_, RootDatabase>, + pat: ast::TupleStructPat, + token: SyntaxToken, +) -> Option<SignatureHelp> { + let rest_pat = pat.fields().find(|it| matches!(it, ast::Pat::RestPat(_))); + let is_left_of_rest_pat = + rest_pat.map_or(true, |it| token.text_range().start() < it.syntax().text_range().end()); + + let mut res = SignatureHelp { + doc: None, + signature: String::new(), + parameters: vec![], + active_parameter: None, + }; + + let db = sema.db; + let path_res = sema.resolve_path(&pat.path()?)?; + let fields: Vec<_> = if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { + let en = variant.parent_enum(db); + + res.doc = en.docs(db).map(|it| it.into()); + format_to!(res.signature, "enum {}::{} (", en.name(db), variant.name(db)); + variant.fields(db) + } else { + let adt = match path_res { + PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?, + PathResolution::Def(ModuleDef::Adt(adt)) => adt, + _ => return None, + }; + + match adt { + hir::Adt::Struct(it) => { + res.doc = it.docs(db).map(|it| it.into()); + format_to!(res.signature, "struct {} (", it.name(db)); + it.fields(db) + } + _ => return None, + } + }; + let commas = pat .syntax() .children_with_tokens() .filter_map(syntax::NodeOrToken::into_token) + .filter(|t| t.kind() == syntax::T![,]); + res.active_parameter = Some(if is_left_of_rest_pat { + commas.take_while(|t| t.text_range().start() <= token.text_range().start()).count() + } else { + let n_commas = commas + .collect::<Vec<_>>() + .into_iter() + .rev() + .take_while(|t| t.text_range().start() > token.text_range().start()) + .count(); + fields.len().saturating_sub(1).saturating_sub(n_commas) + }); + + let mut buf = String::new(); + for ty in fields.into_iter().map(|it| it.ty(db)) { + format_to!(buf, "{}", ty.display_truncated(db, Some(20))); + res.push_call_param(&buf); + buf.clear(); + } + res.signature.push_str(")"); + Some(res) +} + +fn signature_help_for_record_( + sema: &Semantics<'_, RootDatabase>, + field_list_children: SyntaxElementChildren, + path: &ast::Path, + fields2: impl Iterator<Item = (hir::Field, hir::Type)>, + token: SyntaxToken, +) -> Option<SignatureHelp> { + let active_parameter = field_list_children + .filter_map(syntax::NodeOrToken::into_token) .filter(|t| t.kind() == syntax::T![,]) .take_while(|t| t.text_range().start() <= token.text_range().start()) .count(); @@ -361,7 +480,7 @@ fn signature_help_for_record_lit( let fields; let db = sema.db; - let path_res = sema.resolve_path(&record.path()?)?; + let path_res = sema.resolve_path(path)?; if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { fields = variant.fields(db); let en = variant.parent_enum(db); @@ -393,8 +512,7 @@ fn signature_help_for_record_lit( let mut fields = fields.into_iter().map(|field| (field.name(db), Some(field))).collect::<FxIndexMap<_, _>>(); let mut buf = String::new(); - for field in record.record_expr_field_list()?.fields() { - let Some((field, _, ty)) = sema.resolve_record_field(&field) else { continue }; + for (field, ty) in fields2 { let name = field.name(db); format_to!(buf, "{name}: {}", ty.display_truncated(db, Some(20))); res.push_record_field(&buf); @@ -435,6 +553,7 @@ mod tests { (database, FilePosition { file_id, offset }) } + #[track_caller] fn check(ra_fixture: &str, expect: Expect) { let fixture = format!( r#" @@ -887,6 +1006,119 @@ fn main() { } #[test] + fn tuple_struct_pat() { + check( + r#" +/// A cool tuple struct +struct S(u32, i32); +fn main() { + let S(0, $0); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32) + --- ^^^ + "#]], + ); + } + + #[test] + fn tuple_struct_pat_rest() { + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S(0, .., $0); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + --- --- --- ^^^ + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16, u8); +fn main() { + let S(0, .., $0, 0); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16, u8) + --- --- --- ^^^ -- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S($0, .., 1); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + ^^^ --- --- --- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16, u8); +fn main() { + let S(1, .., 1, $0, 2); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16, u8) + --- --- --- ^^^ -- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S(1, $0.., 1); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + --- ^^^ --- --- + "#]], + ); + check( + r#" +/// A cool tuple struct +struct S(u32, i32, f32, u16); +fn main() { + let S(1, ..$0, 1); +} +"#, + expect![[r#" + A cool tuple struct + ------ + struct S (u32, i32, f32, u16) + --- ^^^ --- --- + "#]], + ); + } + + #[test] fn generic_struct() { check( r#" @@ -1547,6 +1779,29 @@ impl S { } #[test] + fn record_pat() { + check( + r#" +struct Strukt<T, U = ()> { + t: T, + u: U, + unit: (), +} +fn f() { + let Strukt { + u: 0, + $0 + } +} +"#, + expect![[r#" + struct Strukt { u: i32, t: T, unit: () } + ------ ^^^^ -------- + "#]], + ); + } + + #[test] fn test_enum_in_nested_method_in_lambda() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 3f7f6885f..c97691b14 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -139,6 +139,7 @@ impl StaticIndex<'_> { documentation: true, keywords: true, format: crate::HoverDocFormat::Markdown, + interpret_tests: false, }; let tokens = tokens.filter(|token| { matches!( diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 892e6a9bb..2111baad7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -217,7 +217,9 @@ fn highlight_name_ref( // to anything when used. // We can fix this for derive attributes since derive helpers are recorded, but not for // general attributes. - None if name_ref.syntax().ancestors().any(|it| it.kind() == ATTR) => { + None if name_ref.syntax().ancestors().any(|it| it.kind() == ATTR) + && !sema.hir_file_for(name_ref.syntax()).is_derive_attr_pseudo_expansion(sema.db) => + { return HlTag::Symbol(SymbolKind::Attribute).into(); } None => return HlTag::UnresolvedReference.into(), @@ -410,6 +412,7 @@ fn highlight_def( h } Definition::Trait(_) => Highlight::new(HlTag::Symbol(SymbolKind::Trait)), + Definition::TraitAlias(_) => Highlight::new(HlTag::Symbol(SymbolKind::TraitAlias)), Definition::TypeAlias(type_) => { let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 9139528c7..3c4cfc781 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -274,6 +274,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::Const(_) => SymbolKind::Const, Definition::Static(_) => SymbolKind::Static, Definition::Trait(_) => SymbolKind::Trait, + Definition::TraitAlias(_) => SymbolKind::TraitAlias, Definition::TypeAlias(_) => SymbolKind::TypeAlias, Definition::BuiltinType(_) => return HlTag::BuiltinType, Definition::Macro(_) => SymbolKind::Macro, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs index 3949f1189..a81c4ee0c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs @@ -150,6 +150,7 @@ impl HlTag { SymbolKind::Struct => "struct", SymbolKind::ToolModule => "tool_module", SymbolKind::Trait => "trait", + SymbolKind::TraitAlias => "trait_alias", SymbolKind::TypeAlias => "type_alias", SymbolKind::TypeParam => "type_param", SymbolKind::Union => "union", diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html index 1a4398814..567ab8ccc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html @@ -53,6 +53,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="comment">// This is another normal comment</span> <span class="comment documentation">/// This is another doc comment</span> <span class="comment">// This is another normal comment</span> -<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Copy</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span> +<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Copy</span><span class="comma attribute">,</span> <span class="unresolved_reference attribute">Unresolved</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span> <span class="comment">// The reason for these being here is to test AttrIds</span> <span class="keyword">struct</span> <span class="struct declaration">Foo</span><span class="semicolon">;</span></code></pre>
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index fc9b5d3ba..ac9bd8e39 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -34,7 +34,7 @@ fn attributes() { // This is another normal comment /// This is another doc comment // This is another normal comment -#[derive(Copy)] +#[derive(Copy, Unresolved)] // The reason for these being here is to test AttrIds struct Foo; "#, diff --git a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs new file mode 100644 index 000000000..a36aba58b --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs @@ -0,0 +1,29 @@ +use hir::{DefWithBody, Semantics}; +use ide_db::base_db::FilePosition; +use ide_db::RootDatabase; +use syntax::{algo::find_node_at_offset, ast, AstNode}; + +// Feature: View Mir +// +// |=== +// | Editor | Action Name +// +// | VS Code | **rust-analyzer: View Mir** +// |=== +pub(crate) fn view_mir(db: &RootDatabase, position: FilePosition) -> String { + body_mir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) +} + +fn body_mir(db: &RootDatabase, position: FilePosition) -> Option<String> { + let sema = Semantics::new(db); + let source_file = sema.parse(position.file_id); + + let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?; + let def: DefWithBody = match item { + ast::Item::Fn(it) => sema.to_def(&it)?.into(), + ast::Item::Const(it) => sema.to_def(&it)?.into(), + ast::Item::Static(it) => sema.to_def(&it)?.into(), + _ => return None, + }; + Some(def.debug_mir(db)) +} |