Skip to content

Clarify the state of (extern) preludes for block def maps #13175

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

Merged
merged 1 commit into from
Sep 2, 2022
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
4 changes: 4 additions & 0 deletions crates/hir-def/src/nameres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ pub struct DefMap {
/// The prelude module for this crate. This either comes from an import
/// marked with the `prelude_import` attribute, or (in the normal case) from
/// a dependency (`std` or `core`).
/// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
/// but that attribute is nightly and when used in a block, it affects resolution globally
/// so we aren't handling this correctly anyways).
prelude: Option<ModuleId>,
/// The extern prelude is only populated for non-block DefMaps
extern_prelude: FxHashMap<Name, ModuleId>,

/// Side table for resolving derive helpers.
Expand Down
13 changes: 7 additions & 6 deletions crates/hir-def/src/nameres/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,10 +512,9 @@ impl DefCollector<'_> {
Edition::Edition2021 => name![rust_2021],
};

let path_kind = if self.def_map.edition == Edition::Edition2015 {
PathKind::Plain
} else {
PathKind::Abs
let path_kind = match self.def_map.edition {
Edition::Edition2015 => PathKind::Plain,
_ => PathKind::Abs,
};
let path =
ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
Expand All @@ -535,7 +534,6 @@ impl DefCollector<'_> {
match per_ns.types {
Some((ModuleDefId::ModuleId(m), _)) => {
self.def_map.prelude = Some(m);
return;
}
types => {
tracing::debug!(
Expand Down Expand Up @@ -850,7 +848,10 @@ impl DefCollector<'_> {
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);

// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
if import.is_extern_crate && module_id == self.def_map.root {
if import.is_extern_crate
&& self.def_map.block.is_none()
&& module_id == self.def_map.root
{
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
{
self.def_map.extern_prelude.insert(name.clone(), def);
Expand Down
103 changes: 49 additions & 54 deletions crates/hir-def/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,34 +368,43 @@ impl Resolver {
for scope in self.scopes() {
scope.process_names(&mut res, db);
}
process_module_scope_names(&mut res, db, &self.module_scope);
let ModuleItemMap { ref def_map, module_id } = self.module_scope;
// FIXME: should we provide `self` here?
// f(
// Name::self_param(),
// PerNs::types(Resolution::Def {
// def: m.module.into(),
// }),
// );
def_map[module_id].scope.entries().for_each(|(name, def)| {
res.add_per_ns(name, def);
});
def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| {
macs.iter().for_each(|&mac| {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))));
})
});
def_map.extern_prelude().for_each(|(name, &def)| {
res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
});
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
res.add_per_ns(name, def);
});
if let Some(prelude) = def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
res.add_per_ns(name, def)
}
}
res.map
}

pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
let mut traits = FxHashSet::default();

let collect_module_traits = |traits: &mut FxHashSet<_>, m: &ModuleItemMap| {
if let Some(prelude) = m.def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
traits.extend(prelude_def_map[prelude.local_id].scope.traits());
}
traits.extend(m.def_map[m.module_id].scope.traits());

// Add all traits that are in scope because of the containing DefMaps
m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
if let Some(prelude) = def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
traits.extend(prelude_def_map[prelude.local_id].scope.traits());
}
traits.extend(def_map[module].scope.traits());
None::<()>
});
};

for scope in self.scopes() {
match scope {
Scope::BlockScope(m) => collect_module_traits(&mut traits, m),
Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
&Scope::ImplDefScope(impl_) => {
if let Some(target_trait) = &db.impl_data(impl_).target_trait {
if let Some(TypeNs::TraitId(trait_)) =
Expand All @@ -409,7 +418,13 @@ impl Resolver {
}
}

collect_module_traits(&mut traits, &self.module_scope);
// Fill in the prelude traits
if let Some(prelude) = self.module_scope.def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
traits.extend(prelude_def_map[prelude.local_id].scope.traits());
}
// Fill in module visible traits
traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits());
traits
}

Expand Down Expand Up @@ -493,42 +508,22 @@ pub enum ScopeDef {
Label(LabelId),
}

fn process_module_scope_names(acc: &mut ScopeNames, db: &dyn DefDatabase, m: &ModuleItemMap) {
// FIXME: should we provide `self` here?
// f(
// Name::self_param(),
// PerNs::types(Resolution::Def {
// def: m.module.into(),
// }),
// );
m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
acc.add_per_ns(name, def);
});
m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| {
macs.iter().for_each(|&mac| {
acc.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))));
})
});
m.def_map.extern_prelude().for_each(|(name, &def)| {
acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
});
if m.def_map.block_id().is_none() {
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
acc.add_per_ns(name, def);
});
}
if let Some(prelude) = m.def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
acc.add_per_ns(name, def)
}
}
}

impl Scope {
fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
match self {
Scope::BlockScope(m) => process_module_scope_names(acc, db, m),
Scope::BlockScope(m) => {
m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
acc.add_per_ns(name, def);
});
m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| {
macs.iter().for_each(|&mac| {
acc.add(
name,
ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))),
);
})
});
}
Scope::GenericParams { params, def: parent } => {
let parent = *parent;
for (local_id, param) in params.type_or_consts.iter() {
Expand Down