Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly record meaningful imports as re-exports in symbol index #18967

Merged
merged 5 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2"

[workspace.package]
rust-version = "1.82"
rust-version = "1.83"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
Expand Down
9 changes: 4 additions & 5 deletions crates/hir-def/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ bitflags::bitflags! {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData {
pub name: Name,
pub items: Vec<(Name, AssocItemId)>,
pub items: Box<[(Name, AssocItemId)]>,
pub flags: TraitFlags,
pub visibility: RawVisibility,
// box it as the vec is usually empty anyways
Expand Down Expand Up @@ -360,7 +360,7 @@ impl TraitAliasData {
pub struct ImplData {
pub target_trait: Option<TraitRef>,
pub self_ty: TypeRefId,
pub items: Box<[AssocItemId]>,
pub items: Box<[(Name, AssocItemId)]>,
pub is_negative: bool,
pub is_unsafe: bool,
// box it as the vec is usually empty anyways
Expand Down Expand Up @@ -393,7 +393,6 @@ impl ImplData {
collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);

let (items, macro_calls, diagnostics) = collector.finish();
let items = items.into_iter().map(|(_, item)| item).collect();

(
Arc::new(ImplData {
Expand Down Expand Up @@ -648,12 +647,12 @@ impl<'a> AssocItemCollector<'a> {
fn finish(
self,
) -> (
Vec<(Name, AssocItemId)>,
Box<[(Name, AssocItemId)]>,
Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
Vec<DefDiagnostic>,
) {
(
self.items,
self.items.into_boxed_slice(),
if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
self.diagnostics,
)
Expand Down
19 changes: 14 additions & 5 deletions crates/hir-def/src/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,20 @@ impl ItemScope {
.map(move |name| (name, self.get(name)))
}

pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportId>)> + '_ {
self.values.iter().map(|(n, &i)| (n, i))
}

pub fn types(
&self,
) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrExternCrate>)> + '_ {
self.types.iter().map(|(n, &i)| (n, i))
}

pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportId>)> + '_ {
self.macros.iter().map(|(n, &i)| (n, i))
}

pub fn imports(&self) -> impl Iterator<Item = ImportId> + '_ {
self.use_imports_types
.keys()
Expand Down Expand Up @@ -263,11 +277,6 @@ impl ItemScope {
self.unnamed_consts.iter().copied()
}

/// Iterate over all module scoped macros
pub(crate) fn macros(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ {
self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
}

/// Iterate over all legacy textual scoped macros visible at the end of the module
pub fn legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_ {
self.legacy_macros.iter().map(|(name, def)| (name, &**def))
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/lang_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl LangItems {
for (_, module_data) in crate_def_map.modules() {
for impl_def in module_data.scope.impls() {
lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef);
for assoc in db.impl_data(impl_def).items.iter().copied() {
for &(_, assoc) in db.impl_data(impl_def).items.iter() {
match assoc {
AssocItemId::FunctionId(f) => {
lang_items.collect_lang_item(db, f, LangItemTarget::Function)
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-def/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ impl ModuleId {
}

/// Whether this module represents the crate root module
fn is_crate_root(&self) -> bool {
pub fn is_crate_root(&self) -> bool {
self.local_id == DefMap::ROOT && self.block.is_none()
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-def/src/nameres/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,8 +717,8 @@ impl DefCollector<'_> {
}
}
None => {
for (name, def) in root_scope.macros() {
self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate));
for (name, it) in root_scope.macros() {
self.def_map.macro_use_prelude.insert(name.clone(), (it.def, extern_crate));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-def/src/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,12 @@ impl Visibility {

if a_ancestors.any(|m| m == mod_b.local_id) {
// B is above A
return Some(Visibility::Module(mod_a, expl_b));
return Some(Visibility::Module(mod_a, expl_a));
}

if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B
return Some(Visibility::Module(mod_b, expl_a));
return Some(Visibility::Module(mod_b, expl_b));
}

None
Expand Down
40 changes: 33 additions & 7 deletions crates/hir-expand/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use syntax::utils::is_raw_identifier;
/// and declarations. In theory, names should also carry hygiene info, but we are
/// not there yet!
///
/// Note that the rawness (`r#`) of names does not depend on whether they are written raw.
/// Note that the rawness (`r#`) of names is not preserved. Names are always stored without a `r#` prefix.
/// This is because we want to show (in completions etc.) names as raw depending on the needs
/// of the current crate, for example if it is edition 2021 complete `gen` even if the defining
/// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well.
Expand Down Expand Up @@ -77,6 +77,7 @@ impl Name {
/// Hopefully, this should allow us to integrate hygiene cleaner in the
/// future, and to switch to interned representation of names.
fn new_text(text: &str) -> Name {
debug_assert!(!text.starts_with("r#"));
Name { symbol: Symbol::intern(text), ctx: () }
}

Expand All @@ -91,15 +92,34 @@ impl Name {

pub fn new_root(text: &str) -> Name {
// The edition doesn't matter for hygiene.
Self::new(text, SyntaxContextId::root(Edition::Edition2015))
Self::new(text.trim_start_matches("r#"), SyntaxContextId::root(Edition::Edition2015))
}

pub fn new_tuple_field(idx: usize) -> Name {
Name { symbol: Symbol::intern(&idx.to_string()), ctx: () }
let symbol = match idx {
0 => sym::INTEGER_0.clone(),
1 => sym::INTEGER_1.clone(),
2 => sym::INTEGER_2.clone(),
3 => sym::INTEGER_3.clone(),
4 => sym::INTEGER_4.clone(),
5 => sym::INTEGER_5.clone(),
6 => sym::INTEGER_6.clone(),
7 => sym::INTEGER_7.clone(),
8 => sym::INTEGER_8.clone(),
9 => sym::INTEGER_9.clone(),
10 => sym::INTEGER_10.clone(),
11 => sym::INTEGER_11.clone(),
12 => sym::INTEGER_12.clone(),
13 => sym::INTEGER_13.clone(),
14 => sym::INTEGER_14.clone(),
15 => sym::INTEGER_15.clone(),
_ => Symbol::intern(&idx.to_string()),
};
Name { symbol, ctx: () }
}

pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () }
Self::new_text(lt.text().as_str().trim_start_matches("r#"))
}

/// Resolve a name from the text of token.
Expand Down Expand Up @@ -142,15 +162,18 @@ impl Name {
}

/// Returns the text this name represents if it isn't a tuple field.
///
/// Do not use this for user-facing text, use `display` instead to handle editions properly.
pub fn as_str(&self) -> &str {
self.symbol.as_str()
}

// FIXME: Remove this
pub fn unescaped(&self) -> UnescapedName<'_> {
UnescapedName(self)
}

pub fn is_escaped(&self, edition: Edition) -> bool {
pub fn needs_escape(&self, edition: Edition) -> bool {
is_raw_identifier(self.symbol.as_str(), edition)
}

Expand All @@ -173,16 +196,19 @@ impl Name {
&self.symbol
}

pub const fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
debug_assert!(!symbol.as_str().starts_with("r#"));
_ = ctx;
Self { symbol, ctx: () }
}

// FIXME: This needs to go once we have hygiene
pub const fn new_symbol_root(sym: Symbol) -> Self {
pub fn new_symbol_root(sym: Symbol) -> Self {
debug_assert!(!sym.as_str().starts_with("r#"));
Self { symbol: sym, ctx: () }
}

// FIXME: Remove this
#[inline]
pub fn eq_ident(&self, ident: &str) -> bool {
self.as_str() == ident.trim_start_matches("r#")
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/chalk_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ fn impl_def_datum(
let associated_ty_value_ids = impl_data
.items
.iter()
.filter_map(|item| match item {
.filter_map(|(_, item)| match item {
AssocItemId::TypeAliasId(type_alias) => Some(*type_alias),
_ => None,
})
Expand Down
26 changes: 12 additions & 14 deletions crates/hir-ty/src/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -746,16 +746,9 @@ fn lookup_impl_assoc_item_for_trait_ref(
let table = InferenceTable::new(db, env);

let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?;
let item = impl_data.items.iter().find_map(|&it| match it {
AssocItemId::FunctionId(f) => {
(db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f))
}
AssocItemId::ConstId(c) => db
.const_data(c)
.name
.as_ref()
.map(|n| n == name)
.and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }),
let item = impl_data.items.iter().find_map(|(n, it)| match *it {
AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
AssocItemId::TypeAliasId(_) => None,
})?;
Some((item, impl_subst))
Expand Down Expand Up @@ -850,7 +843,7 @@ fn is_inherent_impl_coherent(
};
rustc_has_incoherent_inherent_impls
&& !impl_data.items.is_empty()
&& impl_data.items.iter().copied().all(|assoc| match assoc {
&& impl_data.items.iter().all(|&(_, assoc)| match assoc {
AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl,
AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl,
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl,
Expand Down Expand Up @@ -1399,7 +1392,7 @@ fn iterate_inherent_methods(
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
for &impl_id in impls.for_self_ty(self_ty) {
for &item in table.db.impl_data(impl_id).items.iter() {
for &(ref item_name, item) in table.db.impl_data(impl_id).items.iter() {
let visible = match is_valid_impl_method_candidate(
table,
self_ty,
Expand All @@ -1408,6 +1401,7 @@ fn iterate_inherent_methods(
name,
impl_id,
item,
item_name,
) {
IsValidCandidate::Yes => true,
IsValidCandidate::NotVisible => false,
Expand Down Expand Up @@ -1467,6 +1461,7 @@ fn is_valid_impl_method_candidate(
name: Option<&Name>,
impl_id: ImplId,
item: AssocItemId,
item_name: &Name,
) -> IsValidCandidate {
match item {
AssocItemId::FunctionId(f) => is_valid_impl_fn_candidate(
Expand All @@ -1477,11 +1472,12 @@ fn is_valid_impl_method_candidate(
receiver_ty,
self_ty,
visible_from_module,
item_name,
),
AssocItemId::ConstId(c) => {
let db = table.db;
check_that!(receiver_ty.is_none());
check_that!(name.is_none_or(|n| db.const_data(c).name.as_ref() == Some(n)));
check_that!(name.is_none_or(|n| n == item_name));

if let Some(from_module) = visible_from_module {
if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
Expand Down Expand Up @@ -1565,11 +1561,13 @@ fn is_valid_impl_fn_candidate(
receiver_ty: Option<&Ty>,
self_ty: &Ty,
visible_from_module: Option<ModuleId>,
item_name: &Name,
) -> IsValidCandidate {
check_that!(name.is_none_or(|n| n == item_name));

let db = table.db;
let data = db.function_data(fn_id);

check_that!(name.is_none_or(|n| n == &data.name));
if let Some(from_module) = visible_from_module {
if !db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module) {
cov_mark::hit!(autoderef_candidate_not_visible);
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ pub(crate) fn visit_module(
visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb);
for impl_id in crate_def_map[module_id].scope.impls() {
let impl_data = db.impl_data(impl_id);
for &item in impl_data.items.iter() {
for &(_, item) in impl_data.items.iter() {
match item {
AssocItemId::FunctionId(it) => {
let body = db.body(it.into());
Expand Down
1 change: 1 addition & 0 deletions crates/hir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ itertools.workspace = true
smallvec.workspace = true
tracing.workspace = true
triomphe.workspace = true
indexmap.workspace = true

# local deps
base-db.workspace = true
Expand Down
Loading
Loading