aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-03-24 16:36:15 +0000
committerFlorian Diebold <[email protected]>2019-03-25 20:28:36 +0000
commitc947c15ce1ec02261803f10568e4659e9396109e (patch)
tree87e31a56ee05e5b3f3e498b74a0579b0d4cf7a19
parentbb77bc5c2f6c6b9681d9b3d0a068791db7eec0e2 (diff)
Basics for trait method resolution
-rw-r--r--crates/ra_hir/src/code_model_api.rs13
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/nameres.rs8
-rw-r--r--crates/ra_hir/src/resolve.rs17
-rw-r--r--crates/ra_hir/src/traits.rs52
-rw-r--r--crates/ra_hir/src/ty/infer.rs3
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs60
-rw-r--r--crates/ra_hir/src/ty/tests.rs12
-rw-r--r--crates/ra_syntax/src/ast/generated.rs6
-rw-r--r--crates/ra_syntax/src/grammar.ron5
11 files changed, 156 insertions, 25 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 5437133b8..88c13566c 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -17,6 +17,7 @@ use crate::{
17 impl_block::ImplBlock, 17 impl_block::ImplBlock,
18 resolve::Resolver, 18 resolve::Resolver,
19 diagnostics::DiagnosticSink, 19 diagnostics::DiagnosticSink,
20 traits::{TraitItem, TraitData},
20}; 21};
21 22
22/// hir::Crate describes a single crate. It's the main interface with which 23/// hir::Crate describes a single crate. It's the main interface with which
@@ -649,6 +650,18 @@ impl Trait {
649 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { 650 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> {
650 db.generic_params((*self).into()) 651 db.generic_params((*self).into())
651 } 652 }
653
654 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
655 self.trait_data(db).name().clone()
656 }
657
658 pub fn items(self, db: &impl DefDatabase) -> Vec<TraitItem> {
659 self.trait_data(db).items().to_vec()
660 }
661
662 pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
663 db.trait_data(self)
664 }
652} 665}
653 666
654impl Docs for Trait { 667impl Docs for Trait {
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index d3908f8ac..dd0bf6e34 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -14,6 +14,7 @@ use crate::{
14 impl_block::{ModuleImplBlocks, ImplSourceMap}, 14 impl_block::{ModuleImplBlocks, ImplSourceMap},
15 generics::{GenericParams, GenericDef}, 15 generics::{GenericParams, GenericDef},
16 type_ref::TypeRef, 16 type_ref::TypeRef,
17 traits::TraitData, Trait
17}; 18};
18 19
19#[salsa::query_group(DefDatabaseStorage)] 20#[salsa::query_group(DefDatabaseStorage)]
@@ -27,6 +28,9 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
27 #[salsa::invoke(crate::adt::EnumData::enum_data_query)] 28 #[salsa::invoke(crate::adt::EnumData::enum_data_query)]
28 fn enum_data(&self, e: Enum) -> Arc<EnumData>; 29 fn enum_data(&self, e: Enum) -> Arc<EnumData>;
29 30
31 #[salsa::invoke(crate::traits::TraitData::trait_data_query)]
32 fn trait_data(&self, t: Trait) -> Arc<TraitData>;
33
30 #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)] 34 #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)]
31 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; 35 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;
32 36
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ce54d7608..974ebd831 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -27,6 +27,7 @@ mod ids;
27mod name; 27mod name;
28mod nameres; 28mod nameres;
29mod adt; 29mod adt;
30mod traits;
30mod type_alias; 31mod type_alias;
31mod type_ref; 32mod type_ref;
32mod ty; 33mod ty;
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 56ed872d5..c34aa4b50 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -62,7 +62,7 @@ use test_utils::tested_by;
62 62
63use crate::{ 63use crate::{
64 ModuleDef, Name, Crate, Module, 64 ModuleDef, Name, Crate, Module,
65 DefDatabase, Path, PathKind, HirFileId, 65 DefDatabase, Path, PathKind, HirFileId, Trait,
66 ids::{SourceItemId, SourceFileItemId, MacroCallId}, 66 ids::{SourceItemId, SourceFileItemId, MacroCallId},
67 diagnostics::DiagnosticSink, 67 diagnostics::DiagnosticSink,
68 nameres::diagnostics::DefDiagnostic, 68 nameres::diagnostics::DefDiagnostic,
@@ -139,6 +139,12 @@ impl ModuleScope {
139 pub fn get(&self, name: &Name) -> Option<&Resolution> { 139 pub fn get(&self, name: &Name) -> Option<&Resolution> {
140 self.items.get(name) 140 self.items.get(name)
141 } 141 }
142 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
143 self.items.values().filter_map(|r| match r.def.take_types() {
144 Some(ModuleDef::Trait(t)) => Some(t),
145 _ => None,
146 })
147 }
142} 148}
143 149
144#[derive(Debug, Clone, PartialEq, Eq, Default)] 150#[derive(Debug, Clone, PartialEq, Eq, Default)]
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index f28154517..0f5031e76 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -11,7 +11,7 @@ use crate::{
11 generics::GenericParams, 11 generics::GenericParams,
12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, 12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body},
13 impl_block::ImplBlock, 13 impl_block::ImplBlock,
14 path::Path, 14 path::Path, Trait
15}; 15};
16 16
17#[derive(Debug, Clone, Default)] 17#[derive(Debug, Clone, Default)]
@@ -175,6 +175,21 @@ impl Resolver {
175 names 175 names
176 } 176 }
177 177
178 pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
179 // FIXME prelude
180 self.scopes
181 .iter()
182 .rev()
183 .flat_map(|scope| {
184 match scope {
185 Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()),
186 _ => None,
187 }
188 .into_iter()
189 })
190 .flat_map(|i| i)
191 }
192
178 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { 193 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
179 self.scopes.iter().rev().find_map(|scope| match scope { 194 self.scopes.iter().rev().find_map(|scope| match scope {
180 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), 195 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs
new file mode 100644
index 000000000..725bdd5cb
--- /dev/null
+++ b/crates/ra_hir/src/traits.rs
@@ -0,0 +1,52 @@
1//! HIR for trait definitions.
2
3use std::sync::Arc;
4
5use ra_syntax::ast::{self, NameOwner};
6
7use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct TraitData {
11 name: Option<Name>,
12 items: Vec<TraitItem>,
13}
14
15impl TraitData {
16 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: Trait) -> Arc<TraitData> {
17 let (file_id, node) = tr.source(db);
18 let name = node.name().map(|n| n.as_name());
19 let module = tr.module(db);
20 let ctx = LocationCtx::new(db, module, file_id);
21 let items = if let Some(item_list) = node.item_list() {
22 item_list
23 .impl_items()
24 .map(|item_node| match item_node.kind() {
25 ast::ImplItemKind::FnDef(it) => Function { id: ctx.to_def(it) }.into(),
26 ast::ImplItemKind::ConstDef(it) => Const { id: ctx.to_def(it) }.into(),
27 ast::ImplItemKind::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(it) }.into(),
28 })
29 .collect()
30 } else {
31 Vec::new()
32 };
33 Arc::new(TraitData { name, items })
34 }
35
36 pub(crate) fn name(&self) -> &Option<Name> {
37 &self.name
38 }
39
40 pub(crate) fn items(&self) -> &[TraitItem] {
41 &self.items
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub enum TraitItem {
47 Function(Function),
48 Const(Const),
49 TypeAlias(TypeAlias),
50 // Existential
51}
52impl_froms!(TraitItem: Function, Const, TypeAlias);
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 5fd602a9e..573115321 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -821,7 +821,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
821 } 821 }
822 Expr::MethodCall { receiver, args, method_name, generic_args } => { 822 Expr::MethodCall { receiver, args, method_name, generic_args } => {
823 let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); 823 let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
824 let resolved = receiver_ty.clone().lookup_method(self.db, method_name); 824 let resolved =
825 receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver);
825 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 826 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
826 Some((ty, func)) => { 827 Some((ty, func)) => {
827 self.write_method_resolution(tgt_expr, func); 828 self.write_method_resolution(tgt_expr, func);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index b1684acf9..708a435b4 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -11,7 +11,7 @@ use crate::{
11 ids::TraitId, 11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 12 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{Ty, TypeCtor}, 13 ty::{Ty, TypeCtor},
14 nameres::CrateModuleId, 14 nameres::CrateModuleId, resolve::Resolver, traits::TraitItem
15 15
16}; 16};
17 17
@@ -73,18 +73,18 @@ impl CrateImplBlocks {
73 73
74 let target_ty = impl_block.target_ty(db); 74 let target_ty = impl_block.target_ty(db);
75 75
76 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
77 self.impls
78 .entry(target_ty_fp)
79 .or_insert_with(Vec::new)
80 .push((module.module_id, impl_id));
81 }
82
83 if let Some(tr) = impl_block.target_trait(db) { 76 if let Some(tr) = impl_block.target_trait(db) {
84 self.impls_by_trait 77 self.impls_by_trait
85 .entry(tr.id) 78 .entry(tr.id)
86 .or_insert_with(Vec::new) 79 .or_insert_with(Vec::new)
87 .push((module.module_id, impl_id)); 80 .push((module.module_id, impl_id));
81 } else {
82 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
83 self.impls
84 .entry(target_ty_fp)
85 .or_insert_with(Vec::new)
86 .push((module.module_id, impl_id));
87 }
88 } 88 }
89 } 89 }
90 90
@@ -120,20 +120,52 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
120} 120}
121 121
122impl Ty { 122impl Ty {
123 // FIXME: cache this as a query?
124 // - if so, what signature? (TyFingerprint, Name)?
125 // - or maybe cache all names and def_ids of methods per fingerprint?
126 /// Look up the method with the given name, returning the actual autoderefed 123 /// Look up the method with the given name, returning the actual autoderefed
127 /// receiver type (but without autoref applied yet). 124 /// receiver type (but without autoref applied yet).
128 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { 125 pub fn lookup_method(
129 self.iterate_methods(db, |ty, f| { 126 self,
127 db: &impl HirDatabase,
128 name: &Name,
129 resolver: &Resolver,
130 ) -> Option<(Ty, Function)> {
131 // FIXME: what has priority, an inherent method that needs autoderefs or a trait method?
132 let inherent_method = self.clone().iterate_methods(db, |ty, f| {
130 let sig = f.signature(db); 133 let sig = f.signature(db);
131 if sig.name() == name && sig.has_self_param() { 134 if sig.name() == name && sig.has_self_param() {
132 Some((ty.clone(), f)) 135 Some((ty.clone(), f))
133 } else { 136 } else {
134 None 137 None
135 } 138 }
136 }) 139 });
140 inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver))
141 }
142
143 fn lookup_trait_method(
144 self,
145 db: &impl HirDatabase,
146 name: &Name,
147 resolver: &Resolver,
148 ) -> Option<(Ty, Function)> {
149 let mut candidates = Vec::new();
150 for t in resolver.traits_in_scope() {
151 let data = t.trait_data(db);
152 for item in data.items() {
153 match item {
154 &TraitItem::Function(m) => {
155 let sig = m.signature(db);
156 if sig.name() == name && sig.has_self_param() {
157 candidates.push((t, m));
158 }
159 }
160 _ => {}
161 }
162 }
163 }
164 // FIXME the implements check may result in other obligations or unifying variables?
165 candidates.retain(|(_t, _m)| /* self implements t */ true);
166 // FIXME what happens if there are still multiple potential candidates?
167 let (_chosen_trait, chosen_method) = candidates.first()?;
168 Some((self.clone(), *chosen_method))
137 } 169 }
138 170
139 // This would be nicer if it just returned an iterator, but that runs into 171 // This would be nicer if it just returned an iterator, but that runs into
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 3aedba243..971043266 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1272,8 +1272,8 @@ fn test() {
1272[241; 252) 'Struct::FOO': u32 1272[241; 252) 'Struct::FOO': u32
1273[262; 263) 'y': u32 1273[262; 263) 'y': u32
1274[266; 275) 'Enum::BAR': u32 1274[266; 275) 'Enum::BAR': u32
1275[285; 286) 'z': u32 1275[285; 286) 'z': {unknown}
1276[289; 302) 'TraitTest::ID': u32"### 1276[289; 302) 'TraitTest::ID': {unknown}"###
1277 ); 1277 );
1278} 1278}
1279 1279
@@ -1918,9 +1918,9 @@ fn test() {
1918[110; 114) 'self': &{unknown} 1918[110; 114) 'self': &{unknown}
1919[170; 228) '{ ...i128 }': () 1919[170; 228) '{ ...i128 }': ()
1920[176; 178) 'S1': S1 1920[176; 178) 'S1': S1
1921[176; 187) 'S1.method()': {unknown} 1921[176; 187) 'S1.method()': u32
1922[203; 205) 'S2': S2 1922[203; 205) 'S2': S2
1923[203; 214) 'S2.method()': {unknown}"### 1923[203; 214) 'S2.method()': u32"###
1924 ); 1924 );
1925} 1925}
1926 1926
@@ -1964,10 +1964,10 @@ mod bar_test {
1964[169; 173) 'self': &{unknown} 1964[169; 173) 'self': &{unknown}
1965[300; 337) '{ ... }': () 1965[300; 337) '{ ... }': ()
1966[310; 311) 'S': S 1966[310; 311) 'S': S
1967[310; 320) 'S.method()': {unknown} 1967[310; 320) 'S.method()': u32
1968[416; 454) '{ ... }': () 1968[416; 454) '{ ... }': ()
1969[426; 427) 'S': S 1969[426; 427) 'S': S
1970[426; 436) 'S.method()': {unknown}"### 1970[426; 436) 'S.method()': i128"###
1971 ); 1971 );
1972} 1972}
1973 1973
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 54b72f8c5..47a37e4d1 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -4061,7 +4061,11 @@ impl ast::NameOwner for TraitDef {}
4061impl ast::AttrsOwner for TraitDef {} 4061impl ast::AttrsOwner for TraitDef {}
4062impl ast::DocCommentsOwner for TraitDef {} 4062impl ast::DocCommentsOwner for TraitDef {}
4063impl ast::TypeParamsOwner for TraitDef {} 4063impl ast::TypeParamsOwner for TraitDef {}
4064impl TraitDef {} 4064impl TraitDef {
4065 pub fn item_list(&self) -> Option<&ItemList> {
4066 super::child_opt(self)
4067 }
4068}
4065 4069
4066// TrueKw 4070// TrueKw
4067#[derive(Debug, PartialEq, Eq, Hash)] 4071#[derive(Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 4f8e19bd0..ad6d74162 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -292,7 +292,10 @@ Grammar(
292 ], options: [["variant_list", "EnumVariantList"]] ), 292 ], options: [["variant_list", "EnumVariantList"]] ),
293 "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), 293 "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ),
294 "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), 294 "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ),
295 "TraitDef": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"] ), 295 "TraitDef": (
296 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"],
297 options: ["ItemList"]
298 ),
296 "Module": ( 299 "Module": (
297 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ], 300 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ],
298 options: [ "ItemList" ] 301 options: [ "ItemList" ]