mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Fix stable iteration ordering for Map<Name, ...>
usages
This commit is contained in:
parent
f2d51073d2
commit
cde0f69cae
11 changed files with 55 additions and 29 deletions
|
@ -1,10 +1,9 @@
|
||||||
//! Describes items defined or visible (ie, imported) in a certain scope.
|
//! Describes items defined or visible (ie, imported) in a certain scope.
|
||||||
//! This is shared between modules and blocks.
|
//! This is shared between modules and blocks.
|
||||||
|
|
||||||
use std::collections::hash_map::Entry;
|
|
||||||
|
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId};
|
use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId};
|
||||||
|
use indexmap::map::Entry;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use la_arena::Idx;
|
use la_arena::Idx;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
@ -17,8 +16,8 @@ use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
visibility::{Visibility, VisibilityExplicitness},
|
visibility::{Visibility, VisibilityExplicitness},
|
||||||
AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId,
|
AdtId, BuiltinType, ConstId, ExternCrateId, FxIndexMap, HasModule, ImplId, LocalModuleId,
|
||||||
ModuleDefId, ModuleId, TraitId, UseId,
|
Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -67,9 +66,9 @@ pub struct ItemScope {
|
||||||
/// Defs visible in this scope. This includes `declarations`, but also
|
/// Defs visible in this scope. This includes `declarations`, but also
|
||||||
/// imports. The imports belong to this module and can be resolved by using them on
|
/// imports. The imports belong to this module and can be resolved by using them on
|
||||||
/// the `use_imports_*` fields.
|
/// the `use_imports_*` fields.
|
||||||
types: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
|
types: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
|
||||||
values: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
|
values: FxIndexMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
|
||||||
macros: FxHashMap<Name, (MacroId, Visibility, Option<ImportId>)>,
|
macros: FxIndexMap<Name, (MacroId, Visibility, Option<ImportId>)>,
|
||||||
unresolved: FxHashSet<Name>,
|
unresolved: FxHashSet<Name>,
|
||||||
|
|
||||||
/// The defs declared in this scope. Each def has a single scope where it is
|
/// The defs declared in this scope. Each def has a single scope where it is
|
||||||
|
@ -118,7 +117,7 @@ struct DeriveMacroInvocation {
|
||||||
derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
|
derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
|
pub(crate) static BUILTIN_SCOPE: Lazy<FxIndexMap<Name, PerNs>> = Lazy::new(|| {
|
||||||
BuiltinType::all_builtin_types()
|
BuiltinType::all_builtin_types()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None)))
|
.map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None)))
|
||||||
|
|
|
@ -323,7 +323,7 @@ pub struct ModuleData {
|
||||||
///
|
///
|
||||||
/// [`None`] for block modules because they are always its `DefMap`'s root.
|
/// [`None`] for block modules because they are always its `DefMap`'s root.
|
||||||
pub parent: Option<LocalModuleId>,
|
pub parent: Option<LocalModuleId>,
|
||||||
pub children: FxHashMap<Name, LocalModuleId>,
|
pub children: FxIndexMap<Name, LocalModuleId>,
|
||||||
pub scope: ItemScope,
|
pub scope: ItemScope,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,10 +593,8 @@ impl DefMap {
|
||||||
self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
|
self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn macro_use_prelude(
|
pub(crate) fn macro_use_prelude(&self) -> &FxHashMap<Name, (MacroId, Option<ExternCrateId>)> {
|
||||||
&self,
|
&self.macro_use_prelude
|
||||||
) -> impl Iterator<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
|
|
||||||
self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_path(
|
pub(crate) fn resolve_path(
|
||||||
|
@ -668,7 +666,7 @@ impl ModuleData {
|
||||||
origin,
|
origin,
|
||||||
visibility,
|
visibility,
|
||||||
parent: None,
|
parent: None,
|
||||||
children: FxHashMap::default(),
|
children: Default::default(),
|
||||||
scope: ItemScope::default(),
|
scope: ItemScope::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1348,6 +1348,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
|
||||||
.keys()
|
.keys()
|
||||||
.map(|name| name.display(&db).to_string())
|
.map(|name| name.display(&db).to_string())
|
||||||
.sorted()
|
.sorted()
|
||||||
|
.sorted()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::{fmt, iter, mem};
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use hir_expand::{name::Name, MacroDefId};
|
use hir_expand::{name::Name, MacroDefId};
|
||||||
use intern::{sym, Interned};
|
use intern::{sym, Interned};
|
||||||
|
use itertools::Itertools as _;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
@ -497,9 +498,11 @@ impl Resolver {
|
||||||
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
|
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(mac)));
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
def_map.macro_use_prelude().for_each(|(name, (def, _extern_crate))| {
|
def_map.macro_use_prelude().iter().sorted_by_key(|&(k, _)| k.clone()).for_each(
|
||||||
res.add(name, ScopeDef::ModuleDef(def.into()));
|
|(name, &(def, _extern_crate))| {
|
||||||
});
|
res.add(name, ScopeDef::ModuleDef(def.into()));
|
||||||
|
},
|
||||||
|
);
|
||||||
def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
|
def_map.extern_prelude().for_each(|(name, (def, _extern_crate))| {
|
||||||
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
|
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def.into())));
|
||||||
});
|
});
|
||||||
|
|
|
@ -1637,8 +1637,8 @@ mod bar {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn local_inline_import_has_alias() {
|
fn local_inline_import_has_alias() {
|
||||||
// FIXME
|
// FIXME wrong import
|
||||||
check_assist_not_applicable(
|
check_assist(
|
||||||
auto_import,
|
auto_import,
|
||||||
r#"
|
r#"
|
||||||
struct S<T>(T);
|
struct S<T>(T);
|
||||||
|
@ -1647,14 +1647,24 @@ use S as IoResult;
|
||||||
mod foo {
|
mod foo {
|
||||||
pub fn bar() -> S$0<()> {}
|
pub fn bar() -> S$0<()> {}
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
struct S<T>(T);
|
||||||
|
use S as IoResult;
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
use crate::S;
|
||||||
|
|
||||||
|
pub fn bar() -> S<()> {}
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn alias_local() {
|
fn alias_local() {
|
||||||
// FIXME
|
// FIXME wrong import
|
||||||
check_assist_not_applicable(
|
check_assist(
|
||||||
auto_import,
|
auto_import,
|
||||||
r#"
|
r#"
|
||||||
struct S<T>(T);
|
struct S<T>(T);
|
||||||
|
@ -1663,6 +1673,16 @@ use S as IoResult;
|
||||||
mod foo {
|
mod foo {
|
||||||
pub fn bar() -> IoResult$0<()> {}
|
pub fn bar() -> IoResult$0<()> {}
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
struct S<T>(T);
|
||||||
|
use S as IoResult;
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
use crate::S;
|
||||||
|
|
||||||
|
pub fn bar() -> IoResult<()> {}
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub(crate) fn format_string(
|
||||||
};
|
};
|
||||||
|
|
||||||
let source_range = TextRange::new(brace_offset, cursor);
|
let source_range = TextRange::new(brace_offset, cursor);
|
||||||
ctx.locals.iter().for_each(|(name, _)| {
|
ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()).for_each(|(name, _)| {
|
||||||
CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str())
|
CompletionItem::new(CompletionItemKind::Binding, source_range, name.to_smol_str())
|
||||||
.add_to(acc, ctx.db);
|
.add_to(acc, ctx.db);
|
||||||
});
|
});
|
||||||
|
|
|
@ -259,7 +259,7 @@ pub(super) fn add_call_parens<'b>(
|
||||||
|
|
||||||
fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str {
|
fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'static str {
|
||||||
if let Some(derefed_ty) = ty.remove_ref() {
|
if let Some(derefed_ty) = ty.remove_ref() {
|
||||||
for (name, local) in ctx.locals.iter() {
|
for (name, local) in ctx.locals.iter().sorted_by_key(|&(k, _)| k.clone()) {
|
||||||
if name.as_str() == arg {
|
if name.as_str() == arg {
|
||||||
return if local.ty(ctx.db) == derefed_ty {
|
return if local.ty(ctx.db) == derefed_ty {
|
||||||
if ty.is_mutable_reference() {
|
if ty.is_mutable_reference() {
|
||||||
|
|
|
@ -767,8 +767,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
|
||||||
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
|
||||||
|
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
|
||||||
me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,7 +15,7 @@ use syntax::{
|
||||||
use crate::{
|
use crate::{
|
||||||
helpers::item_name,
|
helpers::item_name,
|
||||||
items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
|
items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
|
||||||
RootDatabase,
|
FxIndexSet, RootDatabase,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A candidate for import, derived during various IDE activities:
|
/// A candidate for import, derived during various IDE activities:
|
||||||
|
@ -262,7 +262,7 @@ impl ImportAssets {
|
||||||
|
|
||||||
let scope = match sema.scope(&self.candidate_node) {
|
let scope = match sema.scope(&self.candidate_node) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => return <FxHashSet<_>>::default().into_iter(),
|
None => return <FxIndexSet<_>>::default().into_iter(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let krate = self.module_with_candidate.krate();
|
let krate = self.module_with_candidate.krate();
|
||||||
|
@ -319,7 +319,7 @@ fn path_applicable_imports(
|
||||||
path_candidate: &PathImportCandidate,
|
path_candidate: &PathImportCandidate,
|
||||||
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
|
mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy,
|
||||||
scope_filter: impl Fn(ItemInNs) -> bool + Copy,
|
scope_filter: impl Fn(ItemInNs) -> bool + Copy,
|
||||||
) -> FxHashSet<LocatedImport> {
|
) -> FxIndexSet<LocatedImport> {
|
||||||
let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
|
let _p = tracing::info_span!("ImportAssets::path_applicable_imports").entered();
|
||||||
|
|
||||||
match &path_candidate.qualifier {
|
match &path_candidate.qualifier {
|
||||||
|
@ -500,7 +500,7 @@ fn trait_applicable_items(
|
||||||
trait_assoc_item: bool,
|
trait_assoc_item: bool,
|
||||||
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
|
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
|
||||||
scope_filter: impl Fn(hir::Trait) -> bool,
|
scope_filter: impl Fn(hir::Trait) -> bool,
|
||||||
) -> FxHashSet<LocatedImport> {
|
) -> FxIndexSet<LocatedImport> {
|
||||||
let _p = tracing::info_span!("ImportAssets::trait_applicable_items").entered();
|
let _p = tracing::info_span!("ImportAssets::trait_applicable_items").entered();
|
||||||
|
|
||||||
let db = sema.db;
|
let db = sema.db;
|
||||||
|
@ -566,7 +566,7 @@ fn trait_applicable_items(
|
||||||
definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate()
|
definitions_exist_in_trait_crate || definitions_exist_in_receiver_crate()
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut located_imports = FxHashSet::default();
|
let mut located_imports = FxIndexSet::default();
|
||||||
let mut trait_import_paths = FxHashMap::default();
|
let mut trait_import_paths = FxHashMap::default();
|
||||||
|
|
||||||
if trait_assoc_item {
|
if trait_assoc_item {
|
||||||
|
|
|
@ -37,6 +37,7 @@ const _: () =
|
||||||
/// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or
|
/// A pointer that points to a pointer to a `str`, it may be backed as a `&'static &'static str` or
|
||||||
/// `Arc<Box<str>>` but its size is that of a thin pointer. The active variant is encoded as a tag
|
/// `Arc<Box<str>>` but its size is that of a thin pointer. The active variant is encoded as a tag
|
||||||
/// in the LSB of the alignment niche.
|
/// in the LSB of the alignment niche.
|
||||||
|
// Note, Ideally this would encode a `ThinArc<str>` and `ThinRef<str>`/`ThinConstPtr<str>` instead of the double indirection.
|
||||||
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
|
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
|
||||||
struct TaggedArcPtr {
|
struct TaggedArcPtr {
|
||||||
packed: NonNull<*const str>,
|
packed: NonNull<*const str>,
|
||||||
|
|
|
@ -13,6 +13,10 @@ use crate::{
|
||||||
|
|
||||||
macro_rules! define_symbols {
|
macro_rules! define_symbols {
|
||||||
(@WITH_NAME: $($alias:ident = $value:literal),* $(,)? @PLAIN: $($name:ident),* $(,)?) => {
|
(@WITH_NAME: $($alias:ident = $value:literal),* $(,)? @PLAIN: $($name:ident),* $(,)?) => {
|
||||||
|
// Ideally we would be emitting `const` here, but then we no longer have stable addresses
|
||||||
|
// which is what we are relying on for equality! In the future if consts can refer to
|
||||||
|
// statics we should swap these for `const`s and have the the string literal being pointed
|
||||||
|
// to be statics to refer to such that their address is stable.
|
||||||
$(
|
$(
|
||||||
pub static $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) };
|
pub static $name: Symbol = Symbol { repr: TaggedArcPtr::non_arc(&stringify!($name)) };
|
||||||
)*
|
)*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue