aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/db.rs9
-rw-r--r--crates/ra_hir/src/lang_item.rs102
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/nameres.rs4
-rw-r--r--crates/ra_hir/src/resolve.rs8
-rw-r--r--crates/ra_hir/src/ty/infer.rs4
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs23
-rw-r--r--crates/ra_hir/src/ty/tests.rs22
8 files changed, 166 insertions, 7 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 18627bbc2..8af0a3176 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,6 +1,6 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile, ast}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile, SmolStr, ast};
4use ra_db::{SourceDatabase, salsa}; 4use ra_db::{SourceDatabase, salsa};
5 5
6use crate::{ 6use crate::{
@@ -16,6 +16,7 @@ use crate::{
16 generics::{GenericParams, GenericDef}, 16 generics::{GenericParams, GenericDef},
17 type_ref::TypeRef, 17 type_ref::TypeRef,
18 traits::TraitData, Trait, ty::TraitRef, 18 traits::TraitData, Trait, ty::TraitRef,
19 lang_item::{LangItems, LangItemTarget},
19 ids 20 ids
20}; 21};
21 22
@@ -100,6 +101,12 @@ pub trait DefDatabase: SourceDatabase {
100 101
101 #[salsa::invoke(crate::ConstSignature::static_signature_query)] 102 #[salsa::invoke(crate::ConstSignature::static_signature_query)]
102 fn static_signature(&self, konst: Static) -> Arc<ConstSignature>; 103 fn static_signature(&self, konst: Static) -> Arc<ConstSignature>;
104
105 #[salsa::invoke(crate::lang_item::LangItems::lang_items_query)]
106 fn lang_items(&self, krate: Crate) -> Arc<LangItems>;
107
108 #[salsa::invoke(crate::lang_item::LangItems::lang_item_query)]
109 fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>;
103} 110}
104 111
105#[salsa::query_group(HirDatabaseStorage)] 112#[salsa::query_group(HirDatabaseStorage)]
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs
new file mode 100644
index 000000000..5f3f91cba
--- /dev/null
+++ b/crates/ra_hir/src/lang_item.rs
@@ -0,0 +1,102 @@
1use std::sync::Arc;
2use rustc_hash::FxHashMap;
3
4use ra_syntax::{SmolStr, ast::AttrsOwner};
5
6use crate::{
7 Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, Static, Struct, Trait
8};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum LangItemTarget {
12 Enum(Enum),
13 Function(Function),
14 ImplBlock(ImplBlock),
15 Static(Static),
16 Struct(Struct),
17 Trait(Trait),
18}
19
20impl LangItemTarget {
21 pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
22 match self {
23 LangItemTarget::Enum(e) => e.module(db).krate(db),
24 LangItemTarget::Function(f) => f.module(db).krate(db),
25 LangItemTarget::ImplBlock(i) => i.module().krate(db),
26 LangItemTarget::Static(s) => s.module(db).krate(db),
27 LangItemTarget::Struct(s) => s.module(db).krate(db),
28 LangItemTarget::Trait(t) => t.module(db).krate(db),
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct LangItems {
35 items: FxHashMap<SmolStr, LangItemTarget>,
36}
37
38impl LangItems {
39 pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
40 self.items.get(item)
41 }
42
43 /// Salsa query. This will look for lang items in a specific crate.
44 pub(crate) fn lang_items_query(db: &impl DefDatabase, krate: Crate) -> Arc<LangItems> {
45 let mut lang_items = LangItems { items: FxHashMap::default() };
46
47 if let Some(module) = krate.root_module(db) {
48 lang_items.collect_lang_items_recursive(db, &module);
49 }
50
51 Arc::new(lang_items)
52 }
53
54 /// Salsa query. Look for a lang item, starting from the specified crate and recursively
55 /// traversing its dependencies.
56 pub(crate) fn lang_item_query(
57 db: &impl DefDatabase,
58 start_crate: Crate,
59 item: SmolStr,
60 ) -> Option<LangItemTarget> {
61 let lang_items = db.lang_items(start_crate);
62 let start_crate_target = lang_items.items.get(&item);
63 if let Some(target) = start_crate_target {
64 Some(*target)
65 } else {
66 for dep in start_crate.dependencies(db) {
67 let dep_crate = dep.krate;
68 let dep_target = db.lang_item(dep_crate, item.clone());
69 if dep_target.is_some() {
70 return dep_target;
71 }
72 }
73 None
74 }
75 }
76
77 fn collect_lang_items_recursive(&mut self, db: &impl DefDatabase, module: &Module) {
78 // Look for impl targets
79 let (impl_blocks, source_map) = db.impls_in_module_with_source_map(module.clone());
80 let source = module.definition_source(db).1;
81 for (impl_id, _) in impl_blocks.impls.iter() {
82 let impl_block = source_map.get(&source, impl_id);
83 let lang_item_name = impl_block
84 .attrs()
85 .filter_map(|a| a.as_key_value())
86 .filter(|(key, _)| key == "lang")
87 .map(|(_, val)| val)
88 .nth(0);
89 if let Some(lang_item_name) = lang_item_name {
90 let imp = ImplBlock::from_id(*module, impl_id);
91 self.items.entry(lang_item_name).or_insert(LangItemTarget::ImplBlock(imp));
92 }
93 }
94
95 // FIXME we should look for the other lang item targets (traits, structs, ...)
96
97 // Look for lang items in the children
98 for child in module.children(db) {
99 self.collect_lang_items_recursive(db, &child);
100 }
101 }
102}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 9292de1b5..4411715de 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -36,6 +36,7 @@ mod type_ref;
36mod ty; 36mod ty;
37mod impl_block; 37mod impl_block;
38mod expr; 38mod expr;
39mod lang_item;
39mod generics; 40mod generics;
40mod docs; 41mod docs;
41mod resolve; 42mod resolve;
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 0eddfab12..39152360c 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -202,6 +202,10 @@ impl CrateDefMap {
202 Arc::new(def_map) 202 Arc::new(def_map)
203 } 203 }
204 204
205 pub(crate) fn krate(&self) -> Crate {
206 self.krate
207 }
208
205 pub(crate) fn root(&self) -> CrateModuleId { 209 pub(crate) fn root(&self) -> CrateModuleId {
206 self.root 210 self.root
207 } 211 }
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 685f4b8b1..f2c85eb66 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -5,13 +5,15 @@ use rustc_hash::FxHashMap;
5 5
6use crate::{ 6use crate::{
7 ModuleDef, 7 ModuleDef,
8 code_model_api::Crate,
8 db::HirDatabase, 9 db::HirDatabase,
9 name::{Name, KnownName}, 10 name::{Name, KnownName},
10 nameres::{PerNs, CrateDefMap, CrateModuleId}, 11 nameres::{PerNs, CrateDefMap, CrateModuleId},
11 generics::GenericParams, 12 generics::GenericParams,
12 expr::{scope::{ExprScopes, ScopeId}, PatId}, 13 expr::{scope::{ExprScopes, ScopeId}, PatId},
13 impl_block::ImplBlock, 14 impl_block::ImplBlock,
14 path::Path, Trait 15 path::Path,
16 Trait
15}; 17};
16 18
17#[derive(Debug, Clone, Default)] 19#[derive(Debug, Clone, Default)]
@@ -197,6 +199,10 @@ impl Resolver {
197 _ => None, 199 _ => None,
198 }) 200 })
199 } 201 }
202
203 pub(crate) fn krate(&self) -> Option<Crate> {
204 self.module().map(|t| t.0.krate())
205 }
200} 206}
201 207
202impl Resolver { 208impl Resolver {
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 7ca1ff595..c7772a7f6 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -462,6 +462,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
462 let remaining_index = remaining_index.unwrap_or(path.segments.len()); 462 let remaining_index = remaining_index.unwrap_or(path.segments.len());
463 let mut actual_def_ty: Option<Ty> = None; 463 let mut actual_def_ty: Option<Ty> = None;
464 464
465 let krate = resolver.krate()?;
465 // resolve intermediate segments 466 // resolve intermediate segments
466 for (i, segment) in path.segments[remaining_index..].iter().enumerate() { 467 for (i, segment) in path.segments[remaining_index..].iter().enumerate() {
467 let ty = match resolved { 468 let ty = match resolved {
@@ -500,9 +501,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
500 // Attempt to find an impl_item for the type which has a name matching 501 // Attempt to find an impl_item for the type which has a name matching
501 // the current segment 502 // the current segment
502 log::debug!("looking for path segment: {:?}", segment); 503 log::debug!("looking for path segment: {:?}", segment);
504
503 actual_def_ty = Some(ty.clone()); 505 actual_def_ty = Some(ty.clone());
504 506
505 let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { 507 let item: crate::ModuleDef = ty.iterate_impl_items(self.db, krate, |item| {
506 let matching_def: Option<crate::ModuleDef> = match item { 508 let matching_def: Option<crate::ModuleDef> = match item {
507 crate::ImplItem::Method(func) => { 509 crate::ImplItem::Method(func) => {
508 let sig = func.signature(self.db); 510 let sig = func.signature(self.db);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 667b66095..ea6e0dc0f 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -14,6 +14,7 @@ use crate::{
14 resolve::Resolver, 14 resolve::Resolver,
15 traits::TraitItem, 15 traits::TraitItem,
16 generics::HasGenericParams, 16 generics::HasGenericParams,
17 ty::primitive::{UncertainIntTy, UncertainFloatTy}
17}; 18};
18use super::{TraitRef, Substs}; 19use super::{TraitRef, Substs};
19 20
@@ -110,10 +111,19 @@ impl CrateImplBlocks {
110 } 111 }
111} 112}
112 113
113fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { 114fn def_crate(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<Crate> {
114 match ty { 115 match ty {
115 Ty::Apply(a_ty) => match a_ty.ctor { 116 Ty::Apply(a_ty) => match a_ty.ctor {
116 TypeCtor::Adt(def_id) => def_id.krate(db), 117 TypeCtor::Adt(def_id) => def_id.krate(db),
118 TypeCtor::Bool => db.lang_item(cur_crate, "bool".into())?.krate(db),
119 TypeCtor::Char => db.lang_item(cur_crate, "char".into())?.krate(db),
120 TypeCtor::Float(UncertainFloatTy::Known(f)) => {
121 db.lang_item(cur_crate, f.ty_to_string().into())?.krate(db)
122 }
123 TypeCtor::Int(UncertainIntTy::Known(i)) => {
124 db.lang_item(cur_crate, i.ty_to_string().into())?.krate(db)
125 }
126 TypeCtor::Str => db.lang_item(cur_crate, "str".into())?.krate(db),
117 _ => None, 127 _ => None,
118 }, 128 },
119 _ => None, 129 _ => None,
@@ -150,8 +160,11 @@ impl Ty {
150 // find in the end takes &self, we still do the autoderef step (just as 160 // find in the end takes &self, we still do the autoderef step (just as
151 // rustc does an autoderef and then autoref again). 161 // rustc does an autoderef and then autoref again).
152 162
163 let krate = resolver.krate()?;
153 for derefed_ty in self.autoderef(db) { 164 for derefed_ty in self.autoderef(db) {
154 if let Some(result) = derefed_ty.iterate_inherent_methods(db, name, &mut callback) { 165 if let Some(result) =
166 derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback)
167 {
155 return Some(result); 168 return Some(result);
156 } 169 }
157 if let Some(result) = 170 if let Some(result) =
@@ -208,9 +221,10 @@ impl Ty {
208 &self, 221 &self,
209 db: &impl HirDatabase, 222 db: &impl HirDatabase,
210 name: Option<&Name>, 223 name: Option<&Name>,
224 krate: Crate,
211 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 225 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
212 ) -> Option<T> { 226 ) -> Option<T> {
213 let krate = match def_crate(db, self) { 227 let krate = match def_crate(db, krate, self) {
214 Some(krate) => krate, 228 Some(krate) => krate,
215 None => return None, 229 None => return None,
216 }; 230 };
@@ -239,9 +253,10 @@ impl Ty {
239 pub fn iterate_impl_items<T>( 253 pub fn iterate_impl_items<T>(
240 self, 254 self,
241 db: &impl HirDatabase, 255 db: &impl HirDatabase,
256 krate: Crate,
242 mut callback: impl FnMut(ImplItem) -> Option<T>, 257 mut callback: impl FnMut(ImplItem) -> Option<T>,
243 ) -> Option<T> { 258 ) -> Option<T> {
244 let krate = def_crate(db, &self)?; 259 let krate = def_crate(db, krate, &self)?;
245 let impls = db.impls_in_crate(krate); 260 let impls = db.impls_in_crate(krate);
246 261
247 for impl_block in impls.lookup_impl_blocks(&self) { 262 for impl_block in impls.lookup_impl_blocks(&self) {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 8d8a0eaaa..86f18b487 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -627,6 +627,28 @@ fn test(a: A) {
627} 627}
628 628
629#[test] 629#[test]
630fn infer_inherent_method_str() {
631 assert_snapshot_matches!(
632 infer(r#"
633#[lang = "str"]
634impl str {
635 fn foo(&self) -> i32 {}
636}
637
638fn test() {
639 "foo".foo();
640}
641"#),
642 @r###"
643[40; 44) 'self': &str
644[53; 55) '{}': ()
645[69; 89) '{ ...o(); }': ()
646[75; 80) '"foo"': &str
647[75; 86) '"foo".foo()': i32"###
648 );
649}
650
651#[test]
630fn infer_tuple() { 652fn infer_tuple() {
631 assert_snapshot_matches!( 653 assert_snapshot_matches!(
632 infer(r#" 654 infer(r#"