mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
Auto merge of #18160 - ChayimFriedman2:fix-18138, r=Veykril
fix: Fix name resolution when an import is resolved to some namespace and then later in the algorithm another namespace is added The import is flagged as "indeterminate", and previously it was re-resolved, but only at the end of name resolution, when it's already too late for anything that depends on it. This issue was tried to fix in https://github.com/rust-lang/rust-analyzer/pull/2466, but it was not fixed fully. That PR is also why IDE features did work: the import at the end was resolved correctly, so IDE features that re-resolved the macro path resolved it correctly. I was concerned about the performance of this, but this doesn't seem to regress `analysis-stats .`, so I guess it's fine to land this. I have no idea about the incremental perf however and I don't know how to measure that, although when typing in `zbus` (including creating a new function, which should recompute the def map) completion was fast enough. I didn't check what rustc does, so maybe it does something more performant, like keeping track of only possibly problematic imports. Fixes #18138. Probably fixes #17630.
This commit is contained in:
commit
a159b370ba
3 changed files with 82 additions and 13 deletions
|
@ -221,7 +221,7 @@ struct DefCollector<'a> {
|
|||
deps: FxHashMap<Name, Dependency>,
|
||||
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, UseId)>>,
|
||||
unresolved_imports: Vec<ImportDirective>,
|
||||
indeterminate_imports: Vec<ImportDirective>,
|
||||
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
|
||||
unresolved_macros: Vec<MacroDirective>,
|
||||
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
|
||||
cfg_options: &'a CfgOptions,
|
||||
|
@ -415,16 +415,6 @@ impl DefCollector<'_> {
|
|||
|
||||
self.resolution_loop();
|
||||
|
||||
// Resolve all indeterminate resolved imports again
|
||||
// As some of the macros will expand newly import shadowing partial resolved imports
|
||||
// FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
|
||||
// correctly
|
||||
let partial_resolved = self.indeterminate_imports.drain(..).map(|directive| {
|
||||
ImportDirective { status: PartialResolvedImport::Unresolved, ..directive }
|
||||
});
|
||||
self.unresolved_imports.extend(partial_resolved);
|
||||
self.resolve_imports();
|
||||
|
||||
let unresolved_imports = mem::take(&mut self.unresolved_imports);
|
||||
// show unresolved imports in completion, etc
|
||||
for directive in &unresolved_imports {
|
||||
|
@ -749,9 +739,9 @@ impl DefCollector<'_> {
|
|||
.filter_map(|mut directive| {
|
||||
directive.status = self.resolve_import(directive.module_id, &directive.import);
|
||||
match directive.status {
|
||||
PartialResolvedImport::Indeterminate(_) => {
|
||||
PartialResolvedImport::Indeterminate(resolved) => {
|
||||
self.record_resolved_import(&directive);
|
||||
self.indeterminate_imports.push(directive);
|
||||
self.indeterminate_imports.push((directive, resolved));
|
||||
res = ReachedFixedPoint::No;
|
||||
None
|
||||
}
|
||||
|
@ -764,6 +754,33 @@ impl DefCollector<'_> {
|
|||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Resolve all indeterminate resolved imports again
|
||||
// As some of the macros will expand newly import shadowing partial resolved imports
|
||||
// FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
|
||||
// correctly
|
||||
let mut indeterminate_imports = std::mem::take(&mut self.indeterminate_imports);
|
||||
indeterminate_imports.retain_mut(|(directive, partially_resolved)| {
|
||||
let partially_resolved = partially_resolved.availability();
|
||||
directive.status = self.resolve_import(directive.module_id, &directive.import);
|
||||
match directive.status {
|
||||
PartialResolvedImport::Indeterminate(import)
|
||||
if partially_resolved != import.availability() =>
|
||||
{
|
||||
self.record_resolved_import(directive);
|
||||
res = ReachedFixedPoint::No;
|
||||
false
|
||||
}
|
||||
PartialResolvedImport::Resolved(_) => {
|
||||
self.record_resolved_import(directive);
|
||||
res = ReachedFixedPoint::No;
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
self.indeterminate_imports = indeterminate_imports;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
//!
|
||||
//! `PerNs` (per namespace) captures this.
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
use crate::{
|
||||
item_scope::{ImportId, ImportOrExternCrate, ItemInNs},
|
||||
visibility::Visibility,
|
||||
|
@ -16,6 +18,16 @@ pub enum Namespace {
|
|||
Macros,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Describes only the presence/absence of each namespace, without its value.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) struct NsAvailability : u32 {
|
||||
const TYPES = 1 << 0;
|
||||
const VALUES = 1 << 1;
|
||||
const MACROS = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct PerNs {
|
||||
pub types: Option<(ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
|
||||
|
@ -24,6 +36,14 @@ pub struct PerNs {
|
|||
}
|
||||
|
||||
impl PerNs {
|
||||
pub(crate) fn availability(&self) -> NsAvailability {
|
||||
let mut result = NsAvailability::empty();
|
||||
result.set(NsAvailability::TYPES, self.types.is_some());
|
||||
result.set(NsAvailability::VALUES, self.values.is_some());
|
||||
result.set(NsAvailability::MACROS, self.macros.is_some());
|
||||
result
|
||||
}
|
||||
|
||||
pub fn none() -> PerNs {
|
||||
PerNs { types: None, values: None, macros: None }
|
||||
}
|
||||
|
|
|
@ -2750,4 +2750,36 @@ fn foo() {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_18138() {
|
||||
check(
|
||||
r#"
|
||||
mod foo {
|
||||
macro_rules! x {
|
||||
() => {
|
||||
pub struct Foo;
|
||||
// ^^^
|
||||
};
|
||||
}
|
||||
pub(crate) use x as m;
|
||||
}
|
||||
|
||||
mod bar {
|
||||
use crate::m;
|
||||
|
||||
m!();
|
||||
// ^^^^^
|
||||
|
||||
fn qux() {
|
||||
Foo$0;
|
||||
}
|
||||
}
|
||||
|
||||
mod m {}
|
||||
|
||||
use foo::m;
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue