mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 06:41:48 +00:00
Move lang_items to hir_def
This commit is contained in:
parent
9da07a07eb
commit
8692977d27
10 changed files with 179 additions and 202 deletions
|
@ -3,27 +3,25 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ra_db::salsa;
|
use ra_db::salsa;
|
||||||
use ra_syntax::SmolStr;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
debug::HirDebugDatabase,
|
debug::HirDebugDatabase,
|
||||||
ids,
|
ids,
|
||||||
lang_item::{LangItemTarget, LangItems},
|
|
||||||
ty::{
|
ty::{
|
||||||
method_resolution::CrateImplBlocks,
|
method_resolution::CrateImplBlocks,
|
||||||
traits::{AssocTyValue, Impl},
|
traits::{AssocTyValue, Impl},
|
||||||
CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
|
CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
|
||||||
TypeCtor,
|
TypeCtor,
|
||||||
},
|
},
|
||||||
Crate, DefWithBody, GenericDef, ImplBlock, Module, StructField, Trait,
|
Crate, DefWithBody, GenericDef, ImplBlock, StructField, Trait,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use hir_def::db::{
|
pub use hir_def::db::{
|
||||||
BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, DefDatabase2,
|
BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
|
||||||
DefDatabase2Storage, EnumDataQuery, ExprScopesQuery, FunctionDataQuery, GenericParamsQuery,
|
DefDatabase2, DefDatabase2Storage, EnumDataQuery, ExprScopesQuery, FunctionDataQuery,
|
||||||
ImplDataQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery,
|
GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage, LangItemQuery,
|
||||||
RawItemsWithSourceMapQuery, StaticDataQuery, StructDataQuery, TraitDataQuery,
|
ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery, StaticDataQuery,
|
||||||
TypeAliasDataQuery,
|
StructDataQuery, TraitDataQuery, TypeAliasDataQuery,
|
||||||
};
|
};
|
||||||
pub use hir_expand::db::{
|
pub use hir_expand::db::{
|
||||||
AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
|
AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
|
||||||
|
@ -34,15 +32,6 @@ pub use hir_expand::db::{
|
||||||
#[salsa::query_group(DefDatabaseStorage)]
|
#[salsa::query_group(DefDatabaseStorage)]
|
||||||
#[salsa::requires(AstDatabase)]
|
#[salsa::requires(AstDatabase)]
|
||||||
pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
|
pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
|
||||||
#[salsa::invoke(LangItems::module_lang_items_query)]
|
|
||||||
fn module_lang_items(&self, module: Module) -> Option<Arc<LangItems>>;
|
|
||||||
|
|
||||||
#[salsa::invoke(LangItems::crate_lang_items_query)]
|
|
||||||
fn crate_lang_items(&self, krate: Crate) -> Arc<LangItems>;
|
|
||||||
|
|
||||||
#[salsa::invoke(LangItems::lang_item_query)]
|
|
||||||
fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>;
|
|
||||||
|
|
||||||
#[salsa::invoke(crate::code_model::docs::documentation_query)]
|
#[salsa::invoke(crate::code_model::docs::documentation_query)]
|
||||||
fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>;
|
fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,154 +0,0 @@
|
||||||
//! FIXME: write short doc here
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use hir_def::{AdtId, AttrDefId, ModuleDefId};
|
|
||||||
use ra_syntax::SmolStr;
|
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
|
||||||
Crate, Enum, Function, ImplBlock, Module, Static, Struct, Trait,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
||||||
pub enum LangItemTarget {
|
|
||||||
Enum(Enum),
|
|
||||||
Function(Function),
|
|
||||||
ImplBlock(ImplBlock),
|
|
||||||
Static(Static),
|
|
||||||
Struct(Struct),
|
|
||||||
Trait(Trait),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LangItemTarget {
|
|
||||||
pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
|
|
||||||
Some(match self {
|
|
||||||
LangItemTarget::Enum(e) => e.module(db).krate(),
|
|
||||||
LangItemTarget::Function(f) => f.module(db).krate(),
|
|
||||||
LangItemTarget::ImplBlock(i) => i.krate(db),
|
|
||||||
LangItemTarget::Static(s) => s.module(db).krate(),
|
|
||||||
LangItemTarget::Struct(s) => s.module(db).krate(),
|
|
||||||
LangItemTarget::Trait(t) => t.module(db).krate(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct LangItems {
|
|
||||||
items: FxHashMap<SmolStr, LangItemTarget>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LangItems {
|
|
||||||
pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
|
|
||||||
self.items.get(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Salsa query. This will look for lang items in a specific crate.
|
|
||||||
pub(crate) fn crate_lang_items_query(
|
|
||||||
db: &(impl DefDatabase + AstDatabase),
|
|
||||||
krate: Crate,
|
|
||||||
) -> Arc<LangItems> {
|
|
||||||
let mut lang_items = LangItems::default();
|
|
||||||
|
|
||||||
if let Some(module) = krate.root_module(db) {
|
|
||||||
lang_items.collect_lang_items_recursive(db, module);
|
|
||||||
}
|
|
||||||
|
|
||||||
Arc::new(lang_items)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn module_lang_items_query(
|
|
||||||
db: &(impl DefDatabase + AstDatabase),
|
|
||||||
module: Module,
|
|
||||||
) -> Option<Arc<LangItems>> {
|
|
||||||
let mut lang_items = LangItems::default();
|
|
||||||
lang_items.collect_lang_items(db, module);
|
|
||||||
if lang_items.items.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(Arc::new(lang_items))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Salsa query. Look for a lang item, starting from the specified crate and recursively
|
|
||||||
/// traversing its dependencies.
|
|
||||||
pub(crate) fn lang_item_query(
|
|
||||||
db: &impl DefDatabase,
|
|
||||||
start_crate: Crate,
|
|
||||||
item: SmolStr,
|
|
||||||
) -> Option<LangItemTarget> {
|
|
||||||
let lang_items = db.crate_lang_items(start_crate);
|
|
||||||
let start_crate_target = lang_items.items.get(&item);
|
|
||||||
if let Some(target) = start_crate_target {
|
|
||||||
Some(*target)
|
|
||||||
} else {
|
|
||||||
for dep in start_crate.dependencies(db) {
|
|
||||||
let dep_crate = dep.krate;
|
|
||||||
let dep_target = db.lang_item(dep_crate, item.clone());
|
|
||||||
if dep_target.is_some() {
|
|
||||||
return dep_target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_lang_items(&mut self, db: &(impl DefDatabase + AstDatabase), module: Module) {
|
|
||||||
// Look for impl targets
|
|
||||||
let def_map = db.crate_def_map(module.id.krate);
|
|
||||||
let module_data = &def_map[module.id.module_id];
|
|
||||||
for &impl_block in module_data.impls.iter() {
|
|
||||||
self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
for def in module_data.scope.declarations() {
|
|
||||||
match def {
|
|
||||||
ModuleDefId::TraitId(trait_) => {
|
|
||||||
self.collect_lang_item(db, trait_, LangItemTarget::Trait)
|
|
||||||
}
|
|
||||||
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
|
|
||||||
self.collect_lang_item(db, e, LangItemTarget::Enum)
|
|
||||||
}
|
|
||||||
ModuleDefId::AdtId(AdtId::StructId(s)) => {
|
|
||||||
self.collect_lang_item(db, s, LangItemTarget::Struct)
|
|
||||||
}
|
|
||||||
ModuleDefId::FunctionId(f) => {
|
|
||||||
self.collect_lang_item(db, f, LangItemTarget::Function)
|
|
||||||
}
|
|
||||||
ModuleDefId::StaticId(s) => self.collect_lang_item(db, s, LangItemTarget::Static),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_lang_items_recursive(
|
|
||||||
&mut self,
|
|
||||||
db: &(impl DefDatabase + AstDatabase),
|
|
||||||
module: Module,
|
|
||||||
) {
|
|
||||||
if let Some(module_lang_items) = db.module_lang_items(module) {
|
|
||||||
self.items.extend(module_lang_items.items.iter().map(|(k, v)| (k.clone(), *v)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for lang items in the children
|
|
||||||
for child in module.children(db) {
|
|
||||||
self.collect_lang_items_recursive(db, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_lang_item<T, D>(
|
|
||||||
&mut self,
|
|
||||||
db: &(impl DefDatabase + AstDatabase),
|
|
||||||
item: T,
|
|
||||||
constructor: fn(D) -> LangItemTarget,
|
|
||||||
) where
|
|
||||||
T: Into<AttrDefId> + Copy,
|
|
||||||
D: From<T>,
|
|
||||||
{
|
|
||||||
let attrs = db.attrs(item.into());
|
|
||||||
if let Some(lang_item_name) = attrs.find_string_value("lang") {
|
|
||||||
self.items.entry(lang_item_name).or_insert_with(|| constructor(D::from(item)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,7 +35,6 @@ mod ids;
|
||||||
mod ty;
|
mod ty;
|
||||||
mod impl_block;
|
mod impl_block;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod lang_item;
|
|
||||||
pub mod diagnostics;
|
pub mod diagnostics;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
|
|
||||||
use std::iter::successors;
|
use std::iter::successors;
|
||||||
|
|
||||||
use hir_def::resolver::Resolver;
|
use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
|
||||||
use hir_expand::name;
|
use hir_expand::name;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
|
use crate::{db::HirDatabase, Trait};
|
||||||
|
|
||||||
use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
|
use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
|
||||||
use crate::db::HirDatabase;
|
|
||||||
|
|
||||||
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ fn deref_by_trait(
|
||||||
) -> Option<Canonical<Ty>> {
|
) -> Option<Canonical<Ty>> {
|
||||||
let krate = resolver.krate()?;
|
let krate = resolver.krate()?;
|
||||||
let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
|
let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
|
||||||
crate::lang_item::LangItemTarget::Trait(t) => t,
|
LangItemTarget::TraitId(t) => Trait::from(t),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
|
let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
|
||||||
|
|
|
@ -4,13 +4,12 @@
|
||||||
//!
|
//!
|
||||||
//! See: https://doc.rust-lang.org/nomicon/coercions.html
|
//! See: https://doc.rust-lang.org/nomicon/coercions.html
|
||||||
|
|
||||||
use hir_def::resolver::Resolver;
|
use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use test_utils::tested_by;
|
use test_utils::tested_by;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
lang_item::LangItemTarget,
|
|
||||||
ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
|
ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
|
||||||
Adt, Mutability,
|
Adt, Mutability,
|
||||||
};
|
};
|
||||||
|
@ -50,7 +49,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
|
) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
|
||||||
let krate = resolver.krate().unwrap();
|
let krate = resolver.krate().unwrap();
|
||||||
let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) {
|
let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) {
|
||||||
Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate.into(), trait_),
|
Some(LangItemTarget::TraitId(trait_)) => {
|
||||||
|
db.impls_for_trait(krate.into(), trait_.into())
|
||||||
|
}
|
||||||
_ => return FxHashMap::default(),
|
_ => return FxHashMap::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use hir_def::resolver::Resolver;
|
use hir_def::{lang_item::LangItemTarget, resolver::Resolver, AstItemDef};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -91,34 +91,43 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV
|
||||||
// Types like slice can have inherent impls in several crates, (core and alloc).
|
// Types like slice can have inherent impls in several crates, (core and alloc).
|
||||||
// The corresponding impls are marked with lang items, so we can use them to find the required crates.
|
// The corresponding impls are marked with lang items, so we can use them to find the required crates.
|
||||||
macro_rules! lang_item_crate {
|
macro_rules! lang_item_crate {
|
||||||
($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{
|
($($name:expr),+ $(,)?) => {{
|
||||||
let mut v = ArrayVec::<[Crate; 2]>::new();
|
let mut v = ArrayVec::<[LangItemTarget; 2]>::new();
|
||||||
$(
|
$(
|
||||||
v.extend($db.lang_item($cur_crate, $name.into()).and_then(|item| item.krate($db)));
|
v.extend(db.lang_item(cur_crate.crate_id, $name.into()));
|
||||||
)+
|
)+
|
||||||
Some(v)
|
v
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
match ty {
|
let lang_item_targets = match ty {
|
||||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||||
TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()),
|
TypeCtor::Adt(def_id) => return Some(std::iter::once(def_id.krate(db)?).collect()),
|
||||||
TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"),
|
TypeCtor::Bool => lang_item_crate!("bool"),
|
||||||
TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"),
|
TypeCtor::Char => lang_item_crate!("char"),
|
||||||
TypeCtor::Float(Uncertain::Known(f)) => match f.bitness {
|
TypeCtor::Float(Uncertain::Known(f)) => match f.bitness {
|
||||||
// There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
|
// There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
|
||||||
FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"),
|
FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"),
|
||||||
FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"),
|
FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"),
|
||||||
},
|
},
|
||||||
TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(db, cur_crate, i.ty_to_string()),
|
TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()),
|
||||||
TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"),
|
TypeCtor::Str => lang_item_crate!("str_alloc", "str"),
|
||||||
TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"),
|
TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"),
|
||||||
TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"),
|
TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"),
|
||||||
TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!(db, cur_crate, "mut_ptr"),
|
TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!("mut_ptr"),
|
||||||
_ => None,
|
_ => return None,
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => return None,
|
||||||
}
|
};
|
||||||
|
let res = lang_item_targets
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|it| match it {
|
||||||
|
LangItemTarget::ImplBlockId(it) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|it| it.module(db).krate.into())
|
||||||
|
.collect();
|
||||||
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look up the method with the given name, returning the actual autoderefed
|
/// Look up the method with the given name, returning the actual autoderefed
|
||||||
|
|
|
@ -9,6 +9,7 @@ use chalk_ir::{
|
||||||
};
|
};
|
||||||
use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
|
use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
|
||||||
|
|
||||||
|
use hir_def::lang_item::LangItemTarget;
|
||||||
use hir_expand::name;
|
use hir_expand::name;
|
||||||
|
|
||||||
use ra_db::salsa::{InternId, InternKey};
|
use ra_db::salsa::{InternId, InternKey};
|
||||||
|
@ -832,9 +833,9 @@ fn closure_fn_trait_output_assoc_ty_value(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
|
fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
|
||||||
let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
|
let target = db.lang_item(krate.crate_id, fn_trait.lang_item_name().into())?;
|
||||||
match target {
|
match target {
|
||||||
crate::lang_item::LangItemTarget::Trait(t) => Some(t),
|
LangItemTarget::TraitId(t) => Some(t.into()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use hir_expand::{db::AstDatabase, HirFileId};
|
use hir_expand::{db::AstDatabase, HirFileId};
|
||||||
use ra_db::{salsa, CrateId, SourceDatabase};
|
use ra_db::{salsa, CrateId, SourceDatabase};
|
||||||
use ra_syntax::ast;
|
use ra_syntax::{ast, SmolStr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::{EnumData, StructData},
|
adt::{EnumData, StructData},
|
||||||
|
@ -11,12 +11,13 @@ use crate::{
|
||||||
body::{scope::ExprScopes, Body, BodySourceMap},
|
body::{scope::ExprScopes, Body, BodySourceMap},
|
||||||
data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData},
|
data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData},
|
||||||
generics::GenericParams,
|
generics::GenericParams,
|
||||||
|
lang_item::{LangItemTarget, LangItems},
|
||||||
nameres::{
|
nameres::{
|
||||||
raw::{ImportSourceMap, RawItems},
|
raw::{ImportSourceMap, RawItems},
|
||||||
CrateDefMap,
|
CrateDefMap,
|
||||||
},
|
},
|
||||||
AttrDefId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, ImplId, ItemLoc, StaticId,
|
AttrDefId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, ImplId, ItemLoc, ModuleId,
|
||||||
StructOrUnionId, TraitId, TypeAliasId,
|
StaticId, StructOrUnionId, TraitId, TypeAliasId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[salsa::query_group(InternDatabaseStorage)]
|
#[salsa::query_group(InternDatabaseStorage)]
|
||||||
|
@ -91,4 +92,13 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
|
||||||
|
|
||||||
#[salsa::invoke(Attrs::attrs_query)]
|
#[salsa::invoke(Attrs::attrs_query)]
|
||||||
fn attrs(&self, def: AttrDefId) -> Attrs;
|
fn attrs(&self, def: AttrDefId) -> Attrs;
|
||||||
|
|
||||||
|
#[salsa::invoke(LangItems::module_lang_items_query)]
|
||||||
|
fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>;
|
||||||
|
|
||||||
|
#[salsa::invoke(LangItems::crate_lang_items_query)]
|
||||||
|
fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
|
||||||
|
|
||||||
|
#[salsa::invoke(LangItems::lang_item_query)]
|
||||||
|
fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>;
|
||||||
}
|
}
|
||||||
|
|
120
crates/ra_hir_def/src/lang_item.rs
Normal file
120
crates/ra_hir_def/src/lang_item.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
//! Collects lang items: items marked with `#[lang = "..."]` attribute.
|
||||||
|
//!
|
||||||
|
//! This attribute to tell the compiler about semi built-in std library
|
||||||
|
//! features, such as Fn family of traits.
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ra_syntax::SmolStr;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
db::DefDatabase2, AdtId, AttrDefId, CrateId, EnumId, FunctionId, ImplId, ModuleDefId, ModuleId,
|
||||||
|
StaticId, StructId, TraitId,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum LangItemTarget {
|
||||||
|
EnumId(EnumId),
|
||||||
|
FunctionId(FunctionId),
|
||||||
|
ImplBlockId(ImplId),
|
||||||
|
StaticId(StaticId),
|
||||||
|
StructId(StructId),
|
||||||
|
TraitId(TraitId),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct LangItems {
|
||||||
|
items: FxHashMap<SmolStr, LangItemTarget>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LangItems {
|
||||||
|
pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
|
||||||
|
self.items.get(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Salsa query. This will look for lang items in a specific crate.
|
||||||
|
pub(crate) fn crate_lang_items_query(db: &impl DefDatabase2, krate: CrateId) -> Arc<LangItems> {
|
||||||
|
let mut lang_items = LangItems::default();
|
||||||
|
|
||||||
|
let crate_def_map = db.crate_def_map(krate);
|
||||||
|
|
||||||
|
crate_def_map
|
||||||
|
.modules()
|
||||||
|
.filter_map(|module_id| db.module_lang_items(ModuleId { krate, module_id }))
|
||||||
|
.for_each(|it| lang_items.items.extend(it.items.iter().map(|(k, v)| (k.clone(), *v))));
|
||||||
|
|
||||||
|
Arc::new(lang_items)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn module_lang_items_query(
|
||||||
|
db: &impl DefDatabase2,
|
||||||
|
module: ModuleId,
|
||||||
|
) -> Option<Arc<LangItems>> {
|
||||||
|
let mut lang_items = LangItems::default();
|
||||||
|
lang_items.collect_lang_items(db, module);
|
||||||
|
if lang_items.items.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Arc::new(lang_items))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Salsa query. Look for a lang item, starting from the specified crate and recursively
|
||||||
|
/// traversing its dependencies.
|
||||||
|
pub(crate) fn lang_item_query(
|
||||||
|
db: &impl DefDatabase2,
|
||||||
|
start_crate: CrateId,
|
||||||
|
item: SmolStr,
|
||||||
|
) -> Option<LangItemTarget> {
|
||||||
|
let lang_items = db.crate_lang_items(start_crate);
|
||||||
|
let start_crate_target = lang_items.items.get(&item);
|
||||||
|
if let Some(target) = start_crate_target {
|
||||||
|
return Some(*target);
|
||||||
|
}
|
||||||
|
db.crate_graph()
|
||||||
|
.dependencies(start_crate)
|
||||||
|
.find_map(|dep| db.lang_item(dep.crate_id, item.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_lang_items(&mut self, db: &impl DefDatabase2, module: ModuleId) {
|
||||||
|
// Look for impl targets
|
||||||
|
let def_map = db.crate_def_map(module.krate);
|
||||||
|
let module_data = &def_map[module.module_id];
|
||||||
|
for &impl_block in module_data.impls.iter() {
|
||||||
|
self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId)
|
||||||
|
}
|
||||||
|
|
||||||
|
for def in module_data.scope.declarations() {
|
||||||
|
match def {
|
||||||
|
ModuleDefId::TraitId(trait_) => {
|
||||||
|
self.collect_lang_item(db, trait_, LangItemTarget::TraitId)
|
||||||
|
}
|
||||||
|
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
|
||||||
|
self.collect_lang_item(db, e, LangItemTarget::EnumId)
|
||||||
|
}
|
||||||
|
ModuleDefId::AdtId(AdtId::StructId(s)) => {
|
||||||
|
self.collect_lang_item(db, s, LangItemTarget::StructId)
|
||||||
|
}
|
||||||
|
ModuleDefId::FunctionId(f) => {
|
||||||
|
self.collect_lang_item(db, f, LangItemTarget::FunctionId)
|
||||||
|
}
|
||||||
|
ModuleDefId::StaticId(s) => self.collect_lang_item(db, s, LangItemTarget::StaticId),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_lang_item<T>(
|
||||||
|
&mut self,
|
||||||
|
db: &impl DefDatabase2,
|
||||||
|
item: T,
|
||||||
|
constructor: fn(T) -> LangItemTarget,
|
||||||
|
) where
|
||||||
|
T: Into<AttrDefId> + Copy,
|
||||||
|
{
|
||||||
|
let attrs = db.attrs(item.into());
|
||||||
|
if let Some(lang_item_name) = attrs.find_string_value("lang") {
|
||||||
|
self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ pub mod body;
|
||||||
pub mod generics;
|
pub mod generics;
|
||||||
pub mod resolver;
|
pub mod resolver;
|
||||||
pub mod data;
|
pub mod data;
|
||||||
|
pub mod lang_item;
|
||||||
|
|
||||||
mod trace;
|
mod trace;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue