From 37a87708aee788de10352603baff82f6d2192fad Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 20 Dec 2021 13:19:48 +0100 Subject: [PATCH 1/2] internal: Don't kick off inference in Semantics::descend_into_macros_impl --- crates/hir/src/semantics.rs | 35 +++++++++++++++++++++---------- crates/hir/src/source_analyzer.rs | 26 +++++++++++++++++++++-- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index d27869450e5..02da397b0ce 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -528,7 +528,7 @@ impl<'db> SemanticsImpl<'db> { if first == last { self.descend_into_macros_impl( first, - |InFile { value, .. }| { + &mut |InFile { value, .. }| { if let Some(node) = value.ancestors().find_map(N::cast) { res.push(node) } @@ -540,7 +540,7 @@ impl<'db> SemanticsImpl<'db> { let mut scratch: SmallVec<[_; 1]> = smallvec![]; self.descend_into_macros_impl( first, - |token| { + &mut |token| { scratch.push(token); }, false, @@ -549,7 +549,7 @@ impl<'db> SemanticsImpl<'db> { let mut scratch = scratch.into_iter(); self.descend_into_macros_impl( last, - |InFile { value: last, file_id: last_fid }| { + &mut |InFile { value: last, file_id: last_fid }| { if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() { if first_fid == last_fid { if let Some(p) = first.parent() { @@ -574,20 +574,20 @@ impl<'db> SemanticsImpl<'db> { fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { let mut res = smallvec![]; - self.descend_into_macros_impl(token, |InFile { value, .. }| res.push(value), false); + self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res.push(value), false); res } fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken { let mut res = token.clone(); - self.descend_into_macros_impl(token, |InFile { value, .. }| res = value, true); + self.descend_into_macros_impl(token, &mut |InFile { value, .. }| res = value, true); res } fn descend_into_macros_impl( &self, token: SyntaxToken, - mut f: impl FnMut(InFile), + f: &mut dyn FnMut(InFile), single: bool, ) { let _p = profile::span("descend_into_macros"); @@ -595,7 +595,7 @@ impl<'db> SemanticsImpl<'db> { Some(it) => it, None => return, }; - let sa = self.analyze(&parent); + let sa = self.analyze_no_infer(&parent); let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)]; let mut cache = self.expansion_info_cache.borrow_mut(); let mut mcache = self.macro_call_cache.borrow_mut(); @@ -927,14 +927,23 @@ impl<'db> SemanticsImpl<'db> { } fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer { - self.analyze_impl(node, None) + self.analyze_impl(node, None, true) } fn analyze_with_offset(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer { - self.analyze_impl(node, Some(offset)) + self.analyze_impl(node, Some(offset), true) } - fn analyze_impl(&self, node: &SyntaxNode, offset: Option) -> SourceAnalyzer { + fn analyze_no_infer(&self, node: &SyntaxNode) -> SourceAnalyzer { + self.analyze_impl(node, None, false) + } + + fn analyze_impl( + &self, + node: &SyntaxNode, + offset: Option, + infer_body: bool, + ) -> SourceAnalyzer { let _p = profile::span("Semantics::analyze_impl"); let node = self.find_file(node.clone()); let node = node.as_ref(); @@ -946,7 +955,11 @@ impl<'db> SemanticsImpl<'db> { let resolver = match container { ChildContainer::DefWithBodyId(def) => { - return SourceAnalyzer::new_for_body(self.db, def, node, offset) + return if infer_body { + SourceAnalyzer::new_for_body(self.db, def, node, offset) + } else { + SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset) + } } ChildContainer::TraitId(it) => it.resolver(self.db.upcast()), ChildContainer::ImplId(it) => it.resolver(self.db.upcast()), diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 4f987db651f..2d779393f09 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -50,7 +50,7 @@ impl SourceAnalyzer { pub(crate) fn new_for_body( db: &dyn HirDatabase, def: DefWithBodyId, - node: InFile<&SyntaxNode>, + node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option, ) -> SourceAnalyzer { let (body, source_map) = db.body_with_source_map(def); @@ -65,7 +65,29 @@ impl SourceAnalyzer { body: Some(body), body_source_map: Some(source_map), infer: Some(db.infer(def)), - file_id: node.file_id, + file_id, + } + } + + pub(crate) fn new_for_body_no_infer( + db: &dyn HirDatabase, + def: DefWithBodyId, + node @ InFile { file_id, .. }: InFile<&SyntaxNode>, + offset: Option, + ) -> SourceAnalyzer { + let (body, source_map) = db.body_with_source_map(def); + let scopes = db.expr_scopes(def); + let scope = match offset { + None => scope_for(&scopes, &source_map, node), + Some(offset) => scope_for_offset(db, &scopes, &source_map, node.with_value(offset)), + }; + let resolver = resolver_for_scope(db.upcast(), def, scope); + SourceAnalyzer { + resolver, + body: Some(body), + body_source_map: Some(source_map), + infer: None, + file_id, } } From a574434c3f0d963392113d4f6aa80872d9c49d16 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 20 Dec 2021 13:47:06 +0100 Subject: [PATCH 2/2] Simplify NameClass::classify --- crates/hir/src/semantics.rs | 1 + crates/hir/src/semantics/source_to_def.rs | 21 ++- crates/ide_db/src/defs.rs | 196 +++++++++------------- 3 files changed, 102 insertions(+), 116 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 02da397b0ce..a299aa44988 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1130,6 +1130,7 @@ to_def_impls![ (crate::TypeParam, ast::TypeParam, type_param_to_def), (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), (crate::ConstParam, ast::ConstParam, const_param_to_def), + (crate::GenericParam, ast::GenericParam, generic_param_to_def), (crate::MacroDef, ast::Macro, macro_to_def), (crate::Local, ast::IdentPat, bind_pat_to_def), (crate::Local, ast::SelfParam, self_param_to_def), diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 877d385fbd1..9b8e5635923 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -92,8 +92,8 @@ use hir_def::{ expr::{LabelId, PatId}, keys::{self, Key}, AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, - GenericDefId, ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, - TypeParamId, UnionId, VariantId, + GenericDefId, GenericParamId, ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, + TypeAliasId, TypeParamId, UnionId, VariantId, }; use hir_expand::{name::AsName, AstId, HirFileId, MacroCallId, MacroDefId, MacroDefKind}; use rustc_hash::FxHashMap; @@ -299,6 +299,23 @@ impl SourceToDefCtx<'_, '_> { dyn_map[keys::CONST_PARAM].get(&src).copied() } + pub(super) fn generic_param_to_def( + &mut self, + InFile { file_id, value }: InFile, + ) -> Option { + match value { + ast::GenericParam::ConstParam(it) => { + self.const_param_to_def(InFile::new(file_id, it)).map(GenericParamId::ConstParamId) + } + ast::GenericParam::LifetimeParam(it) => self + .lifetime_param_to_def(InFile::new(file_id, it)) + .map(GenericParamId::LifetimeParamId), + ast::GenericParam::TypeParam(it) => { + self.type_param_to_def(InFile::new(file_id, it)).map(GenericParamId::TypeParamId) + } + } + } + pub(super) fn macro_to_def(&mut self, src: InFile) -> Option { let makro = self.dyn_map(src.as_ref()).and_then(|it| it[keys::MACRO].get(&src).copied()); if let res @ Some(_) = makro { diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index 30ebf7828ae..b5a13cea917 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs @@ -224,125 +224,93 @@ impl NameClass { let parent = name.syntax().parent()?; - if let Some(bind_pat) = ast::IdentPat::cast(parent.clone()) { - if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { + let def = if let Some(item) = ast::Item::cast(parent.clone()) { + match item { + ast::Item::MacroRules(it) => { + Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?) + } + ast::Item::MacroDef(it) => { + Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?) + } + ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?), + ast::Item::Fn(it) => Definition::Function(sema.to_def(&it)?), + ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?), + ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?), + ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?), + ast::Item::TypeAlias(it) => Definition::TypeAlias(sema.to_def(&it)?), + ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)), + ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)), + ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)), + _ => return None, + } + } else if let Some(it) = ast::IdentPat::cast(parent.clone()) { + if let Some(def) = sema.resolve_bind_pat_to_const(&it) { return Some(NameClass::ConstReference(Definition::from(def))); } - } - match_ast! { - match parent { - ast::Rename(it) => { - if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) { - let path = use_tree.path()?; - let path_segment = path.segment()?; - let name_ref = path_segment.name_ref()?; - let name_ref = if name_ref.self_token().is_some() { - use_tree - .syntax() - .parent() - .as_ref() - // Skip over UseTreeList - .and_then(|it| { - let use_tree = it.parent().and_then(ast::UseTree::cast)?; - let path = use_tree.path()?; - let path_segment = path.segment()?; - path_segment.name_ref() - }).unwrap_or(name_ref) - } else { - name_ref - }; - let name_ref_class = NameRefClass::classify(sema, &name_ref)?; - - Some(NameClass::Definition(match name_ref_class { - NameRefClass::Definition(def) => def, - NameRefClass::FieldShorthand { local_ref: _, field_ref } => { - Definition::Field(field_ref) - } - })) - } else { - let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?; - let krate = sema.resolve_extern_crate(&extern_crate)?; - let root_module = krate.root_module(sema.db); - Some(NameClass::Definition(Definition::Module(root_module))) + let local = sema.to_def(&it)?; + let pat_parent = it.syntax().parent(); + if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) { + if record_pat_field.name_ref().is_none() { + if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { + return Some(NameClass::PatFieldShorthand { + local_def: local, + field_ref: field, + }); } - }, - ast::IdentPat(it) => { - let local = sema.to_def(&it)?; - - if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) { - if record_pat_field.name_ref().is_none() { - if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { - return Some(NameClass::PatFieldShorthand { local_def: local, field_ref: field }); - } - } - } - - Some(NameClass::Definition(Definition::Local(local))) - }, - ast::SelfParam(it) => { - let def = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Local(def))) - }, - ast::RecordField(it) => { - let field: hir::Field = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Field(field))) - }, - ast::Module(it) => { - let def = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Module(def))) - }, - ast::Struct(it) => { - let def: hir::Struct = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Adt(def.into()))) - }, - ast::Union(it) => { - let def: hir::Union = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Adt(def.into()))) - }, - ast::Enum(it) => { - let def: hir::Enum = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Adt(def.into()))) - }, - ast::Trait(it) => { - let def: hir::Trait = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Trait(def))) - }, - ast::Static(it) => { - let def: hir::Static = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Static(def))) - }, - ast::Variant(it) => { - let def: hir::Variant = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Variant(def))) - }, - ast::Fn(it) => { - let def: hir::Function = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Function(def))) - }, - ast::Const(it) => { - let def: hir::Const = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Const(def))) - }, - ast::TypeAlias(it) => { - let def: hir::TypeAlias = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::TypeAlias(def))) - }, - ast::Macro(it) => { - let def = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::Macro(def))) - }, - ast::TypeParam(it) => { - let def = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::GenericParam(def.into()))) - }, - ast::ConstParam(it) => { - let def = sema.to_def(&it)?; - Some(NameClass::Definition(Definition::GenericParam(def.into()))) - }, - _ => None, + } } - } + + Definition::Local(local) + } else if let Some(it) = ast::Rename::cast(parent.clone()) { + if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) { + let path = use_tree.path()?; + let path_segment = path.segment()?; + let name_ref = path_segment.name_ref()?; + let name_ref = if name_ref.self_token().is_some() { + use_tree + .syntax() + .parent() + .as_ref() + // Skip over UseTreeList + .and_then(|it| { + let use_tree = it.parent().and_then(ast::UseTree::cast)?; + let path = use_tree.path()?; + let path_segment = path.segment()?; + path_segment.name_ref() + }) + .unwrap_or(name_ref) + } else { + name_ref + }; + let name_ref_class = NameRefClass::classify(sema, &name_ref)?; + + match name_ref_class { + NameRefClass::Definition(def) => def, + NameRefClass::FieldShorthand { local_ref: _, field_ref } => { + Definition::Field(field_ref) + } + } + } else { + let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?; + let krate = sema.resolve_extern_crate(&extern_crate)?; + let root_module = krate.root_module(sema.db); + Definition::Module(root_module) + } + } else { + match_ast! { + match parent { + ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?), + ast::RecordField(it) => Definition::Field(sema.to_def(&it)?), + ast::Variant(it) => Definition::Variant(sema.to_def(&it)?), + ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), + ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), + _ => return None, + } + } + }; + + Some(NameClass::Definition(def)) } pub fn classify_lifetime(