Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/item_scope.rs32
-rw-r--r--crates/hir-def/src/per_ns.rs10
-rw-r--r--crates/ide-diagnostics/src/handlers/type_mismatch.rs25
3 files changed, 55 insertions, 12 deletions
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 1443d3ea4b..14f10651cb 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -621,7 +621,11 @@ impl ItemScope {
// for that.
}
_ => {
- if glob_imports.types.remove(&lookup) {
+ // A non-glob import either shadows a glob import of the same
+ // name, or re-resolves a stale binding it recorded earlier.
+ if glob_imports.types.remove(&lookup)
+ || entry.get().is_reresolved_by(&fld.def, import)
+ {
let prev = std::mem::replace(&mut fld.import, import);
if let Some(import) = import {
self.use_imports_types.insert(
@@ -659,19 +663,22 @@ impl ItemScope {
changed = true;
}
Entry::Occupied(mut entry)
- if !matches!(import, Some(ImportOrExternCrate::Glob(..)))
- && glob_imports.values.remove(&lookup) =>
+ if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
{
- cov_mark::hit!(import_shadowed);
-
let import = import.and_then(ImportOrExternCrate::import_or_glob);
- let prev = std::mem::replace(&mut fld.import, import);
- if let Some(import) = import {
- self.use_imports_values
- .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
+ if glob_imports.values.remove(&lookup)
+ || entry.get().is_reresolved_by(&fld.def, import)
+ {
+ cov_mark::hit!(import_shadowed);
+
+ let prev = std::mem::replace(&mut fld.import, import);
+ if let Some(import) = import {
+ self.use_imports_values
+ .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
+ }
+ entry.insert(fld);
+ changed = true;
}
- entry.insert(fld);
- changed = true;
}
_ => {}
}
@@ -699,7 +706,8 @@ impl ItemScope {
}
Entry::Occupied(mut entry)
if !matches!(import, Some(ImportOrExternCrate::Glob(..)))
- && glob_imports.macros.remove(&lookup) =>
+ && (glob_imports.macros.remove(&lookup)
+ || entry.get().is_reresolved_by(&fld.def, import)) =>
{
cov_mark::hit!(import_shadowed);
let prev = std::mem::replace(&mut fld.import, import);
diff --git a/crates/hir-def/src/per_ns.rs b/crates/hir-def/src/per_ns.rs
index f7e5ac316a..1cdc9b1f2c 100644
--- a/crates/hir-def/src/per_ns.rs
+++ b/crates/hir-def/src/per_ns.rs
@@ -35,6 +35,16 @@ pub struct Item<Def, Import = ImportId> {
pub import: Option<Import>,
}
+impl<Def: PartialEq, Import: Copy + PartialEq> Item<Def, Import> {
+ /// Whether `import` is the same import that produced `self`, now resolving to a different
+ /// `def`. This happens when an import is first recorded as an indeterminate resolution
+ /// (e.g. only one namespace was available at the time) and later re-resolves to another
+ /// def, such as an explicit import that shadows a glob only after the glob has been seen.
+ pub(crate) fn is_reresolved_by(&self, def: &Def, import: Option<Import>) -> bool {
+ import.is_some() && self.import == import && self.def != *def
+ }
+}
+
pub type TypesItem = Item<ModuleDefId, ImportOrExternCrate>;
pub type ValuesItem = Item<ModuleDefId, ImportOrGlob>;
// May be Externcrate for `[macro_use]`'d macros
diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 295f37ab1d..b16be503ef 100644
--- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1813,4 +1813,29 @@ fn main() {
"#,
);
}
+
+ #[test]
+ fn regression_21668() {
+ check_diagnostics(
+ r#"
+mod std {
+ pub enum Ordering { Less }
+}
+pub use std::*;
+
+pub mod evil {
+ pub struct Ordering(pub i32);
+}
+
+pub mod oblivious {
+ use crate::Ordering;
+
+ pub fn what() -> Ordering {
+ Ordering(2)
+ }
+}
+pub use evil::Ordering;
+"#,
+ );
+ }
}