]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/resolver.rs
parameters.split_last()
[rust.git] / crates / hir_def / src / resolver.rs
index 4a2d1c08752d3c0a1b7defaec31457132a8e49bf..9f68b800a55ebd8571ef5654c1e3452fcb36f8e2 100644 (file)
@@ -6,7 +6,9 @@
     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>,
 }
 
@@ -50,7 +56,7 @@ enum 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
@@ -122,6 +128,10 @@ pub fn resolve_known_enum(&self, db: &dyn DefDatabase, path: &ModPath) -> Option
         }
     }
 
+    fn scopes(&self) -> impl Iterator<Item = &Scope> {
+        self.scopes.iter().rev()
+    }
+
     fn resolve_module_path(
         &self,
         db: &dyn DefDatabase,
@@ -132,7 +142,7 @@ fn resolve_module_path(
             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();
         }
@@ -143,15 +153,28 @@ pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath)
         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,
         }
     }
@@ -163,7 +186,7 @@ pub fn resolve_path_in_type_ns(
     ) -> 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,
@@ -237,7 +260,7 @@ pub fn resolve_path_in_value_ns(
         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(_)
@@ -324,41 +347,93 @@ pub fn resolve_path_as_macro(
         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,
@@ -375,12 +450,10 @@ pub fn krate(&self) -> Option<CrateId> {
         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,
@@ -389,22 +462,25 @@ pub fn where_predicates_in_scope<'a>(
     }
 
     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),
@@ -413,8 +489,7 @@ pub enum ScopeDef {
 }
 
 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?
@@ -425,57 +500,53 @@ fn process_names(&self, db: &dyn DefDatabase, f: &mut dyn FnMut(Name, ScopeDef))
                 //     }),
                 // );
                 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) = &param.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(&param.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(&param.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());
                 });
             }
         }
@@ -496,6 +567,8 @@ pub fn resolver_for_scope(
     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) {
@@ -548,7 +621,7 @@ fn resolve_path_in_value_ns(
         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)?;
@@ -578,7 +651,7 @@ fn resolve_path_in_type_ns(
         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))
     }
@@ -592,8 +665,7 @@ fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
         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(_)
@@ -620,6 +692,47 @@ fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
     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;
@@ -627,8 +740,18 @@ pub trait HasResolver: Copy {
 
 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
     }
 }
 
@@ -682,6 +805,13 @@ fn resolver(self, db: &dyn DefDatabase) -> 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 {
@@ -692,12 +822,13 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
     }
 }
 
-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),
         }
     }
 }