diff options
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/traits.rs | 52 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 60 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 12 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 6 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 5 |
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 | ||
654 | impl Docs for Trait { | 667 | impl 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; | |||
27 | mod name; | 27 | mod name; |
28 | mod nameres; | 28 | mod nameres; |
29 | mod adt; | 29 | mod adt; |
30 | mod traits; | ||
30 | mod type_alias; | 31 | mod type_alias; |
31 | mod type_ref; | 32 | mod type_ref; |
32 | mod ty; | 33 | mod 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 | ||
63 | use crate::{ | 63 | use 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 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use ra_syntax::ast::{self, NameOwner}; | ||
6 | |||
7 | use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName}; | ||
8 | |||
9 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
10 | pub struct TraitData { | ||
11 | name: Option<Name>, | ||
12 | items: Vec<TraitItem>, | ||
13 | } | ||
14 | |||
15 | impl 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)] | ||
46 | pub enum TraitItem { | ||
47 | Function(Function), | ||
48 | Const(Const), | ||
49 | TypeAlias(TypeAlias), | ||
50 | // Existential | ||
51 | } | ||
52 | impl_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 | ||
122 | impl Ty { | 122 | impl 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 {} | |||
4061 | impl ast::AttrsOwner for TraitDef {} | 4061 | impl ast::AttrsOwner for TraitDef {} |
4062 | impl ast::DocCommentsOwner for TraitDef {} | 4062 | impl ast::DocCommentsOwner for TraitDef {} |
4063 | impl ast::TypeParamsOwner for TraitDef {} | 4063 | impl ast::TypeParamsOwner for TraitDef {} |
4064 | impl TraitDef {} | 4064 | impl 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" ] |