diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/db.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/lang_item.rs | 102 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 22 |
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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile, ast}; | 3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile, SmolStr, ast}; |
4 | use ra_db::{SourceDatabase, salsa}; | 4 | use ra_db::{SourceDatabase, salsa}; |
5 | 5 | ||
6 | use crate::{ | 6 | use 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 @@ | |||
1 | use std::sync::Arc; | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use ra_syntax::{SmolStr, ast::AttrsOwner}; | ||
5 | |||
6 | use crate::{ | ||
7 | Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, Static, Struct, Trait | ||
8 | }; | ||
9 | |||
10 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
11 | pub enum LangItemTarget { | ||
12 | Enum(Enum), | ||
13 | Function(Function), | ||
14 | ImplBlock(ImplBlock), | ||
15 | Static(Static), | ||
16 | Struct(Struct), | ||
17 | Trait(Trait), | ||
18 | } | ||
19 | |||
20 | impl 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)] | ||
34 | pub struct LangItems { | ||
35 | items: FxHashMap<SmolStr, LangItemTarget>, | ||
36 | } | ||
37 | |||
38 | impl 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; | |||
36 | mod ty; | 36 | mod ty; |
37 | mod impl_block; | 37 | mod impl_block; |
38 | mod expr; | 38 | mod expr; |
39 | mod lang_item; | ||
39 | mod generics; | 40 | mod generics; |
40 | mod docs; | 41 | mod docs; |
41 | mod resolve; | 42 | mod 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 | ||
6 | use crate::{ | 6 | use 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 | ||
202 | impl Resolver { | 208 | impl 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 | }; |
18 | use super::{TraitRef, Substs}; | 19 | use super::{TraitRef, Substs}; |
19 | 20 | ||
@@ -110,10 +111,19 @@ impl CrateImplBlocks { | |||
110 | } | 111 | } |
111 | } | 112 | } |
112 | 113 | ||
113 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | 114 | fn 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] |
630 | fn infer_inherent_method_str() { | ||
631 | assert_snapshot_matches!( | ||
632 | infer(r#" | ||
633 | #[lang = "str"] | ||
634 | impl str { | ||
635 | fn foo(&self) -> i32 {} | ||
636 | } | ||
637 | |||
638 | fn 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] | ||
630 | fn infer_tuple() { | 652 | fn infer_tuple() { |
631 | assert_snapshot_matches!( | 653 | assert_snapshot_matches!( |
632 | infer(r#" | 654 | infer(r#" |