Move CrateDefMap to hir_def

This commit is contained in:
Aleksey Kladov 2019-10-31 18:45:10 +03:00
parent f9f1effd01
commit ba2efca2bb
23 changed files with 824 additions and 731 deletions

View file

@ -9,7 +9,7 @@
adt::VariantData,
builtin_type::BuiltinType,
type_ref::{Mutability, TypeRef},
CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId,
CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId,
};
use hir_expand::{
diagnostics::DiagnosticSink,
@ -28,11 +28,11 @@
TypeAliasId,
},
impl_block::ImplBlock,
nameres::{ImportId, ModuleScope, Namespace},
nameres::{ImportId, Namespace},
resolve::{Resolver, Scope, TypeNs},
traits::TraitData,
ty::{InferenceResult, TraitRef},
Either, HasSource, Name, Ty,
Either, HasSource, Name, ScopeDef, Ty,
};
/// hir::Crate describes a single crate. It's the main interface with which
@ -66,7 +66,7 @@ pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> {
}
pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> {
let module_id = db.crate_def_map(self).root();
let module_id = db.crate_def_map(self.crate_id).root();
Some(Module::new(self, module_id))
}
@ -120,7 +120,7 @@ pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module {
/// Name of this module.
pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
let parent = def_map[self.id.module_id].parent?;
def_map[parent].children.iter().find_map(|(name, module_id)| {
if *module_id == self.id.module_id {
@ -151,20 +151,20 @@ pub fn krate(self) -> Crate {
/// might be missing `krate`. This can happen if a module's file is not included
/// in the module tree of any target in `Cargo.toml`.
pub fn crate_root(self, db: &impl DefDatabase) -> Module {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
self.with_module_id(def_map.root())
}
/// Finds a child module with the specified name.
pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
let child_id = def_map[self.id.module_id].children.get(name)?;
Some(self.with_module_id(*child_id))
}
/// Iterates over all child modules.
pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
let children = def_map[self.id.module_id]
.children
.iter()
@ -175,7 +175,7 @@ pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
/// Finds a parent module.
pub fn parent(self, db: &impl DefDatabase) -> Option<Module> {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
let parent_id = def_map[self.id.module_id].parent?;
Some(self.with_module_id(parent_id))
}
@ -191,12 +191,16 @@ pub fn path_to_root(self, db: &impl HirDatabase) -> Vec<Module> {
}
/// Returns a `ModuleScope`: a set of items, visible in this module.
pub fn scope(self, db: &impl HirDatabase) -> ModuleScope {
db.crate_def_map(self.krate())[self.id.module_id].scope.clone()
pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<ImportId>)> {
db.crate_def_map(self.id.krate)[self.id.module_id]
.scope
.entries()
.map(|(name, res)| (name.clone(), res.def.into(), res.import))
.collect()
}
pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
db.crate_def_map(self.krate()).add_diagnostics(db, self.id.module_id, sink);
db.crate_def_map(self.id.krate).add_diagnostics(db, self.id.module_id, sink);
for decl in self.declarations(db) {
match decl {
crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
@ -220,12 +224,12 @@ pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
}
pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
Resolver::default().push_module_scope(def_map, self.id.module_id)
}
pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
def_map[self.id.module_id]
.scope
.entries()
@ -233,6 +237,7 @@ pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> {
.flat_map(|per_ns| {
per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
})
.map(ModuleDef::from)
.collect()
}
@ -336,12 +341,12 @@ pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Union {
pub(crate) id: StructId,
pub(crate) id: UnionId,
}
impl Union {
pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
db.struct_data(self.id).name.clone()
db.union_data(self.id).name.clone()
}
pub fn module(self, db: &impl HirDatabase) -> Module {

View file

@ -22,7 +22,7 @@ pub trait HasSource {
impl Module {
/// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
let decl_id = def_map[self.id.module_id].declaration;
let file_id = def_map[self.id.module_id].definition;
let ast = ModuleSource::new(db, file_id, decl_id);
@ -36,7 +36,7 @@ pub fn declaration_source(
self,
db: &(impl DefDatabase + AstDatabase),
) -> Option<Source<ast::Module>> {
let def_map = db.crate_def_map(self.krate());
let def_map = db.crate_def_map(self.id.krate);
let decl = def_map[self.id.module_id].declaration?;
let ast = decl.to_node(db);
Some(Source { file_id: decl.file_id(), ast })

View file

@ -11,7 +11,7 @@
ids,
impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks},
lang_item::{LangItemTarget, LangItems},
nameres::{CrateDefMap, Namespace},
nameres::Namespace,
traits::TraitData,
ty::{
method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate,
@ -23,8 +23,8 @@
};
pub use hir_def::db::{
DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, InternDatabaseStorage,
RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery,
CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase,
InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery,
};
pub use hir_expand::db::{
AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@ -41,9 +41,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
#[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)]
fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex;
#[salsa::invoke(CrateDefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
#[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)]
fn impls_in_module_with_source_map(
&self,

View file

@ -3,10 +3,10 @@
use std::any::Any;
use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
use relative_path::RelativePathBuf;
use crate::{db::AstDatabase, HirFileId, Name, Source};
pub use hir_def::diagnostics::UnresolvedModule;
pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
#[derive(Debug)]
@ -29,25 +29,6 @@ fn as_any(&self) -> &(dyn Any + Send + 'static) {
}
}
#[derive(Debug)]
pub struct UnresolvedModule {
pub file: HirFileId,
pub decl: AstPtr<ast::Module>,
pub candidate: RelativePathBuf,
}
impl Diagnostic for UnresolvedModule {
fn message(&self) -> String {
"unresolved module".to_string()
}
fn source(&self) -> Source<SyntaxNodePtr> {
Source { file_id: self.file, ast: self.decl.into() }
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}
#[derive(Debug)]
pub struct MissingFields {
pub file: HirFileId,

View file

@ -0,0 +1,58 @@
use hir_def::{AdtId, EnumVariantId, ModuleDefId};
use crate::{Adt, EnumVariant, ModuleDef};
macro_rules! from_id {
($(($id:path, $ty:path)),*) => {$(
impl From<$id> for $ty {
fn from(id: $id) -> $ty {
$ty { id }
}
}
)*}
}
from_id![
(hir_def::ModuleId, crate::Module),
(hir_def::StructId, crate::Struct),
(hir_def::UnionId, crate::Union),
(hir_def::EnumId, crate::Enum),
(hir_def::TypeAliasId, crate::TypeAlias),
(hir_def::TraitId, crate::Trait),
(hir_def::StaticId, crate::Static),
(hir_def::ConstId, crate::Const),
(hir_def::FunctionId, crate::Function),
(hir_expand::MacroDefId, crate::MacroDef)
];
impl From<AdtId> for Adt {
fn from(id: AdtId) -> Self {
match id {
AdtId::StructId(it) => Adt::Struct(it.into()),
AdtId::UnionId(it) => Adt::Union(it.into()),
AdtId::EnumId(it) => Adt::Enum(it.into()),
}
}
}
impl From<EnumVariantId> for EnumVariant {
fn from(id: EnumVariantId) -> Self {
EnumVariant { parent: id.parent.into(), id: id.local_id }
}
}
impl From<ModuleDefId> for ModuleDef {
fn from(id: ModuleDefId) -> Self {
match id {
ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()),
ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()),
ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()),
ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()),
ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()),
ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()),
ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()),
ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()),
ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it),
}
}
}

View file

@ -149,14 +149,20 @@ pub fn from_definition(
ModuleSource::SourceFile(_) => None,
};
db.relevant_crates(src.file_id.original_file(db))
.iter()
.map(|&crate_id| Crate { crate_id })
.find_map(|krate| {
let def_map = db.crate_def_map(krate);
let module_id = def_map.find_module_by_source(src.file_id, decl_id)?;
Some(Module::new(krate, module_id))
})
db.relevant_crates(src.file_id.original_file(db)).iter().find_map(|&crate_id| {
let def_map = db.crate_def_map(crate_id);
let (module_id, _module_data) =
def_map.modules.iter().find(|(_module_id, module_data)| {
if decl_id.is_some() {
module_data.declaration == decl_id
} else {
module_data.definition.map(|it| it.into()) == Some(src.file_id)
}
})?;
Some(Module::new(Crate { crate_id }, module_id))
})
}
}

View file

@ -47,6 +47,7 @@ fn from(it: $sv) -> $e {
pub mod diagnostics;
mod util;
mod from_id;
mod code_model;
pub mod from_source;

View file

@ -47,512 +47,10 @@
//! path and, upon success, we run macro expansion and "collect module" phase
//! on the result
mod per_ns;
mod collector;
#[cfg(test)]
mod tests;
use std::sync::Arc;
use hir_def::{builtin_type::BuiltinType, CrateModuleId};
use hir_expand::diagnostics::DiagnosticSink;
use once_cell::sync::Lazy;
use ra_arena::Arena;
use ra_db::{Edition, FileId};
use ra_prof::profile;
use ra_syntax::ast;
use rustc_hash::{FxHashMap, FxHashSet};
use test_utils::tested_by;
use crate::{
db::{AstDatabase, DefDatabase},
ids::MacroDefId,
nameres::diagnostics::DefDiagnostic,
Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait,
pub use hir_def::nameres::{
per_ns::{Namespace, PerNs},
raw::ImportId,
};
pub use self::per_ns::{Namespace, PerNs};
pub use hir_def::nameres::raw::ImportId;
/// Contains all top-level defs from a macro-expanded crate
#[derive(Debug, PartialEq, Eq)]
pub struct CrateDefMap {
krate: Crate,
edition: Edition,
/// 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`).
prelude: Option<Module>,
extern_prelude: FxHashMap<Name, ModuleDef>,
root: CrateModuleId,
modules: Arena<CrateModuleId, ModuleData>,
/// Some macros are not well-behavior, which leads to infinite loop
/// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
/// We mark it down and skip it in collector
///
/// FIXME:
/// Right now it only handle a poison macro in a single crate,
/// such that if other crate try to call that macro,
/// the whole process will do again until it became poisoned in that crate.
/// We should handle this macro set globally
/// However, do we want to put it as a global variable?
poison_macros: FxHashSet<MacroDefId>,
diagnostics: Vec<DefDiagnostic>,
}
impl std::ops::Index<CrateModuleId> for CrateDefMap {
type Output = ModuleData;
fn index(&self, id: CrateModuleId) -> &ModuleData {
&self.modules[id]
}
}
#[derive(Default, Debug, PartialEq, Eq)]
pub struct ModuleData {
pub(crate) parent: Option<CrateModuleId>,
pub(crate) children: FxHashMap<Name, CrateModuleId>,
pub(crate) scope: ModuleScope,
/// None for root
pub(crate) declaration: Option<AstId<ast::Module>>,
/// None for inline modules.
///
/// Note that non-inline modules, by definition, live inside non-macro file.
pub(crate) definition: Option<FileId>,
}
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct ModuleScope {
items: FxHashMap<Name, Resolution>,
/// Macros visable in current module in legacy textual scope
///
/// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
/// If it yields no result, then it turns to module scoped `macros`.
/// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
/// and only normal scoped `macros` will be searched in.
///
/// Note that this automatically inherit macros defined textually before the definition of module itself.
///
/// Module scoped macros will be inserted into `items` instead of here.
// FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
// be all resolved to the last one defined if shadowing happens.
legacy_macros: FxHashMap<Name, MacroDef>,
}
static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
BuiltinType::ALL
.iter()
.map(|(name, ty)| {
(name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
})
.collect()
});
/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ModuleScope {
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
//FIXME: shadowing
self.items.iter().chain(BUILTIN_SCOPE.iter())
}
/// Iterate over all module scoped macros
pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
self.items
.iter()
.filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
}
/// Iterate over all legacy textual scoped macros visable at the end of the module
pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
self.legacy_macros.iter().map(|(name, def)| (name, *def))
}
/// Get a name from current module scope, legacy macros are not included
pub fn get(&self, name: &Name) -> Option<&Resolution> {
self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
}
pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
self.items.values().filter_map(|r| match r.def.take_types() {
Some(ModuleDef::Trait(t)) => Some(t),
_ => None,
})
}
fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> {
self.legacy_macros.get(name).copied()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Resolution {
/// None for unresolved
pub def: PerNs,
/// ident by which this is imported into local scope.
pub import: Option<ImportId>,
}
impl Resolution {
pub(crate) fn from_macro(macro_: MacroDef) -> Self {
Resolution { def: PerNs::macros(macro_), import: None }
}
}
#[derive(Debug, Clone)]
struct ResolvePathResult {
resolved_def: PerNs,
segment_index: Option<usize>,
reached_fixedpoint: ReachedFixedPoint,
}
impl ResolvePathResult {
fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
}
fn with(
resolved_def: PerNs,
reached_fixedpoint: ReachedFixedPoint,
segment_index: Option<usize>,
) -> ResolvePathResult {
ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ResolveMode {
Import,
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ReachedFixedPoint {
Yes,
No,
}
impl CrateDefMap {
pub(crate) fn crate_def_map_query(
// Note that this doesn't have `+ AstDatabase`!
// This gurantess that `CrateDefMap` is stable across reparses.
db: &impl DefDatabase,
krate: Crate,
) -> Arc<CrateDefMap> {
let _p = profile("crate_def_map_query");
let def_map = {
let edition = krate.edition(db);
let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
let root = modules.alloc(ModuleData::default());
CrateDefMap {
krate,
edition,
extern_prelude: FxHashMap::default(),
prelude: None,
root,
modules,
poison_macros: FxHashSet::default(),
diagnostics: Vec::new(),
}
};
let def_map = collector::collect_defs(db, def_map);
Arc::new(def_map)
}
pub(crate) fn krate(&self) -> Crate {
self.krate
}
pub(crate) fn root(&self) -> CrateModuleId {
self.root
}
pub(crate) fn prelude(&self) -> Option<Module> {
self.prelude
}
pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> {
&self.extern_prelude
}
pub(crate) fn add_diagnostics(
&self,
db: &(impl DefDatabase + AstDatabase),
module: CrateModuleId,
sink: &mut DiagnosticSink,
) {
self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
}
pub(crate) fn find_module_by_source(
&self,
file_id: HirFileId,
decl_id: Option<AstId<ast::Module>>,
) -> Option<CrateModuleId> {
let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
if decl_id.is_some() {
module_data.declaration == decl_id
} else {
module_data.definition.map(|it| it.into()) == Some(file_id)
}
})?;
Some(module_id)
}
pub(crate) fn resolve_path(
&self,
db: &impl DefDatabase,
original_module: CrateModuleId,
path: &Path,
) -> (PerNs, Option<usize>) {
let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
(res.resolved_def, res.segment_index)
}
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
// the result.
fn resolve_path_fp_with_macro(
&self,
db: &impl DefDatabase,
mode: ResolveMode,
original_module: CrateModuleId,
path: &Path,
) -> ResolvePathResult {
let mut segments = path.segments.iter().enumerate();
let mut curr_per_ns: PerNs = match path.kind {
PathKind::DollarCrate(crate_id) => {
let krate = Crate { crate_id };
if krate == self.krate {
tested_by!(macro_dollar_crate_self);
PerNs::types(Module::new(self.krate, self.root).into())
} else {
match krate.root_module(db) {
Some(module) => {
tested_by!(macro_dollar_crate_other);
PerNs::types(module.into())
}
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
}
}
}
PathKind::Crate => PerNs::types(Module::new(self.krate, self.root).into()),
PathKind::Self_ => PerNs::types(Module::new(self.krate, original_module).into()),
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
// FIXME there must be a nicer way to write this condition
PathKind::Plain | PathKind::Abs
if self.edition == Edition::Edition2015
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
{
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
}
PathKind::Plain => {
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
log::debug!("resolving {:?} in module", segment);
self.resolve_name_in_module(db, original_module, &segment.name)
}
PathKind::Super => {
if let Some(p) = self.modules[original_module].parent {
PerNs::types(Module::new(self.krate, p).into())
} else {
log::debug!("super path in root module");
return ResolvePathResult::empty(ReachedFixedPoint::Yes);
}
}
PathKind::Abs => {
// 2018-style absolute path -- only extern prelude
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
if let Some(def) = self.extern_prelude.get(&segment.name) {
log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
PerNs::types(*def)
} else {
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
}
}
PathKind::Type(_) => {
// This is handled in `infer::infer_path_expr`
// The result returned here does not matter
return ResolvePathResult::empty(ReachedFixedPoint::Yes);
}
};
for (i, segment) in segments {
let curr = match curr_per_ns.take_types() {
Some(r) => r,
None => {
// we still have path segments left, but the path so far
// didn't resolve in the types namespace => no resolution
// (don't break here because `curr_per_ns` might contain
// something in the value namespace, and it would be wrong
// to return that)
return ResolvePathResult::empty(ReachedFixedPoint::No);
}
};
// resolve segment in curr
curr_per_ns = match curr {
ModuleDef::Module(module) => {
if module.krate() != self.krate {
let path =
Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
log::debug!("resolving {:?} in other crate", path);
let defp_map = db.crate_def_map(module.krate());
let (def, s) = defp_map.resolve_path(db, module.id.module_id, &path);
return ResolvePathResult::with(
def,
ReachedFixedPoint::Yes,
s.map(|s| s + i),
);
}
// Since it is a qualified path here, it should not contains legacy macros
match self[module.id.module_id].scope.get(&segment.name) {
Some(res) => res.def,
_ => {
log::debug!("path segment {:?} not found", segment.name);
return ResolvePathResult::empty(ReachedFixedPoint::No);
}
}
}
ModuleDef::Adt(Adt::Enum(e)) => {
// enum variant
tested_by!(can_import_enum_variant);
match e.variant(db, &segment.name) {
Some(variant) => PerNs::both(variant.into(), variant.into()),
None => {
return ResolvePathResult::with(
PerNs::types(e.into()),
ReachedFixedPoint::Yes,
Some(i),
);
}
}
}
s => {
// could be an inherent method call in UFCS form
// (`Struct::method`), or some other kind of associated item
log::debug!(
"path segment {:?} resolved to non-module {:?}, but is not last",
segment.name,
curr,
);
return ResolvePathResult::with(
PerNs::types(s),
ReachedFixedPoint::Yes,
Some(i),
);
}
};
}
ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
}
fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
let from_crate_root =
self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
from_crate_root.or(from_extern_prelude)
}
pub(crate) fn resolve_name_in_module(
&self,
db: &impl DefDatabase,
module: CrateModuleId,
name: &Name,
) -> PerNs {
// Resolve in:
// - legacy scope of macro
// - current module / scope
// - extern prelude
// - std prelude
let from_legacy_macro =
self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
let from_extern_prelude =
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
let from_prelude = self.resolve_in_prelude(db, name);
from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
}
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
}
fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
if let Some(prelude) = self.prelude {
let keep;
let def_map = if prelude.krate() == self.krate {
self
} else {
// Extend lifetime
keep = db.crate_def_map(prelude.krate());
&keep
};
def_map[prelude.id.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
} else {
PerNs::none()
}
}
}
mod diagnostics {
use hir_expand::diagnostics::DiagnosticSink;
use ra_syntax::{ast, AstPtr};
use relative_path::RelativePathBuf;
use crate::{
db::{AstDatabase, DefDatabase},
diagnostics::UnresolvedModule,
nameres::CrateModuleId,
AstId,
};
#[derive(Debug, PartialEq, Eq)]
pub(super) enum DefDiagnostic {
UnresolvedModule {
module: CrateModuleId,
declaration: AstId<ast::Module>,
candidate: RelativePathBuf,
},
}
impl DefDiagnostic {
pub(super) fn add_to(
&self,
db: &(impl DefDatabase + AstDatabase),
target_module: CrateModuleId,
sink: &mut DiagnosticSink,
) {
match self {
DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
if *module != target_module {
return;
}
let decl = declaration.to_node(db);
sink.push(UnresolvedModule {
file: declaration.file_id(),
decl: AstPtr::new(&decl),
candidate: candidate.clone(),
})
}
}
}
}
}

View file

@ -6,30 +6,25 @@
use std::sync::Arc;
use hir_def::{db::DefDatabase2, nameres::*, CrateModuleId};
use insta::assert_snapshot;
use ra_db::SourceDatabase;
use test_utils::covers;
// use test_utils::covers;
use crate::{
mock::{CrateGraphFixture, MockDatabase},
Crate,
};
use super::*;
use crate::mock::{CrateGraphFixture, MockDatabase};
fn compute_crate_def_map(fixture: &str, graph: Option<CrateGraphFixture>) -> Arc<CrateDefMap> {
let mut db = MockDatabase::with_files(fixture);
if let Some(graph) = graph {
db.set_crate_graph_from_fixture(graph);
}
let crate_id = db.crate_graph().iter().next().unwrap();
let krate = Crate { crate_id };
let krate = db.crate_graph().iter().next().unwrap();
db.crate_def_map(krate)
}
fn render_crate_def_map(map: &CrateDefMap) -> String {
let mut buf = String::new();
go(&mut buf, map, "\ncrate", map.root);
go(&mut buf, map, "\ncrate", map.root());
return buf.trim().to_string();
fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) {
@ -118,7 +113,7 @@ enum E { V }
#[test]
fn bogus_paths() {
covers!(bogus_paths);
// covers!(bogus_paths);
let map = def_map(
"
//- /lib.rs
@ -233,7 +228,7 @@ fn re_exports() {
#[test]
fn std_prelude() {
covers!(std_prelude);
// covers!(std_prelude);
let map = def_map_with_crate_graph(
"
//- /main.rs
@ -261,7 +256,7 @@ fn std_prelude() {
#[test]
fn can_import_enum_variant() {
covers!(can_import_enum_variant);
// covers!(can_import_enum_variant);
let map = def_map(
"
//- /lib.rs

View file

@ -75,7 +75,7 @@ fn glob_2() {
#[test]
fn glob_across_crates() {
covers!(glob_across_crates);
// covers!(glob_across_crates);
let map = def_map_with_crate_graph(
"
//- /main.rs
@ -98,7 +98,7 @@ fn glob_across_crates() {
#[test]
fn glob_enum() {
covers!(glob_enum);
// covers!(glob_enum);
let map = def_map(
"
//- /lib.rs

View file

@ -1,13 +1,12 @@
use super::*;
use std::sync::Arc;
use ra_db::{SourceDatabase, SourceDatabaseExt};
use super::*;
fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
let (mut db, pos) = MockDatabase::with_position(initial);
let crate_id = db.crate_graph().iter().next().unwrap();
let krate = Crate { crate_id };
let krate = db.crate_graph().iter().next().unwrap();
{
let events = db.log_executed(|| {
db.crate_def_map(krate);

View file

@ -187,7 +187,7 @@ macro_rules! bar {
#[test]
fn macro_rules_from_other_crates_are_visible_with_macro_use() {
covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
// covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
let map = def_map_with_crate_graph(
"
//- /main.rs
@ -241,7 +241,7 @@ macro_rules! structs_priv {
#[test]
fn prelude_is_macro_use() {
covers!(prelude_is_macro_use);
// covers!(prelude_is_macro_use);
let map = def_map_with_crate_graph(
"
//- /main.rs
@ -531,8 +531,8 @@ macro_rules! bar {
#[test]
fn macro_dollar_crate_is_correct_in_item() {
covers!(macro_dollar_crate_self);
covers!(macro_dollar_crate_other);
// covers!(macro_dollar_crate_self);
// covers!(macro_dollar_crate_other);
let map = def_map_with_crate_graph(
"
//- /main.rs
@ -594,7 +594,7 @@ macro_rules! not_current2 {
#[test]
fn macro_dollar_crate_is_correct_in_indirect_deps() {
covers!(macro_dollar_crate_other);
// covers!(macro_dollar_crate_other);
// From std
let map = def_map_with_crate_graph(
r#"

View file

@ -3,8 +3,9 @@
use hir_def::{
builtin_type::BuiltinType,
nameres::CrateDefMap,
path::{Path, PathKind},
CrateModuleId,
AdtId, CrateModuleId, ModuleDefId,
};
use hir_expand::name::{self, Name};
use rustc_hash::FxHashSet;
@ -18,7 +19,7 @@
},
generics::GenericParams,
impl_block::ImplBlock,
nameres::{CrateDefMap, PerNs},
nameres::PerNs,
Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias,
};
@ -90,7 +91,7 @@ impl Resolver {
pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> {
let res = self.resolve_module_path(db, path).take_types()?;
match res {
ModuleDef::Trait(it) => Some(it),
ModuleDefId::TraitId(it) => Some(it.into()),
_ => None,
}
}
@ -103,7 +104,7 @@ pub(crate) fn resolve_known_struct(
) -> Option<Struct> {
let res = self.resolve_module_path(db, path).take_types()?;
match res {
ModuleDef::Adt(Adt::Struct(it)) => Some(it),
ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it.into()),
_ => None,
}
}
@ -112,7 +113,7 @@ pub(crate) fn resolve_known_struct(
pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> {
let res = self.resolve_module_path(db, path).take_types()?;
match res {
ModuleDef::Adt(Adt::Enum(it)) => Some(it),
ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it.into()),
_ => None,
}
}
@ -166,18 +167,18 @@ pub(crate) fn resolve_path_in_type_ns(
Scope::ModuleScope(m) => {
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
let res = match module_def.take_types()? {
ModuleDef::Adt(it) => TypeNs::Adt(it),
ModuleDef::EnumVariant(it) => TypeNs::EnumVariant(it),
ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()),
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariant(it.into()),
ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it),
ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it),
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()),
ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
ModuleDef::Trait(it) => TypeNs::Trait(it),
ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()),
ModuleDef::Function(_)
| ModuleDef::Const(_)
| ModuleDef::Static(_)
| ModuleDef::Module(_) => return None,
ModuleDefId::FunctionId(_)
| ModuleDefId::ConstId(_)
| ModuleDefId::StaticId(_)
| ModuleDefId::ModuleId(_) => return None,
};
return Some((res, idx));
}
@ -261,33 +262,35 @@ pub(crate) fn resolve_path_in_value_ns<'p>(
return match idx {
None => {
let value = match module_def.take_values()? {
ModuleDef::Function(it) => ValueNs::Function(it),
ModuleDef::Adt(Adt::Struct(it)) => ValueNs::Struct(it),
ModuleDef::EnumVariant(it) => ValueNs::EnumVariant(it),
ModuleDef::Const(it) => ValueNs::Const(it),
ModuleDef::Static(it) => ValueNs::Static(it),
ModuleDefId::FunctionId(it) => ValueNs::Function(it.into()),
ModuleDefId::AdtId(AdtId::StructId(it)) => {
ValueNs::Struct(it.into())
}
ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariant(it.into()),
ModuleDefId::ConstId(it) => ValueNs::Const(it.into()),
ModuleDefId::StaticId(it) => ValueNs::Static(it.into()),
ModuleDef::Adt(Adt::Enum(_))
| ModuleDef::Adt(Adt::Union(_))
| ModuleDef::Trait(_)
| ModuleDef::TypeAlias(_)
| ModuleDef::BuiltinType(_)
| ModuleDef::Module(_) => return None,
ModuleDefId::AdtId(AdtId::EnumId(_))
| ModuleDefId::AdtId(AdtId::UnionId(_))
| ModuleDefId::TraitId(_)
| ModuleDefId::TypeAliasId(_)
| ModuleDefId::BuiltinType(_)
| ModuleDefId::ModuleId(_) => return None,
};
Some(ResolveValueResult::ValueNs(value))
}
Some(idx) => {
let ty = match module_def.take_types()? {
ModuleDef::Adt(it) => TypeNs::Adt(it),
ModuleDef::Trait(it) => TypeNs::Trait(it),
ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it),
ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it),
ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()),
ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()),
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()),
ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
ModuleDef::Module(_)
| ModuleDef::Function(_)
| ModuleDef::EnumVariant(_)
| ModuleDef::Const(_)
| ModuleDef::Static(_) => return None,
ModuleDefId::ModuleId(_)
| ModuleDefId::FunctionId(_)
| ModuleDefId::EnumVariantId(_)
| ModuleDefId::ConstId(_)
| ModuleDefId::StaticId(_) => return None,
};
Some(ResolveValueResult::Partial(ty, idx))
}
@ -315,7 +318,7 @@ pub(crate) fn resolve_path_as_macro(
path: &Path,
) -> Option<MacroDef> {
let (item_map, module) = self.module()?;
item_map.resolve_path(db, module, path).0.get_macros()
item_map.resolve_path(db, module, path).0.get_macros().map(MacroDef::from)
}
pub(crate) fn process_all_names(
@ -333,10 +336,11 @@ pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait>
for scope in &self.scopes {
if let Scope::ModuleScope(m) = scope {
if let Some(prelude) = m.crate_def_map.prelude() {
let prelude_def_map = db.crate_def_map(prelude.krate());
traits.extend(prelude_def_map[prelude.id.module_id].scope.traits());
let prelude_def_map = db.crate_def_map(prelude.krate);
traits
.extend(prelude_def_map[prelude.module_id].scope.traits().map(Trait::from));
}
traits.extend(m.crate_def_map[m.module_id].scope.traits());
traits.extend(m.crate_def_map[m.module_id].scope.traits().map(Trait::from));
}
}
traits
@ -351,7 +355,7 @@ fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
}
pub(crate) fn krate(&self) -> Option<Crate> {
self.module().map(|t| t.0.krate())
self.module().map(|t| Crate { crate_id: t.0.krate() })
}
pub(crate) fn where_predicates_in_scope<'a>(
@ -420,8 +424,10 @@ impl From<PerNs> for ScopeDef {
fn from(def: PerNs) -> Self {
def.take_types()
.or_else(|| def.take_values())
.map(ScopeDef::ModuleDef)
.or_else(|| def.get_macros().map(ScopeDef::MacroDef))
.map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into()))
.or_else(|| {
def.get_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into()))
})
.unwrap_or(ScopeDef::Unknown)
}
}
@ -441,18 +447,16 @@ fn process_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)
f(name.clone(), res.def.into());
});
m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
f(name.clone(), ScopeDef::MacroDef(macro_));
f(name.clone(), ScopeDef::MacroDef(macro_.into()));
});
m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
f(name.clone(), ScopeDef::ModuleDef(*def));
m.crate_def_map.extern_prelude().iter().for_each(|(name, &def)| {
f(name.clone(), ScopeDef::ModuleDef(def.into()));
});
if let Some(prelude) = m.crate_def_map.prelude() {
let prelude_def_map = db.crate_def_map(prelude.krate());
prelude_def_map[prelude.id.module_id].scope.entries().for_each(
|(name, res)| {
f(name.clone(), res.def.into());
},
);
let prelude_def_map = db.crate_def_map(prelude.krate);
prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
f(name.clone(), res.def.into());
});
}
}
Scope::GenericParams(gp) => {

View file

@ -253,8 +253,11 @@ pub fn resolve_hir_path(
Some(res)
});
let items =
self.resolver.resolve_module_path(db, &path).take_types().map(PathResolution::Def);
let items = self
.resolver
.resolve_module_path(db, &path)
.take_types()
.map(|it| PathResolution::Def(it.into()));
types.or(values).or(items).or_else(|| {
self.resolver.resolve_path_as_macro(db, &path).map(|def| PathResolution::Macro(def))
})

View file

@ -3403,7 +3403,7 @@ trait Trait { fn foo(self) -> u128 {} }
#[test]
fn infer_macro_with_dollar_crate_is_correct_in_expr() {
covers!(macro_dollar_crate_other);
// covers!(macro_dollar_crate_other);
let (mut db, pos) = MockDatabase::with_position(
r#"
//- /main.rs

View file

@ -8,7 +8,7 @@
use crate::{
db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId,
LocalStructFieldId, StructId,
LocalStructFieldId, StructId, UnionId,
};
/// Note that we use `StructData` for unions as well!
@ -56,6 +56,13 @@ pub(crate) fn struct_data_query(db: &impl DefDatabase2, struct_: StructId) -> Ar
let variant_data = Arc::new(variant_data);
Arc::new(StructData { name, variant_data })
}
pub(crate) fn union_data_query(db: &impl DefDatabase2, struct_: UnionId) -> Arc<StructData> {
let src = struct_.source(db);
let name = src.ast.name().map(|n| n.as_name());
let variant_data = VariantData::new(src.ast.kind());
let variant_data = Arc::new(variant_data);
Arc::new(StructData { name, variant_data })
}
}
impl EnumData {
@ -74,6 +81,11 @@ pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc<EnumData
.collect();
Arc::new(EnumData { name, variants })
}
pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
let (id, _) = self.variants.iter().find(|(_id, data)| data.name.as_ref() == Some(name))?;
Some(id)
}
}
impl VariantData {

View file

@ -2,13 +2,16 @@
use std::sync::Arc;
use hir_expand::{db::AstDatabase, HirFileId};
use ra_db::{salsa, SourceDatabase};
use ra_db::{salsa, CrateId, SourceDatabase};
use ra_syntax::ast;
use crate::{
adt::{EnumData, StructData},
nameres::raw::{ImportSourceMap, RawItems},
EnumId, StructId,
nameres::{
raw::{ImportSourceMap, RawItems},
CrateDefMap,
},
EnumId, StructId, UnionId,
};
#[salsa::query_group(InternDatabaseStorage)]
@ -42,9 +45,15 @@ fn raw_items_with_source_map(
#[salsa::invoke(RawItems::raw_items_query)]
fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
#[salsa::invoke(CrateDefMap::crate_def_map_query)]
fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;
#[salsa::invoke(StructData::struct_data_query)]
fn struct_data(&self, s: StructId) -> Arc<StructData>;
#[salsa::invoke(StructData::union_data_query)]
fn union_data(&self, s: UnionId) -> Arc<StructData>;
#[salsa::invoke(EnumData::enum_data_query)]
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
}

View file

@ -0,0 +1,26 @@
use std::any::Any;
use hir_expand::diagnostics::Diagnostic;
use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
use relative_path::RelativePathBuf;
use hir_expand::{HirFileId, Source};
#[derive(Debug)]
pub struct UnresolvedModule {
pub file: HirFileId,
pub decl: AstPtr<ast::Module>,
pub candidate: RelativePathBuf,
}
impl Diagnostic for UnresolvedModule {
fn message(&self) -> String {
"unresolved module".to_string()
}
fn source(&self) -> Source<SyntaxNodePtr> {
Source { file_id: self.file, ast: self.decl.into() }
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}

View file

@ -13,6 +13,7 @@
pub mod type_ref;
pub mod builtin_type;
pub mod adt;
pub mod diagnostics;
// FIXME: this should be private
pub mod nameres;
@ -237,8 +238,8 @@ fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
// FIXME: rename to `VariantId`, only enums can ave variants
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumVariantId {
parent: EnumId,
local_id: LocalEnumVariantId,
pub parent: EnumId,
pub local_id: LocalEnumVariantId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -2,4 +2,492 @@
// FIXME: review privacy of submodules
pub mod raw;
pub mod per_ns;
pub mod collector;
pub mod mod_resolution;
use std::sync::Arc;
use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId};
use once_cell::sync::Lazy;
use ra_arena::Arena;
use ra_db::{CrateId, Edition, FileId};
use ra_prof::profile;
use ra_syntax::ast;
use rustc_hash::{FxHashMap, FxHashSet};
// use test_utils::tested_by;
use crate::{
builtin_type::BuiltinType,
db::DefDatabase2,
nameres::{diagnostics::DefDiagnostic, per_ns::PerNs, raw::ImportId},
path::{Path, PathKind},
AdtId, AstId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, TraitId,
};
/// Contains all top-level defs from a macro-expanded crate
#[derive(Debug, PartialEq, Eq)]
pub struct CrateDefMap {
krate: CrateId,
edition: Edition,
/// 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`).
prelude: Option<ModuleId>,
extern_prelude: FxHashMap<Name, ModuleDefId>,
root: CrateModuleId,
pub modules: Arena<CrateModuleId, ModuleData>,
/// Some macros are not well-behavior, which leads to infinite loop
/// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
/// We mark it down and skip it in collector
///
/// FIXME:
/// Right now it only handle a poison macro in a single crate,
/// such that if other crate try to call that macro,
/// the whole process will do again until it became poisoned in that crate.
/// We should handle this macro set globally
/// However, do we want to put it as a global variable?
poison_macros: FxHashSet<MacroDefId>,
diagnostics: Vec<DefDiagnostic>,
}
impl std::ops::Index<CrateModuleId> for CrateDefMap {
type Output = ModuleData;
fn index(&self, id: CrateModuleId) -> &ModuleData {
&self.modules[id]
}
}
#[derive(Default, Debug, PartialEq, Eq)]
pub struct ModuleData {
pub parent: Option<CrateModuleId>,
pub children: FxHashMap<Name, CrateModuleId>,
pub scope: ModuleScope,
/// None for root
pub declaration: Option<AstId<ast::Module>>,
/// None for inline modules.
///
/// Note that non-inline modules, by definition, live inside non-macro file.
pub definition: Option<FileId>,
}
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct ModuleScope {
pub items: FxHashMap<Name, Resolution>,
/// Macros visable in current module in legacy textual scope
///
/// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
/// If it yields no result, then it turns to module scoped `macros`.
/// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
/// and only normal scoped `macros` will be searched in.
///
/// Note that this automatically inherit macros defined textually before the definition of module itself.
///
/// Module scoped macros will be inserted into `items` instead of here.
// FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
// be all resolved to the last one defined if shadowing happens.
legacy_macros: FxHashMap<Name, MacroDefId>,
}
static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
BuiltinType::ALL
.iter()
.map(|(name, ty)| {
(name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
})
.collect()
});
/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ModuleScope {
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
//FIXME: shadowing
self.items.iter().chain(BUILTIN_SCOPE.iter())
}
/// Iterate over all module scoped macros
pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
self.items
.iter()
.filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
}
/// Iterate over all legacy textual scoped macros visable at the end of the module
pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
self.legacy_macros.iter().map(|(name, def)| (name, *def))
}
/// Get a name from current module scope, legacy macros are not included
pub fn get(&self, name: &Name) -> Option<&Resolution> {
self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
}
pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
self.items.values().filter_map(|r| match r.def.take_types() {
Some(ModuleDefId::TraitId(t)) => Some(t),
_ => None,
})
}
fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
self.legacy_macros.get(name).copied()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Resolution {
/// None for unresolved
pub def: PerNs,
/// ident by which this is imported into local scope.
pub import: Option<ImportId>,
}
impl Resolution {
pub(crate) fn from_macro(macro_: MacroDefId) -> Self {
Resolution { def: PerNs::macros(macro_), import: None }
}
}
#[derive(Debug, Clone)]
struct ResolvePathResult {
resolved_def: PerNs,
segment_index: Option<usize>,
reached_fixedpoint: ReachedFixedPoint,
}
impl ResolvePathResult {
fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
}
fn with(
resolved_def: PerNs,
reached_fixedpoint: ReachedFixedPoint,
segment_index: Option<usize>,
) -> ResolvePathResult {
ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ResolveMode {
Import,
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ReachedFixedPoint {
Yes,
No,
}
impl CrateDefMap {
pub(crate) fn crate_def_map_query(
// Note that this doesn't have `+ AstDatabase`!
// This gurantess that `CrateDefMap` is stable across reparses.
db: &impl DefDatabase2,
krate: CrateId,
) -> Arc<CrateDefMap> {
let _p = profile("crate_def_map_query");
let def_map = {
let crate_graph = db.crate_graph();
let edition = crate_graph.edition(krate);
let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
let root = modules.alloc(ModuleData::default());
CrateDefMap {
krate,
edition,
extern_prelude: FxHashMap::default(),
prelude: None,
root,
modules,
poison_macros: FxHashSet::default(),
diagnostics: Vec::new(),
}
};
let def_map = collector::collect_defs(db, def_map);
Arc::new(def_map)
}
pub fn krate(&self) -> CrateId {
self.krate
}
pub fn root(&self) -> CrateModuleId {
self.root
}
pub fn prelude(&self) -> Option<ModuleId> {
self.prelude
}
pub fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDefId> {
&self.extern_prelude
}
pub fn add_diagnostics(
&self,
db: &impl DefDatabase2,
module: CrateModuleId,
sink: &mut DiagnosticSink,
) {
self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
}
pub fn resolve_path(
&self,
db: &impl DefDatabase2,
original_module: CrateModuleId,
path: &Path,
) -> (PerNs, Option<usize>) {
let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
(res.resolved_def, res.segment_index)
}
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
// the result.
fn resolve_path_fp_with_macro(
&self,
db: &impl DefDatabase2,
mode: ResolveMode,
original_module: CrateModuleId,
path: &Path,
) -> ResolvePathResult {
let mut segments = path.segments.iter().enumerate();
let mut curr_per_ns: PerNs = match path.kind {
PathKind::DollarCrate(krate) => {
if krate == self.krate {
// tested_by!(macro_dollar_crate_self);
PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
} else {
let def_map = db.crate_def_map(krate);
let module = ModuleId { krate, module_id: def_map.root };
// tested_by!(macro_dollar_crate_other);
PerNs::types(module.into())
}
}
PathKind::Crate => {
PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
}
PathKind::Self_ => {
PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into())
}
// plain import or absolute path in 2015: crate-relative with
// fallback to extern prelude (with the simplification in
// rust-lang/rust#57745)
// FIXME there must be a nicer way to write this condition
PathKind::Plain | PathKind::Abs
if self.edition == Edition::Edition2015
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
{
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
}
PathKind::Plain => {
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
log::debug!("resolving {:?} in module", segment);
self.resolve_name_in_module(db, original_module, &segment.name)
}
PathKind::Super => {
if let Some(p) = self.modules[original_module].parent {
PerNs::types(ModuleId { krate: self.krate, module_id: p }.into())
} else {
log::debug!("super path in root module");
return ResolvePathResult::empty(ReachedFixedPoint::Yes);
}
}
PathKind::Abs => {
// 2018-style absolute path -- only extern prelude
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
if let Some(def) = self.extern_prelude.get(&segment.name) {
log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
PerNs::types(*def)
} else {
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
}
}
PathKind::Type(_) => {
// This is handled in `infer::infer_path_expr`
// The result returned here does not matter
return ResolvePathResult::empty(ReachedFixedPoint::Yes);
}
};
for (i, segment) in segments {
let curr = match curr_per_ns.take_types() {
Some(r) => r,
None => {
// we still have path segments left, but the path so far
// didn't resolve in the types namespace => no resolution
// (don't break here because `curr_per_ns` might contain
// something in the value namespace, and it would be wrong
// to return that)
return ResolvePathResult::empty(ReachedFixedPoint::No);
}
};
// resolve segment in curr
curr_per_ns = match curr {
ModuleDefId::ModuleId(module) => {
if module.krate != self.krate {
let path =
Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
log::debug!("resolving {:?} in other crate", path);
let defp_map = db.crate_def_map(module.krate);
let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
return ResolvePathResult::with(
def,
ReachedFixedPoint::Yes,
s.map(|s| s + i),
);
}
// Since it is a qualified path here, it should not contains legacy macros
match self[module.module_id].scope.get(&segment.name) {
Some(res) => res.def,
_ => {
log::debug!("path segment {:?} not found", segment.name);
return ResolvePathResult::empty(ReachedFixedPoint::No);
}
}
}
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
// enum variant
// tested_by!(can_import_enum_variant);
let enum_data = db.enum_data(e);
match enum_data.variant(&segment.name) {
Some(local_id) => {
let variant = EnumVariantId { parent: e, local_id };
PerNs::both(variant.into(), variant.into())
}
None => {
return ResolvePathResult::with(
PerNs::types(e.into()),
ReachedFixedPoint::Yes,
Some(i),
);
}
}
}
s => {
// could be an inherent method call in UFCS form
// (`Struct::method`), or some other kind of associated item
log::debug!(
"path segment {:?} resolved to non-module {:?}, but is not last",
segment.name,
curr,
);
return ResolvePathResult::with(
PerNs::types(s),
ReachedFixedPoint::Yes,
Some(i),
);
}
};
}
ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
}
fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
let from_crate_root =
self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
from_crate_root.or(from_extern_prelude)
}
pub(crate) fn resolve_name_in_module(
&self,
db: &impl DefDatabase2,
module: CrateModuleId,
name: &Name,
) -> PerNs {
// Resolve in:
// - legacy scope of macro
// - current module / scope
// - extern prelude
// - std prelude
let from_legacy_macro =
self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
let from_extern_prelude =
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
let from_prelude = self.resolve_in_prelude(db, name);
from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
}
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
}
fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs {
if let Some(prelude) = self.prelude {
let keep;
let def_map = if prelude.krate == self.krate {
self
} else {
// Extend lifetime
keep = db.crate_def_map(prelude.krate);
&keep
};
def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
} else {
PerNs::none()
}
}
}
mod diagnostics {
use hir_expand::diagnostics::DiagnosticSink;
use ra_syntax::{ast, AstPtr};
use relative_path::RelativePathBuf;
use crate::{db::DefDatabase2, diagnostics::UnresolvedModule, nameres::CrateModuleId, AstId};
#[derive(Debug, PartialEq, Eq)]
pub(super) enum DefDiagnostic {
UnresolvedModule {
module: CrateModuleId,
declaration: AstId<ast::Module>,
candidate: RelativePathBuf,
},
}
impl DefDiagnostic {
pub(super) fn add_to(
&self,
db: &impl DefDatabase2,
target_module: CrateModuleId,
sink: &mut DiagnosticSink,
) {
match self {
DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
if *module != target_module {
return;
}
let decl = declaration.to_node(db);
sink.push(UnresolvedModule {
file: declaration.file_id(),
decl: AstPtr::new(&decl),
candidate: candidate.clone(),
})
}
}
}
}
}

View file

@ -1,45 +1,49 @@
//! FIXME: write short doc here
use hir_def::{
attr::Attr,
nameres::{mod_resolution::ModDir, raw},
use hir_expand::{
name::{self, AsName, Name},
HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind,
};
use hir_expand::name;
use ra_cfg::CfgOptions;
use ra_db::FileId;
use ra_db::{CrateId, FileId};
use ra_syntax::{ast, SmolStr};
use rustc_hash::FxHashMap;
use test_utils::tested_by;
// use test_utils::tested_by;
use crate::{
db::DefDatabase,
ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
attr::Attr,
db::DefDatabase2,
nameres::{
diagnostics::DefDiagnostic, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef,
PerNs, ReachedFixedPoint, Resolution, ResolveMode,
diagnostics::DefDiagnostic, mod_resolution::ModDir, per_ns::PerNs, raw, CrateDefMap,
ModuleData, ReachedFixedPoint, Resolution, ResolveMode,
},
Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
Struct, Trait, TypeAlias, Union,
path::{Path, PathKind},
AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
};
pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap {
let crate_graph = db.crate_graph();
// populate external prelude
for dep in def_map.krate.dependencies(db) {
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
if let Some(module) = dep.krate.root_module(db) {
def_map.extern_prelude.insert(dep.name.clone(), module.into());
}
for dep in crate_graph.dependencies(def_map.krate) {
let dep_def_map = db.crate_def_map(dep.crate_id);
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
def_map.extern_prelude.insert(
dep.as_name(),
ModuleId { krate: dep.crate_id, module_id: dep_def_map.root }.into(),
);
// look for the prelude
if def_map.prelude.is_none() {
let map = db.crate_def_map(dep.krate);
let map = db.crate_def_map(dep.crate_id);
if map.prelude.is_some() {
def_map.prelude = map.prelude;
}
}
}
let crate_graph = db.crate_graph();
let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id());
let cfg_options = crate_graph.cfg_options(def_map.krate);
let mut collector = DefCollector {
db,
@ -101,11 +105,11 @@ struct DefCollector<'a, DB> {
impl<DB> DefCollector<'_, DB>
where
DB: DefDatabase,
DB: DefDatabase2,
{
fn collect(&mut self) {
let crate_graph = self.db.crate_graph();
let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
let file_id = crate_graph.crate_root(self.def_map.krate);
let raw_items = self.db.raw_items(file_id.into());
let module_id = self.def_map.root;
self.def_map.modules[module_id].definition = Some(file_id);
@ -168,7 +172,7 @@ fn define_macro(
&mut self,
module_id: CrateModuleId,
name: Name,
macro_: MacroDef,
macro_: MacroDefId,
export: bool,
) {
// Textual scoping
@ -189,7 +193,7 @@ fn define_macro(
/// the definition of current module.
/// And also, `macro_use` on a module will import all legacy macros visable inside to
/// current legacy scope, with possible shadowing.
fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) {
fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDefId) {
// Always shadowing
self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
}
@ -213,9 +217,9 @@ fn import_macros_from_extern_crate(
.expect("extern crate should have been desugared to one-element path"),
);
if let Some(ModuleDef::Module(m)) = res.take_types() {
tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
self.import_all_macros_exported(current_module_id, m.krate());
if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
// tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
self.import_all_macros_exported(current_module_id, m.krate);
}
}
@ -224,7 +228,7 @@ fn import_macros_from_extern_crate(
/// Exported macros are just all macros in the root module scope.
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases
/// created by `use` in the root module, ignoring the visibility of `use`.
fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) {
fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: CrateId) {
let def_map = self.db.crate_def_map(krate);
for (name, def) in def_map[def_map.root].scope.macros() {
// `macro_use` only bring things into legacy scope.
@ -288,15 +292,15 @@ fn record_resolved_import(
if import.is_glob {
log::debug!("glob import: {:?}", import);
match def.take_types() {
Some(ModuleDef::Module(m)) => {
Some(ModuleDefId::ModuleId(m)) => {
if import.is_prelude {
tested_by!(std_prelude);
// tested_by!(std_prelude);
self.def_map.prelude = Some(m);
} else if m.krate() != self.def_map.krate {
tested_by!(glob_across_crates);
} else if m.krate != self.def_map.krate {
// tested_by!(glob_across_crates);
// glob import from other crate => we can just import everything once
let item_map = self.db.crate_def_map(m.krate());
let scope = &item_map[m.id.module_id].scope;
let item_map = self.db.crate_def_map(m.krate);
let scope = &item_map[m.module_id].scope;
// Module scoped macros is included
let items = scope
@ -310,7 +314,7 @@ fn record_resolved_import(
// glob import from same crate => we do an initial
// import, and then need to propagate any further
// additions
let scope = &self.def_map[m.id.module_id].scope;
let scope = &self.def_map[m.module_id].scope;
// Module scoped macros is included
let items = scope
@ -322,23 +326,25 @@ fn record_resolved_import(
self.update(module_id, Some(import_id), &items);
// record the glob import in case we add further items
self.glob_imports
.entry(m.id.module_id)
.entry(m.module_id)
.or_default()
.push((module_id, import_id));
}
}
Some(ModuleDef::Adt(Adt::Enum(e))) => {
tested_by!(glob_enum);
Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
// tested_by!(glob_enum);
// glob import from enum => just import all the variants
let variants = e.variants(self.db);
let resolutions = variants
.into_iter()
.filter_map(|variant| {
let enum_data = self.db.enum_data(e);
let resolutions = enum_data
.variants
.iter()
.filter_map(|(local_id, variant_data)| {
let name = variant_data.name.clone()?;
let variant = EnumVariantId { parent: e, local_id };
let res = Resolution {
def: PerNs::both(variant.into(), variant.into()),
import: Some(import_id),
};
let name = variant.name(self.db)?;
Some((name, res))
})
.collect::<Vec<_>>();
@ -367,7 +373,8 @@ fn record_resolved_import(
let resolution = Resolution { def, import: Some(import_id) };
self.update(module_id, Some(import_id), &[(name, resolution)]);
}
None => tested_by!(bogus_paths),
// tested_by!(bogus_paths),
None => (),
}
}
}
@ -451,8 +458,8 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint {
);
if let Some(def) = resolved_res.resolved_def.get_macros() {
let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id });
resolved.push((*module_id, call_id, def.id));
let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id: *ast_id });
resolved.push((*module_id, call_id, def));
res = ReachedFixedPoint::No;
return false;
}
@ -517,7 +524,7 @@ struct ModCollector<'a, D> {
impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
where
DB: DefDatabase,
DB: DefDatabase2,
{
fn collect(&mut self, items: &[raw::RawItem]) {
// Note: don't assert that inserted value is fresh: it's simply not true
@ -526,10 +533,9 @@ fn collect(&mut self, items: &[raw::RawItem]) {
// Prelude module is always considered to be `#[macro_use]`.
if let Some(prelude_module) = self.def_collector.def_map.prelude {
if prelude_module.krate() != self.def_collector.def_map.krate {
tested_by!(prelude_is_macro_use);
self.def_collector
.import_all_macros_exported(self.module_id, prelude_module.krate());
if prelude_module.krate != self.def_collector.def_map.krate {
// tested_by!(prelude_is_macro_use);
self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
}
}
@ -635,7 +641,9 @@ fn push_child_module(
modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone();
modules[self.module_id].children.insert(name.clone(), res);
let resolution = Resolution {
def: PerNs::types(Module::new(self.def_collector.def_map.krate, res).into()),
def: PerNs::types(
ModuleId { krate: self.def_collector.def_map.krate, module_id: res }.into(),
),
import: None,
};
self.def_collector.update(self.module_id, None, &[(name, resolution)]);
@ -643,30 +651,32 @@ fn push_child_module(
}
fn define_def(&mut self, def: &raw::DefData) {
let module = Module::new(self.def_collector.def_map.krate, self.module_id);
let ctx = LocationCtx::new(self.def_collector.db, module.id, self.file_id);
let module =
ModuleId { krate: self.def_collector.def_map.krate, module_id: self.module_id };
let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id);
macro_rules! def {
($kind:ident, $ast_id:ident) => {
$kind { id: AstItemDef::from_ast_id(ctx, $ast_id) }.into()
};
}
let name = def.name.clone();
let def: PerNs = match def.kind {
raw::DefKind::Function(ast_id) => PerNs::values(def!(Function, ast_id)),
raw::DefKind::Function(ast_id) => {
PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into())
}
raw::DefKind::Struct(ast_id) => {
let s = def!(Struct, ast_id);
let s = StructId::from_ast_id(ctx, ast_id).into();
PerNs::both(s, s)
}
raw::DefKind::Union(ast_id) => {
let s = def!(Union, ast_id);
let s = UnionId::from_ast_id(ctx, ast_id).into();
PerNs::both(s, s)
}
raw::DefKind::Enum(ast_id) => PerNs::types(def!(Enum, ast_id)),
raw::DefKind::Const(ast_id) => PerNs::values(def!(Const, ast_id)),
raw::DefKind::Static(ast_id) => PerNs::values(def!(Static, ast_id)),
raw::DefKind::Trait(ast_id) => PerNs::types(def!(Trait, ast_id)),
raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()),
raw::DefKind::Static(ast_id) => {
PerNs::values(StaticId::from_ast_id(ctx, ast_id).into())
}
raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()),
raw::DefKind::TypeAlias(ast_id) => {
PerNs::types(TypeAliasId::from_ast_id(ctx, ast_id).into())
}
};
let resolution = Resolution { def, import: None };
self.def_collector.update(self.module_id, None, &[(name, resolution)])
@ -678,10 +688,8 @@ fn collect_macro(&mut self, mac: &raw::MacroData) {
// Case 1: macro rules, define a macro in crate-global mutable scope
if is_macro_rules(&mac.path) {
if let Some(name) = &mac.name {
let macro_id =
MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id };
let macro_ = MacroDef { id: macro_id };
self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate };
self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
}
return;
}
@ -691,10 +699,10 @@ fn collect_macro(&mut self, mac: &raw::MacroData) {
if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
}) {
let def = macro_def.id;
let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id });
let macro_call_id =
self.def_collector.db.intern_macro(MacroCallLoc { def: macro_def, ast_id });
self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def);
self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def);
return;
}
@ -731,7 +739,7 @@ fn is_macro_rules(path: &Path) -> bool {
path.as_ident() == Some(&name::MACRO_RULES)
}
#[cfg(test)]
#[cfg(never)]
mod tests {
use ra_db::SourceDatabase;

View file

@ -1,6 +1,8 @@
//! FIXME: write short doc here
use crate::{MacroDef, ModuleDef};
use hir_expand::MacroDefId;
use crate::ModuleDefId;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Namespace {
@ -12,11 +14,11 @@ pub enum Namespace {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PerNs {
pub types: Option<ModuleDef>,
pub values: Option<ModuleDef>,
pub types: Option<ModuleDefId>,
pub values: Option<ModuleDefId>,
/// Since macros has different type, many methods simply ignore it.
/// We can only use special method like `get_macros` to access it.
pub macros: Option<MacroDef>,
pub macros: Option<MacroDefId>,
}
impl Default for PerNs {
@ -30,19 +32,19 @@ pub fn none() -> PerNs {
PerNs { types: None, values: None, macros: None }
}
pub fn values(t: ModuleDef) -> PerNs {
pub fn values(t: ModuleDefId) -> PerNs {
PerNs { types: None, values: Some(t), macros: None }
}
pub fn types(t: ModuleDef) -> PerNs {
pub fn types(t: ModuleDefId) -> PerNs {
PerNs { types: Some(t), values: None, macros: None }
}
pub fn both(types: ModuleDef, values: ModuleDef) -> PerNs {
pub fn both(types: ModuleDefId, values: ModuleDefId) -> PerNs {
PerNs { types: Some(types), values: Some(values), macros: None }
}
pub fn macros(macro_: MacroDef) -> PerNs {
pub fn macros(macro_: MacroDefId) -> PerNs {
PerNs { types: None, values: None, macros: Some(macro_) }
}
@ -54,15 +56,15 @@ pub fn is_all(&self) -> bool {
self.types.is_some() && self.values.is_some() && self.macros.is_some()
}
pub fn take_types(self) -> Option<ModuleDef> {
pub fn take_types(self) -> Option<ModuleDefId> {
self.types
}
pub fn take_values(self) -> Option<ModuleDef> {
pub fn take_values(self) -> Option<ModuleDefId> {
self.values
}
pub fn get_macros(&self) -> Option<MacroDef> {
pub fn get_macros(&self) -> Option<MacroDefId> {
self.macros
}

View file

@ -18,15 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
match def {
hir::ModuleDef::Module(module) => {
let module_scope = module.scope(ctx.db);
for (name, res) in module_scope.entries() {
if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.take_types() {
for (name, def, import) in module_scope {
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
if ctx.use_item_syntax.is_some() {
tested_by!(dont_complete_primitive_in_use);
continue;
}
}
if Some(module) == ctx.module {
if let Some(import) = res.import {
if let Some(import) = import {
if let Either::A(use_tree) = module.import_source(ctx.db, import) {
if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
// for `use self::foo<|>`, don't suggest `foo` as a completion
@ -36,7 +36,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
}
}
}
acc.add_resolution(ctx, name.to_string(), &res.def.into());
acc.add_resolution(ctx, name.to_string(), &def);
}
}
hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => {