From 32bf7af83e3d6f201ebea87006f9c33bbc211f7b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Mar 2022 19:49:08 +0100 Subject: [PATCH 1/2] Support locals with multiple declaration sites --- crates/hir/src/lib.rs | 25 ++- crates/hir_def/src/body.rs | 18 +- crates/hir_def/src/body/lower.rs | 84 ++++++-- crates/ide/src/highlight_related.rs | 201 +++++++++++++----- crates/ide/src/rename.rs | 49 +++++ .../src/handlers/inline_local_variable.rs | 1 + crates/ide_db/src/rename.rs | 14 +- crates/ide_db/src/search.rs | 35 ++- 8 files changed, 346 insertions(+), 81 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 45a4c6a50e..60e3548d49 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2036,6 +2036,11 @@ impl GenericDef { } } +/// A single local definition. +/// +/// If the definition of this is part of a "MultiLocal", that is a local that has multiple declarations due to or-patterns +/// then this only references a single one of those. +/// To retrieve the other locals you should use [`Local::associated_locals`] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Local { pub(crate) parent: DefWithBodyId, @@ -2107,12 +2112,28 @@ impl Local { Type::new(db, krate, def, ty) } + pub fn associated_locals(self, db: &dyn HirDatabase) -> Box<[Local]> { + let body = db.body(self.parent); + body.ident_patterns_for(&self.pat_id) + .iter() + .map(|&pat_id| Local { parent: self.parent, pat_id }) + .collect() + } + + /// If this local is part of a multi-local, retrieve the representative local. + /// That is the local that references are being resolved to. + pub fn representative(self, db: &dyn HirDatabase) -> Local { + let body = db.body(self.parent); + Local { pat_id: body.pattern_representative(self.pat_id), ..self } + } + pub fn source(self, db: &dyn HirDatabase) -> InFile> { let (_body, source_map) = db.body_with_source_map(self.parent); let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... let root = src.file_syntax(db.upcast()); - src.map(|ast| { - ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root)) + src.map(|ast| match ast { + Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)), + Either::Right(it) => Either::Right(it.to_node(&root)), }) } } diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index a2f64eda06..1f5e45eb2d 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs @@ -237,10 +237,11 @@ pub struct Mark { } /// The body of an item (function, const etc.). -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct Body { pub exprs: Arena, pub pats: Arena, + pub or_pats: FxHashMap>, pub labels: Arena