name::{name, Name},
MacroDefId,
};
+use indexmap::IndexMap;
use rustc_hash::FxHashSet;
+use smallvec::{smallvec, SmallVec};
use crate::{
body::scope::{ExprScopes, ScopeId},
db::DefDatabase,
expr::{ExprId, LabelId, PatId},
generics::GenericParams,
+ intern::Interned,
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
nameres::DefMap,
path::{ModPath, PathKind},
per_ns::PerNs,
visibility::{RawVisibility, Visibility},
- AdtId, AssocContainerId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
- FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, LifetimeParamId, LocalModuleId,
- Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
- VariantId,
+ AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
+ FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+ LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
+ TypeParamId, VariantId,
};
#[derive(Debug, Clone, Default)]
pub struct Resolver {
- // FIXME: all usages generally call `.rev`, so maybe reverse once in construction?
+ /// The stack of scopes, where the inner-most scope is the last item.
+ ///
+ /// When using, you generally want to process the scopes in reverse order,
+ /// there's `scopes` *method* for that.
scopes: Vec<Scope>,
}
/// All the items and imported names of a module
ModuleScope(ModuleItemMap),
/// Brings the generic parameters of an item into scope
- GenericParams { def: GenericDefId, params: Arc<GenericParams> },
+ GenericParams { def: GenericDefId, params: Interned<GenericParams> },
/// Brings `Self` in `impl` block into scope
ImplDefScope(ImplId),
/// Brings `Self` in enum, struct and union definitions into scope
}
}
+ fn scopes(&self) -> impl Iterator<Item = &Scope> {
+ self.scopes.iter().rev()
+ }
+
fn resolve_module_path(
&self,
db: &dyn DefDatabase,
Some(it) => it,
None => return PerNs::none(),
};
- let (module_res, segment_index) = item_map.resolve_path(db, module, &path, shadow);
+ let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
if segment_index.is_some() {
return PerNs::none();
}
self.resolve_module_path(db, path, BuiltinShadowMode::Module)
}
- pub fn resolve_module_path_in_trait_items(
+ pub fn resolve_module_path_in_trait_assoc_items(
&self,
db: &dyn DefDatabase,
path: &ModPath,
- ) -> Option<TraitId> {
+ ) -> Option<PerNs> {
let (item_map, module) = self.module_scope()?;
- let (module_res, ..) = item_map.resolve_path(db, module, &path, BuiltinShadowMode::Module);
+ let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
match module_res.take_types()? {
- ModuleDefId::TraitId(it) => Some(it),
+ ModuleDefId::TraitId(it) => {
+ let idx = idx?;
+ let unresolved = &path.segments()[idx..];
+ let assoc = match unresolved {
+ [it] => it,
+ _ => return None,
+ };
+ let &(_, assoc) = db.trait_data(it).items.iter().find(|(n, _)| n == assoc)?;
+ Some(match assoc {
+ AssocItemId::FunctionId(it) => PerNs::values(it.into(), Visibility::Public),
+ AssocItemId::ConstId(it) => PerNs::values(it.into(), Visibility::Public),
+ AssocItemId::TypeAliasId(it) => PerNs::types(it.into(), Visibility::Public),
+ })
+ }
_ => None,
}
}
) -> Option<(TypeNs, Option<usize>)> {
let first_name = path.segments().first()?;
let skip_to_mod = path.kind != PathKind::Plain;
- for scope in self.scopes.iter().rev() {
+ for scope in self.scopes() {
match scope {
Scope::ExprScope(_) => continue,
Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
let tmp = name![self];
let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
- for scope in self.scopes.iter().rev() {
+ for scope in self.scopes() {
match scope {
Scope::AdtScope(_)
| Scope::ExprScope(_)
path: &ModPath,
) -> Option<MacroDefId> {
let (item_map, module) = self.module_scope()?;
- item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros()
- }
-
- pub fn process_all_names(&self, db: &dyn DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
- for scope in self.scopes.iter().rev() {
- scope.process_names(db, f);
+ item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
+ }
+
+ /// Returns a set of names available in the current scope.
+ ///
+ /// Note that this is a somewhat fuzzy concept -- internally, the compiler
+ /// doesn't necessary follow a strict scoping discipline. Rathe, it just
+ /// tells for each ident what it resolves to.
+ ///
+ /// A good example is something like `str::from_utf8`. From scopes point of
+ /// view, this code is erroneous -- both `str` module and `str` type occupy
+ /// the same type namespace.
+ ///
+ /// We don't try to model that super-correctly -- this functionality is
+ /// primarily exposed for completions.
+ ///
+ /// Note that in Rust one name can be bound to several items:
+ ///
+ /// ```
+ /// macro_rules! t { () => (()) }
+ /// type t = t!();
+ /// const t: t = t!()
+ /// ```
+ ///
+ /// That's why we return a multimap.
+ ///
+ /// The shadowing is accounted for: in
+ ///
+ /// ```
+ /// let x = 92;
+ /// {
+ /// let x = 92;
+ /// $0
+ /// }
+ /// ```
+ ///
+ /// there will be only one entry for `x` in the result.
+ ///
+ /// The result is ordered *roughly* from the innermost scope to the
+ /// outermost: when the name is introduced in two namespaces in two scopes,
+ /// we use the position of the first scope.
+ pub fn names_in_scope(&self, db: &dyn DefDatabase) -> IndexMap<Name, SmallVec<[ScopeDef; 1]>> {
+ let mut res = ScopeNames::default();
+ for scope in self.scopes() {
+ scope.process_names(db, &mut res);
}
+ res.map
}
pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
let mut traits = FxHashSet::default();
- for scope in &self.scopes {
- if let Scope::ModuleScope(m) = scope {
- 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() {
+ for scope in self.scopes() {
+ match scope {
+ Scope::ModuleScope(m) => {
+ 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(def_map[module].scope.traits());
- None::<()>
- });
+ 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::<()>
+ });
+ }
+ &Scope::ImplDefScope(impl_) => {
+ if let Some(target_trait) = &db.impl_data(impl_).target_trait {
+ if let Some(TypeNs::TraitId(trait_)) =
+ self.resolve_path_in_type_ns_fully(db, target_trait.path.mod_path())
+ {
+ traits.insert(trait_);
+ }
+ }
+ }
+ _ => (),
}
}
traits
}
fn module_scope(&self) -> Option<(&DefMap, LocalModuleId)> {
- self.scopes.iter().rev().find_map(|scope| match scope {
+ self.scopes().find_map(|scope| match scope {
Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
_ => None,
self.module_scope().map(|t| t.0.krate())
}
- pub fn where_predicates_in_scope<'a>(
- &'a self,
- ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a {
- self.scopes
- .iter()
- .rev()
+ pub fn where_predicates_in_scope(
+ &self,
+ ) -> impl Iterator<Item = &crate::generics::WherePredicate> {
+ self.scopes()
.filter_map(|scope| match scope {
Scope::GenericParams { params, .. } => Some(params),
_ => None,
}
pub fn generic_def(&self) -> Option<GenericDefId> {
- self.scopes.iter().rev().find_map(|scope| match scope {
+ self.scopes().find_map(|scope| match scope {
Scope::GenericParams { def, .. } => Some(*def),
_ => None,
})
}
pub fn body_owner(&self) -> Option<DefWithBodyId> {
- self.scopes.iter().rev().find_map(|scope| match scope {
+ self.scopes().find_map(|scope| match scope {
Scope::ExprScope(it) => Some(it.owner),
_ => None,
})
}
}
+#[derive(Debug, PartialEq, Eq)]
pub enum ScopeDef {
- PerNs(PerNs),
+ ModuleDef(ModuleDefId),
+ MacroDef(MacroDefId),
+ Unknown,
ImplSelfType(ImplId),
AdtSelfType(AdtId),
GenericParam(GenericParamId),
}
impl Scope {
- fn process_names(&self, db: &dyn DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
- let mut seen = FxHashSet::default();
+ fn process_names(&self, db: &dyn DefDatabase, acc: &mut ScopeNames) {
match self {
Scope::ModuleScope(m) => {
// FIXME: should we provide `self` here?
// }),
// );
m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
- f(name.clone(), ScopeDef::PerNs(def));
+ acc.add_per_ns(name, def);
});
- m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
- let scope = PerNs::macros(macro_, Visibility::Public);
- seen.insert((name.clone(), scope));
- f(name.clone(), ScopeDef::PerNs(scope));
+ m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, mac)| {
+ acc.add(name, ScopeDef::MacroDef(mac));
});
m.def_map.extern_prelude().for_each(|(name, &def)| {
- f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public)));
+ acc.add(name, ScopeDef::ModuleDef(def));
});
BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
- f(name.clone(), ScopeDef::PerNs(def));
+ acc.add_per_ns(name, def);
});
if let Some(prelude) = m.def_map.prelude() {
let prelude_def_map = prelude.def_map(db);
- prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
- let seen_tuple = (name.clone(), def);
- if !seen.contains(&seen_tuple) {
- f(seen_tuple.0, ScopeDef::PerNs(def));
- }
- });
+ for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
+ acc.add_per_ns(name, def)
+ }
}
}
- &Scope::GenericParams { ref params, def: parent } => {
+ Scope::GenericParams { params, def: parent } => {
+ let parent = *parent;
for (local_id, param) in params.types.iter() {
- if let Some(ref name) = param.name {
- let id = TypeParamId { local_id, parent };
- f(name.clone(), ScopeDef::GenericParam(id.into()))
+ if let Some(name) = ¶m.name {
+ let id = TypeParamId { parent, local_id };
+ acc.add(name, ScopeDef::GenericParam(id.into()))
}
}
for (local_id, param) in params.consts.iter() {
- let id = ConstParamId { local_id, parent };
- f(param.name.clone(), ScopeDef::GenericParam(id.into()))
+ let id = ConstParamId { parent, local_id };
+ acc.add(¶m.name, ScopeDef::GenericParam(id.into()))
}
for (local_id, param) in params.lifetimes.iter() {
- let id = LifetimeParamId { local_id, parent };
- f(param.name.clone(), ScopeDef::GenericParam(id.into()))
+ let id = LifetimeParamId { parent, local_id };
+ acc.add(¶m.name, ScopeDef::GenericParam(id.into()))
}
}
Scope::ImplDefScope(i) => {
- f(name![Self], ScopeDef::ImplSelfType(*i));
+ acc.add(&name![Self], ScopeDef::ImplSelfType(*i));
}
Scope::AdtScope(i) => {
- f(name![Self], ScopeDef::AdtSelfType(*i));
+ acc.add(&name![Self], ScopeDef::AdtSelfType(*i));
}
Scope::ExprScope(scope) => {
if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) {
- f(name.clone(), ScopeDef::Label(label))
+ acc.add(&name, ScopeDef::Label(label))
}
scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
- f(e.name().clone(), ScopeDef::Local(e.pat()));
+ acc.add_local(e.name(), e.pat());
});
}
}
let mut r = owner.resolver(db);
let scopes = db.expr_scopes(owner);
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
+ r.scopes.reserve(scope_chain.len());
+
for scope in scope_chain.into_iter().rev() {
if let Some(block) = scopes.block(scope) {
if let Some(def_map) = db.block_def_map(block) {
path: &ModPath,
) -> Option<ResolveValueResult> {
let (module_def, idx) =
- self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
+ self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
match idx {
None => {
let value = to_value_ns(module_def)?;
path: &ModPath,
) -> Option<(TypeNs, Option<usize>)> {
let (module_def, idx) =
- self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other);
+ self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
let res = to_type_ns(module_def)?;
Some((res, idx))
}
ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
- ModuleDefId::AdtId(AdtId::EnumId(_))
- | ModuleDefId::AdtId(AdtId::UnionId(_))
+ ModuleDefId::AdtId(AdtId::EnumId(_) | AdtId::UnionId(_))
| ModuleDefId::TraitId(_)
| ModuleDefId::TypeAliasId(_)
| ModuleDefId::BuiltinType(_)
Some(res)
}
+#[derive(Default)]
+struct ScopeNames {
+ map: IndexMap<Name, SmallVec<[ScopeDef; 1]>>,
+}
+
+impl ScopeNames {
+ fn add(&mut self, name: &Name, def: ScopeDef) {
+ let set = self.map.entry(name.clone()).or_default();
+ if !set.contains(&def) {
+ set.push(def)
+ }
+ }
+ fn add_per_ns(&mut self, name: &Name, def: PerNs) {
+ if let Some(ty) = &def.types {
+ self.add(name, ScopeDef::ModuleDef(ty.0))
+ }
+ if let Some(val) = &def.values {
+ self.add(name, ScopeDef::ModuleDef(val.0))
+ }
+ if let Some(mac) = &def.macros {
+ self.add(name, ScopeDef::MacroDef(mac.0))
+ }
+ if def.is_none() {
+ self.add(name, ScopeDef::Unknown)
+ }
+ }
+ fn add_local(&mut self, name: &Name, pat: PatId) {
+ let set = self.map.entry(name.clone()).or_default();
+ // XXX: hack, account for local (and only local) shadowing.
+ //
+ // This should be somewhat more principled and take namespaces into
+ // accounts, but, alas, scoping rules are a hoax. `str` type and `str`
+ // module can be both available in the same scope.
+ if set.iter().any(|it| matches!(it, &ScopeDef::Local(_))) {
+ cov_mark::hit!(shadowing_shows_single_completion);
+ return;
+ }
+ set.push(ScopeDef::Local(pat))
+ }
+}
+
pub trait HasResolver: Copy {
/// Builds a resolver for type references inside this def.
fn resolver(self, db: &dyn DefDatabase) -> Resolver;
impl HasResolver for ModuleId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
- let def_map = self.def_map(db);
- Resolver::default().push_module_scope(def_map, self.local_id)
+ let mut def_map = self.def_map(db);
+ let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
+ while let Some(parent) = def_map.parent() {
+ def_map = parent.def_map(db);
+ modules.push((def_map.clone(), parent.local_id));
+ }
+ let mut resolver = Resolver::default();
+ resolver.scopes.reserve(modules.len());
+ for (def_map, module) in modules.into_iter().rev() {
+ resolver = resolver.push_module_scope(def_map, module);
+ }
+ resolver
}
}
}
}
+impl HasResolver for ExternBlockId {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
+ // Same as parent's
+ self.lookup(db).container.resolver(db)
+ }
+}
+
impl HasResolver for DefWithBodyId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
match self {
}
}
-impl HasResolver for AssocContainerId {
+impl HasResolver for ItemContainerId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
match self {
- AssocContainerId::ModuleId(it) => it.resolver(db),
- AssocContainerId::TraitId(it) => it.resolver(db),
- AssocContainerId::ImplId(it) => it.resolver(db),
+ ItemContainerId::ModuleId(it) => it.resolver(db),
+ ItemContainerId::TraitId(it) => it.resolver(db),
+ ItemContainerId::ImplId(it) => it.resolver(db),
+ ItemContainerId::ExternBlockId(it) => it.resolver(db),
}
}
}