aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Groppo <[email protected]>2019-04-14 23:03:54 +0100
committerMarco Groppo <[email protected]>2019-04-19 23:10:19 +0100
commite85ee60c42db57368e24ad9ac24840c2494d383c (patch)
treea94bb45556b404452e2ef282e6d11887f93601ca
parentd55f1136d6444b1f50b9092c36a976d0e1c26202 (diff)
Initial support for lang items.
-rw-r--r--crates/ra_hir/src/db.rs4
-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.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs54
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs38
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs23
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs14
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1
-rw-r--r--crates/ra_syntax/src/grammar.ron2
11 files changed, 204 insertions, 41 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 18627bbc2..b27efcbe3 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -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,
19 ids 20 ids
20}; 21};
21 22
@@ -100,6 +101,9 @@ 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>;
103} 107}
104 108
105#[salsa::query_group(HirDatabaseStorage)] 109#[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..adcc682a2
--- /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 Impl(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::Impl(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 query a specific crate for lang items.
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 fn collect_lang_items_recursive(&mut self, db: &impl DefDatabase, module: &Module) {
55 // Look for impl targets
56 let (impl_blocks, source_map) = db.impls_in_module_with_source_map(module.clone());
57 let source = module.definition_source(db).1;
58 for (impl_id, _) in impl_blocks.impls.iter() {
59 let impl_block = source_map.get(&source, impl_id);
60 let lang_item_name = impl_block
61 .attrs()
62 .filter_map(|a| a.as_key_value())
63 .filter(|(key, _)| key == "lang")
64 .map(|(_, val)| val)
65 .nth(0);
66 if let Some(lang_item_name) = lang_item_name {
67 let imp = ImplBlock::from_id(*module, impl_id);
68 self.items.entry(lang_item_name).or_insert(LangItemTarget::Impl(imp));
69 }
70 }
71
72 // FIXME we should look for the other lang item targets (traits, structs, ...)
73
74 // Look for lang items in the children
75 for child in module.children(db) {
76 self.collect_lang_items_recursive(db, &child);
77 }
78 }
79}
80
81/// Look for a lang item, starting from the specified crate and recursively traversing its
82/// dependencies.
83pub(crate) fn lang_item_lookup(
84 db: &impl DefDatabase,
85 start_krate: Crate,
86 item: &str,
87) -> Option<LangItemTarget> {
88 let lang_items = db.lang_items(start_krate);
89 let start_krate_target = lang_items.items.get(item);
90 if start_krate_target.is_some() {
91 start_krate_target.map(|t| *t)
92 } else {
93 for dep in start_krate.dependencies(db) {
94 let dep_krate = dep.krate;
95 let dep_target = lang_item_lookup(db, dep_krate, item);
96 if dep_target.is_some() {
97 return dep_target;
98 }
99 }
100 None
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..61925e832 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -190,7 +190,7 @@ impl Resolver {
190 .flatten() 190 .flatten()
191 } 191 }
192 192
193 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { 193 pub(crate) fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
194 self.scopes.iter().rev().find_map(|scope| match scope { 194 self.scopes.iter().rev().find_map(|scope| match scope {
195 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), 195 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
196 196
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 7ca1ff595..2275ac151 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.module().map(|t| t.0.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,38 +501,41 @@ 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 = krate.and_then(|k| {
506 let matching_def: Option<crate::ModuleDef> = match item { 508 ty.iterate_impl_items(self.db, k, |item| {
507 crate::ImplItem::Method(func) => { 509 let matching_def: Option<crate::ModuleDef> = match item {
508 let sig = func.signature(self.db); 510 crate::ImplItem::Method(func) => {
509 if segment.name == *sig.name() { 511 let sig = func.signature(self.db);
510 Some(func.into()) 512 if segment.name == *sig.name() {
511 } else { 513 Some(func.into())
512 None 514 } else {
515 None
516 }
513 } 517 }
514 }
515 518
516 crate::ImplItem::Const(konst) => { 519 crate::ImplItem::Const(konst) => {
517 let sig = konst.signature(self.db); 520 let sig = konst.signature(self.db);
518 if segment.name == *sig.name() { 521 if segment.name == *sig.name() {
519 Some(konst.into()) 522 Some(konst.into())
520 } else { 523 } else {
521 None 524 None
525 }
522 } 526 }
523 }
524 527
525 // FIXME: Resolve associated types 528 // FIXME: Resolve associated types
526 crate::ImplItem::TypeAlias(_) => None, 529 crate::ImplItem::TypeAlias(_) => None,
527 }; 530 };
528 match matching_def { 531 match matching_def {
529 Some(_) => { 532 Some(_) => {
530 self.write_assoc_resolution(id, item); 533 self.write_assoc_resolution(id, item);
531 return matching_def; 534 return matching_def;
535 }
536 None => None,
532 } 537 }
533 None => None, 538 })
534 }
535 })?; 539 })?;
536 540
537 resolved = Resolution::Def(item.into()); 541 resolved = Resolution::Def(item.into());
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 667b66095..ba516313c 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -14,6 +14,8 @@ use crate::{
14 resolve::Resolver, 14 resolve::Resolver,
15 traits::TraitItem, 15 traits::TraitItem,
16 generics::HasGenericParams, 16 generics::HasGenericParams,
17 lang_item::lang_item_lookup,
18 ty::primitive::{UncertainIntTy, UncertainFloatTy}
17}; 19};
18use super::{TraitRef, Substs}; 20use super::{TraitRef, Substs};
19 21
@@ -110,10 +112,33 @@ impl CrateImplBlocks {
110 } 112 }
111} 113}
112 114
113fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { 115/// Rudimentary check whether an impl exists for a given type and trait; this
116/// will actually be done by chalk.
117pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool {
118 // FIXME use all trait impls in the whole crate graph
119 let krate = trait_ref.trait_.module(db).krate(db);
120 let krate = match krate {
121 Some(krate) => krate,
122 None => return false,
123 };
124 let crate_impl_blocks = db.impls_in_crate(krate);
125 let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_);
126 impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty())
127}
128
129fn def_crate(db: &impl HirDatabase, cur_krate: Crate, ty: &Ty) -> Option<Crate> {
114 match ty { 130 match ty {
115 Ty::Apply(a_ty) => match a_ty.ctor { 131 Ty::Apply(a_ty) => match a_ty.ctor {
116 TypeCtor::Adt(def_id) => def_id.krate(db), 132 TypeCtor::Adt(def_id) => def_id.krate(db),
133 TypeCtor::Bool => lang_item_lookup(db, cur_krate, "bool")?.krate(db),
134 TypeCtor::Char => lang_item_lookup(db, cur_krate, "char")?.krate(db),
135 TypeCtor::Float(UncertainFloatTy::Known(f)) => {
136 lang_item_lookup(db, cur_krate, f.ty_to_string())?.krate(db)
137 }
138 TypeCtor::Int(UncertainIntTy::Known(i)) => {
139 lang_item_lookup(db, cur_krate, i.ty_to_string())?.krate(db)
140 }
141 TypeCtor::Str => lang_item_lookup(db, cur_krate, "str")?.krate(db),
117 _ => None, 142 _ => None,
118 }, 143 },
119 _ => None, 144 _ => None,
@@ -150,8 +175,11 @@ impl Ty {
150 // find in the end takes &self, we still do the autoderef step (just as 175 // find in the end takes &self, we still do the autoderef step (just as
151 // rustc does an autoderef and then autoref again). 176 // rustc does an autoderef and then autoref again).
152 177
178 let krate = resolver.module().map(|t| t.0.krate())?;
153 for derefed_ty in self.autoderef(db) { 179 for derefed_ty in self.autoderef(db) {
154 if let Some(result) = derefed_ty.iterate_inherent_methods(db, name, &mut callback) { 180 if let Some(result) =
181 derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback)
182 {
155 return Some(result); 183 return Some(result);
156 } 184 }
157 if let Some(result) = 185 if let Some(result) =
@@ -208,9 +236,10 @@ impl Ty {
208 &self, 236 &self,
209 db: &impl HirDatabase, 237 db: &impl HirDatabase,
210 name: Option<&Name>, 238 name: Option<&Name>,
239 krate: Crate,
211 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 240 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
212 ) -> Option<T> { 241 ) -> Option<T> {
213 let krate = match def_crate(db, self) { 242 let krate = match def_crate(db, krate, self) {
214 Some(krate) => krate, 243 Some(krate) => krate,
215 None => return None, 244 None => return None,
216 }; 245 };
@@ -239,9 +268,10 @@ impl Ty {
239 pub fn iterate_impl_items<T>( 268 pub fn iterate_impl_items<T>(
240 self, 269 self,
241 db: &impl HirDatabase, 270 db: &impl HirDatabase,
271 krate: Crate,
242 mut callback: impl FnMut(ImplItem) -> Option<T>, 272 mut callback: impl FnMut(ImplItem) -> Option<T>,
243 ) -> Option<T> { 273 ) -> Option<T> {
244 let krate = def_crate(db, &self)?; 274 let krate = def_crate(db, krate, &self)?;
245 let impls = db.impls_in_crate(krate); 275 let impls = db.impls_in_crate(krate);
246 276
247 for impl_block in impls.lookup_impl_blocks(&self) { 277 for impl_block in impls.lookup_impl_blocks(&self) {
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index bc03a7095..c49147b9e 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -38,18 +38,21 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
38 } 38 }
39 hir::ModuleDef::Struct(s) => { 39 hir::ModuleDef::Struct(s) => {
40 let ty = s.ty(ctx.db); 40 let ty = s.ty(ctx.db);
41 ty.iterate_impl_items(ctx.db, |item| { 41 let krate = ctx.module.and_then(|m| m.krate(ctx.db));
42 match item { 42 krate.map_or((), |krate| {
43 hir::ImplItem::Method(func) => { 43 ty.iterate_impl_items(ctx.db, krate, |item| {
44 let sig = func.signature(ctx.db); 44 match item {
45 if !sig.has_self_param() { 45 hir::ImplItem::Method(func) => {
46 acc.add_function(ctx, func); 46 let sig = func.signature(ctx.db);
47 if !sig.has_self_param() {
48 acc.add_function(ctx, func);
49 }
47 } 50 }
51 hir::ImplItem::Const(ct) => acc.add_const(ctx, ct),
52 hir::ImplItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
48 } 53 }
49 hir::ImplItem::Const(ct) => acc.add_const(ctx, ct), 54 None::<()>
50 hir::ImplItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), 55 });
51 }
52 None::<()>
53 }); 56 });
54 } 57 }
55 _ => return, 58 _ => return,
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index ca33b43e7..5c4c0ffc1 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -65,6 +65,20 @@ impl ast::Attr {
65 None 65 None
66 } 66 }
67 } 67 }
68
69 pub fn as_key_value(&self) -> Option<(SmolStr, SmolStr)> {
70 let tt = self.value()?;
71 let tt_node = tt.syntax();
72 let attr = tt_node.children_with_tokens().nth(1)?;
73 if attr.kind() == IDENT {
74 let key = attr.as_token()?.text().clone();
75 let val_node = tt_node.children_with_tokens().find(|t| t.kind() == STRING)?;
76 let val = val_node.as_token()?.text().trim_start_matches("\"").trim_end_matches("\"");
77 Some((key, SmolStr::new(val)))
78 } else {
79 None
80 }
81 }
68} 82}
69 83
70#[derive(Debug, Clone, Copy, PartialEq, Eq)] 84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 774d9bcc8..29a7ce166 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1325,6 +1325,7 @@ impl ToOwned for ImplBlock {
1325 1325
1326 1326
1327impl ast::TypeParamsOwner for ImplBlock {} 1327impl ast::TypeParamsOwner for ImplBlock {}
1328impl ast::AttrsOwner for ImplBlock {}
1328impl ImplBlock { 1329impl ImplBlock {
1329 pub fn item_list(&self) -> Option<&ItemList> { 1330 pub fn item_list(&self) -> Option<&ItemList> {
1330 super::child_opt(self) 1331 super::child_opt(self)
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index b41241287..41fe35f08 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -341,7 +341,7 @@ Grammar(
341 ], 341 ],
342 options: ["TypeRef"] 342 options: ["TypeRef"]
343 ), 343 ),
344 "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner"]), 344 "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner", "AttrsOwner"]),
345 345
346 "ParenType": (options: ["TypeRef"]), 346 "ParenType": (options: ["TypeRef"]),
347 "TupleType": ( collections: [["fields", "TypeRef"]] ), 347 "TupleType": ( collections: [["fields", "TypeRef"]] ),