aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/db.rs23
-rw-r--r--crates/ra_hir/src/lang_item.rs154
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs7
-rw-r--r--crates/ra_hir/src/ty/infer/coerce.rs7
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs47
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs5
-rw-r--r--crates/ra_hir_def/src/db.rs16
-rw-r--r--crates/ra_hir_def/src/lang_item.rs120
-rw-r--r--crates/ra_hir_def/src/lib.rs1
10 files changed, 179 insertions, 202 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index c3f698ea0..cae305f98 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -3,27 +3,25 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use ra_db::salsa; 5use ra_db::salsa;
6use ra_syntax::SmolStr;
7 6
8use crate::{ 7use crate::{
9 debug::HirDebugDatabase, 8 debug::HirDebugDatabase,
10 ids, 9 ids,
11 lang_item::{LangItemTarget, LangItems},
12 ty::{ 10 ty::{
13 method_resolution::CrateImplBlocks, 11 method_resolution::CrateImplBlocks,
14 traits::{AssocTyValue, Impl}, 12 traits::{AssocTyValue, Impl},
15 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef, 13 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
16 TypeCtor, 14 TypeCtor,
17 }, 15 },
18 Crate, DefWithBody, GenericDef, ImplBlock, Module, StructField, Trait, 16 Crate, DefWithBody, GenericDef, ImplBlock, StructField, Trait,
19}; 17};
20 18
21pub use hir_def::db::{ 19pub use hir_def::db::{
22 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, DefDatabase2, 20 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
23 DefDatabase2Storage, EnumDataQuery, ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, 21 DefDatabase2, DefDatabase2Storage, EnumDataQuery, ExprScopesQuery, FunctionDataQuery,
24 ImplDataQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, 22 GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage, LangItemQuery,
25 RawItemsWithSourceMapQuery, StaticDataQuery, StructDataQuery, TraitDataQuery, 23 ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery, StaticDataQuery,
26 TypeAliasDataQuery, 24 StructDataQuery, TraitDataQuery, TypeAliasDataQuery,
27}; 25};
28pub use hir_expand::db::{ 26pub use hir_expand::db::{
29 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 27 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@@ -34,15 +32,6 @@ pub use hir_expand::db::{
34#[salsa::query_group(DefDatabaseStorage)] 32#[salsa::query_group(DefDatabaseStorage)]
35#[salsa::requires(AstDatabase)] 33#[salsa::requires(AstDatabase)]
36pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { 34pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
37 #[salsa::invoke(LangItems::module_lang_items_query)]
38 fn module_lang_items(&self, module: Module) -> Option<Arc<LangItems>>;
39
40 #[salsa::invoke(LangItems::crate_lang_items_query)]
41 fn crate_lang_items(&self, krate: Crate) -> Arc<LangItems>;
42
43 #[salsa::invoke(LangItems::lang_item_query)]
44 fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>;
45
46 #[salsa::invoke(crate::code_model::docs::documentation_query)] 35 #[salsa::invoke(crate::code_model::docs::documentation_query)]
47 fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>; 36 fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>;
48} 37}
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs
deleted file mode 100644
index 55f0c3a13..000000000
--- a/crates/ra_hir/src/lang_item.rs
+++ /dev/null
@@ -1,154 +0,0 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use hir_def::{AdtId, AttrDefId, ModuleDefId};
6use ra_syntax::SmolStr;
7use rustc_hash::FxHashMap;
8
9use crate::{
10 db::{AstDatabase, DefDatabase, HirDatabase},
11 Crate, Enum, Function, ImplBlock, Module, Static, Struct, Trait,
12};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum LangItemTarget {
16 Enum(Enum),
17 Function(Function),
18 ImplBlock(ImplBlock),
19 Static(Static),
20 Struct(Struct),
21 Trait(Trait),
22}
23
24impl LangItemTarget {
25 pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
26 Some(match self {
27 LangItemTarget::Enum(e) => e.module(db).krate(),
28 LangItemTarget::Function(f) => f.module(db).krate(),
29 LangItemTarget::ImplBlock(i) => i.krate(db),
30 LangItemTarget::Static(s) => s.module(db).krate(),
31 LangItemTarget::Struct(s) => s.module(db).krate(),
32 LangItemTarget::Trait(t) => t.module(db).krate(),
33 })
34 }
35}
36
37#[derive(Default, Debug, Clone, PartialEq, Eq)]
38pub struct LangItems {
39 items: FxHashMap<SmolStr, LangItemTarget>,
40}
41
42impl LangItems {
43 pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
44 self.items.get(item)
45 }
46
47 /// Salsa query. This will look for lang items in a specific crate.
48 pub(crate) fn crate_lang_items_query(
49 db: &(impl DefDatabase + AstDatabase),
50 krate: Crate,
51 ) -> Arc<LangItems> {
52 let mut lang_items = LangItems::default();
53
54 if let Some(module) = krate.root_module(db) {
55 lang_items.collect_lang_items_recursive(db, module);
56 }
57
58 Arc::new(lang_items)
59 }
60
61 pub(crate) fn module_lang_items_query(
62 db: &(impl DefDatabase + AstDatabase),
63 module: Module,
64 ) -> Option<Arc<LangItems>> {
65 let mut lang_items = LangItems::default();
66 lang_items.collect_lang_items(db, module);
67 if lang_items.items.is_empty() {
68 None
69 } else {
70 Some(Arc::new(lang_items))
71 }
72 }
73
74 /// Salsa query. Look for a lang item, starting from the specified crate and recursively
75 /// traversing its dependencies.
76 pub(crate) fn lang_item_query(
77 db: &impl DefDatabase,
78 start_crate: Crate,
79 item: SmolStr,
80 ) -> Option<LangItemTarget> {
81 let lang_items = db.crate_lang_items(start_crate);
82 let start_crate_target = lang_items.items.get(&item);
83 if let Some(target) = start_crate_target {
84 Some(*target)
85 } else {
86 for dep in start_crate.dependencies(db) {
87 let dep_crate = dep.krate;
88 let dep_target = db.lang_item(dep_crate, item.clone());
89 if dep_target.is_some() {
90 return dep_target;
91 }
92 }
93 None
94 }
95 }
96
97 fn collect_lang_items(&mut self, db: &(impl DefDatabase + AstDatabase), module: Module) {
98 // Look for impl targets
99 let def_map = db.crate_def_map(module.id.krate);
100 let module_data = &def_map[module.id.module_id];
101 for &impl_block in module_data.impls.iter() {
102 self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlock)
103 }
104
105 for def in module_data.scope.declarations() {
106 match def {
107 ModuleDefId::TraitId(trait_) => {
108 self.collect_lang_item(db, trait_, LangItemTarget::Trait)
109 }
110 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
111 self.collect_lang_item(db, e, LangItemTarget::Enum)
112 }
113 ModuleDefId::AdtId(AdtId::StructId(s)) => {
114 self.collect_lang_item(db, s, LangItemTarget::Struct)
115 }
116 ModuleDefId::FunctionId(f) => {
117 self.collect_lang_item(db, f, LangItemTarget::Function)
118 }
119 ModuleDefId::StaticId(s) => self.collect_lang_item(db, s, LangItemTarget::Static),
120 _ => {}
121 }
122 }
123 }
124
125 fn collect_lang_items_recursive(
126 &mut self,
127 db: &(impl DefDatabase + AstDatabase),
128 module: Module,
129 ) {
130 if let Some(module_lang_items) = db.module_lang_items(module) {
131 self.items.extend(module_lang_items.items.iter().map(|(k, v)| (k.clone(), *v)))
132 }
133
134 // Look for lang items in the children
135 for child in module.children(db) {
136 self.collect_lang_items_recursive(db, child);
137 }
138 }
139
140 fn collect_lang_item<T, D>(
141 &mut self,
142 db: &(impl DefDatabase + AstDatabase),
143 item: T,
144 constructor: fn(D) -> LangItemTarget,
145 ) where
146 T: Into<AttrDefId> + Copy,
147 D: From<T>,
148 {
149 let attrs = db.attrs(item.into());
150 if let Some(lang_item_name) = attrs.find_string_value("lang") {
151 self.items.entry(lang_item_name).or_insert_with(|| constructor(D::from(item)));
152 }
153 }
154}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 152590cd1..22da05a97 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -35,7 +35,6 @@ mod ids;
35mod ty; 35mod ty;
36mod impl_block; 36mod impl_block;
37mod expr; 37mod expr;
38mod lang_item;
39pub mod diagnostics; 38pub mod diagnostics;
40mod util; 39mod util;
41 40
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index b60e4bb31..41c99d227 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -5,12 +5,13 @@
5 5
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::resolver::Resolver; 8use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
9use hir_expand::name; 9use hir_expand::name;
10use log::{info, warn}; 10use log::{info, warn};
11 11
12use crate::{db::HirDatabase, Trait};
13
12use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; 14use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
13use crate::db::HirDatabase;
14 15
15const AUTODEREF_RECURSION_LIMIT: usize = 10; 16const AUTODEREF_RECURSION_LIMIT: usize = 10;
16 17
@@ -41,7 +42,7 @@ fn deref_by_trait(
41) -> Option<Canonical<Ty>> { 42) -> Option<Canonical<Ty>> {
42 let krate = resolver.krate()?; 43 let krate = resolver.krate()?;
43 let deref_trait = match db.lang_item(krate.into(), "deref".into())? { 44 let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
44 crate::lang_item::LangItemTarget::Trait(t) => t, 45 LangItemTarget::TraitId(t) => Trait::from(t),
45 _ => return None, 46 _ => return None,
46 }; 47 };
47 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; 48 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs
index 0772b9df5..4ea038d99 100644
--- a/crates/ra_hir/src/ty/infer/coerce.rs
+++ b/crates/ra_hir/src/ty/infer/coerce.rs
@@ -4,13 +4,12 @@
4//! 4//!
5//! See: https://doc.rust-lang.org/nomicon/coercions.html 5//! See: https://doc.rust-lang.org/nomicon/coercions.html
6 6
7use hir_def::resolver::Resolver; 7use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use test_utils::tested_by; 9use test_utils::tested_by;
10 10
11use crate::{ 11use crate::{
12 db::HirDatabase, 12 db::HirDatabase,
13 lang_item::LangItemTarget,
14 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk}, 13 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
15 Adt, Mutability, 14 Adt, Mutability,
16}; 15};
@@ -50,7 +49,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
50 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> { 49 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
51 let krate = resolver.krate().unwrap(); 50 let krate = resolver.krate().unwrap();
52 let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) { 51 let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) {
53 Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate.into(), trait_), 52 Some(LangItemTarget::TraitId(trait_)) => {
53 db.impls_for_trait(krate.into(), trait_.into())
54 }
54 _ => return FxHashMap::default(), 55 _ => return FxHashMap::default(),
55 }; 56 };
56 57
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index f61c27218..caa5f5f74 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -5,7 +5,7 @@
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::resolver::Resolver; 8use hir_def::{lang_item::LangItemTarget, resolver::Resolver, AstItemDef};
9use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
10 10
11use crate::{ 11use crate::{
@@ -91,34 +91,43 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV
91 // Types like slice can have inherent impls in several crates, (core and alloc). 91 // Types like slice can have inherent impls in several crates, (core and alloc).
92 // The corresponding impls are marked with lang items, so we can use them to find the required crates. 92 // The corresponding impls are marked with lang items, so we can use them to find the required crates.
93 macro_rules! lang_item_crate { 93 macro_rules! lang_item_crate {
94 ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{ 94 ($($name:expr),+ $(,)?) => {{
95 let mut v = ArrayVec::<[Crate; 2]>::new(); 95 let mut v = ArrayVec::<[LangItemTarget; 2]>::new();
96 $( 96 $(
97 v.extend($db.lang_item($cur_crate, $name.into()).and_then(|item| item.krate($db))); 97 v.extend(db.lang_item(cur_crate.crate_id, $name.into()));
98 )+ 98 )+
99 Some(v) 99 v
100 }}; 100 }};
101 } 101 }
102 102
103 match ty { 103 let lang_item_targets = match ty {
104 Ty::Apply(a_ty) => match a_ty.ctor { 104 Ty::Apply(a_ty) => match a_ty.ctor {
105 TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), 105 TypeCtor::Adt(def_id) => return Some(std::iter::once(def_id.krate(db)?).collect()),
106 TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), 106 TypeCtor::Bool => lang_item_crate!("bool"),
107 TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), 107 TypeCtor::Char => lang_item_crate!("char"),
108 TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { 108 TypeCtor::Float(Uncertain::Known(f)) => match f.bitness {
109 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) 109 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
110 FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), 110 FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"),
111 FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), 111 FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"),
112 }, 112 },
113 TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(db, cur_crate, i.ty_to_string()), 113 TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()),
114 TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), 114 TypeCtor::Str => lang_item_crate!("str_alloc", "str"),
115 TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), 115 TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"),
116 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), 116 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"),
117 TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!(db, cur_crate, "mut_ptr"), 117 TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!("mut_ptr"),
118 _ => None, 118 _ => return None,
119 }, 119 },
120 _ => None, 120 _ => return None,
121 } 121 };
122 let res = lang_item_targets
123 .into_iter()
124 .filter_map(|it| match it {
125 LangItemTarget::ImplBlockId(it) => Some(it),
126 _ => None,
127 })
128 .map(|it| it.module(db).krate.into())
129 .collect();
130 Some(res)
122} 131}
123 132
124/// Look up the method with the given name, returning the actual autoderefed 133/// Look up the method with the given name, returning the actual autoderefed
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 88785f305..53818a5e5 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -9,6 +9,7 @@ use chalk_ir::{
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11 11
12use hir_def::lang_item::LangItemTarget;
12use hir_expand::name; 13use hir_expand::name;
13 14
14use ra_db::salsa::{InternId, InternKey}; 15use ra_db::salsa::{InternId, InternKey};
@@ -832,9 +833,9 @@ fn closure_fn_trait_output_assoc_ty_value(
832} 833}
833 834
834fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { 835fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
835 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; 836 let target = db.lang_item(krate.crate_id, fn_trait.lang_item_name().into())?;
836 match target { 837 match target {
837 crate::lang_item::LangItemTarget::Trait(t) => Some(t), 838 LangItemTarget::TraitId(t) => Some(t.into()),
838 _ => None, 839 _ => None,
839 } 840 }
840} 841}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index e91e741bb..e87bd525a 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3 3
4use hir_expand::{db::AstDatabase, HirFileId}; 4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, CrateId, SourceDatabase}; 5use ra_db::{salsa, CrateId, SourceDatabase};
6use ra_syntax::ast; 6use ra_syntax::{ast, SmolStr};
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
@@ -11,12 +11,13 @@ use crate::{
11 body::{scope::ExprScopes, Body, BodySourceMap}, 11 body::{scope::ExprScopes, Body, BodySourceMap},
12 data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData}, 12 data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData},
13 generics::GenericParams, 13 generics::GenericParams,
14 lang_item::{LangItemTarget, LangItems},
14 nameres::{ 15 nameres::{
15 raw::{ImportSourceMap, RawItems}, 16 raw::{ImportSourceMap, RawItems},
16 CrateDefMap, 17 CrateDefMap,
17 }, 18 },
18 AttrDefId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, ImplId, ItemLoc, StaticId, 19 AttrDefId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, ImplId, ItemLoc, ModuleId,
19 StructOrUnionId, TraitId, TypeAliasId, 20 StaticId, StructOrUnionId, TraitId, TypeAliasId,
20}; 21};
21 22
22#[salsa::query_group(InternDatabaseStorage)] 23#[salsa::query_group(InternDatabaseStorage)]
@@ -91,4 +92,13 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
91 92
92 #[salsa::invoke(Attrs::attrs_query)] 93 #[salsa::invoke(Attrs::attrs_query)]
93 fn attrs(&self, def: AttrDefId) -> Attrs; 94 fn attrs(&self, def: AttrDefId) -> Attrs;
95
96 #[salsa::invoke(LangItems::module_lang_items_query)]
97 fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>;
98
99 #[salsa::invoke(LangItems::crate_lang_items_query)]
100 fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
101
102 #[salsa::invoke(LangItems::lang_item_query)]
103 fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>;
94} 104}
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
new file mode 100644
index 000000000..4c1a764ea
--- /dev/null
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -0,0 +1,120 @@
1//! Collects lang items: items marked with `#[lang = "..."]` attribute.
2//!
3//! This attribute to tell the compiler about semi built-in std library
4//! features, such as Fn family of traits.
5use std::sync::Arc;
6
7use ra_syntax::SmolStr;
8use rustc_hash::FxHashMap;
9
10use crate::{
11 db::DefDatabase2, AdtId, AttrDefId, CrateId, EnumId, FunctionId, ImplId, ModuleDefId, ModuleId,
12 StaticId, StructId, TraitId,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub enum LangItemTarget {
17 EnumId(EnumId),
18 FunctionId(FunctionId),
19 ImplBlockId(ImplId),
20 StaticId(StaticId),
21 StructId(StructId),
22 TraitId(TraitId),
23}
24
25#[derive(Default, Debug, Clone, PartialEq, Eq)]
26pub struct LangItems {
27 items: FxHashMap<SmolStr, LangItemTarget>,
28}
29
30impl LangItems {
31 pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
32 self.items.get(item)
33 }
34
35 /// Salsa query. This will look for lang items in a specific crate.
36 pub(crate) fn crate_lang_items_query(db: &impl DefDatabase2, krate: CrateId) -> Arc<LangItems> {
37 let mut lang_items = LangItems::default();
38
39 let crate_def_map = db.crate_def_map(krate);
40
41 crate_def_map
42 .modules()
43 .filter_map(|module_id| db.module_lang_items(ModuleId { krate, module_id }))
44 .for_each(|it| lang_items.items.extend(it.items.iter().map(|(k, v)| (k.clone(), *v))));
45
46 Arc::new(lang_items)
47 }
48
49 pub(crate) fn module_lang_items_query(
50 db: &impl DefDatabase2,
51 module: ModuleId,
52 ) -> Option<Arc<LangItems>> {
53 let mut lang_items = LangItems::default();
54 lang_items.collect_lang_items(db, module);
55 if lang_items.items.is_empty() {
56 None
57 } else {
58 Some(Arc::new(lang_items))
59 }
60 }
61
62 /// Salsa query. Look for a lang item, starting from the specified crate and recursively
63 /// traversing its dependencies.
64 pub(crate) fn lang_item_query(
65 db: &impl DefDatabase2,
66 start_crate: CrateId,
67 item: SmolStr,
68 ) -> Option<LangItemTarget> {
69 let lang_items = db.crate_lang_items(start_crate);
70 let start_crate_target = lang_items.items.get(&item);
71 if let Some(target) = start_crate_target {
72 return Some(*target);
73 }
74 db.crate_graph()
75 .dependencies(start_crate)
76 .find_map(|dep| db.lang_item(dep.crate_id, item.clone()))
77 }
78
79 fn collect_lang_items(&mut self, db: &impl DefDatabase2, module: ModuleId) {
80 // Look for impl targets
81 let def_map = db.crate_def_map(module.krate);
82 let module_data = &def_map[module.module_id];
83 for &impl_block in module_data.impls.iter() {
84 self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId)
85 }
86
87 for def in module_data.scope.declarations() {
88 match def {
89 ModuleDefId::TraitId(trait_) => {
90 self.collect_lang_item(db, trait_, LangItemTarget::TraitId)
91 }
92 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
93 self.collect_lang_item(db, e, LangItemTarget::EnumId)
94 }
95 ModuleDefId::AdtId(AdtId::StructId(s)) => {
96 self.collect_lang_item(db, s, LangItemTarget::StructId)
97 }
98 ModuleDefId::FunctionId(f) => {
99 self.collect_lang_item(db, f, LangItemTarget::FunctionId)
100 }
101 ModuleDefId::StaticId(s) => self.collect_lang_item(db, s, LangItemTarget::StaticId),
102 _ => {}
103 }
104 }
105 }
106
107 fn collect_lang_item<T>(
108 &mut self,
109 db: &impl DefDatabase2,
110 item: T,
111 constructor: fn(T) -> LangItemTarget,
112 ) where
113 T: Into<AttrDefId> + Copy,
114 {
115 let attrs = db.attrs(item.into());
116 if let Some(lang_item_name) = attrs.find_string_value("lang") {
117 self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
118 }
119 }
120}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 20d4deadb..899510be4 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -19,6 +19,7 @@ pub mod body;
19pub mod generics; 19pub mod generics;
20pub mod resolver; 20pub mod resolver;
21pub mod data; 21pub mod data;
22pub mod lang_item;
22 23
23mod trace; 24mod trace;
24 25