diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-25 21:00:16 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-25 21:00:16 +0000 |
commit | dc94f3612583c5e960b334761ad0c18d328840ea (patch) | |
tree | c79204bca4912574614eafff8f9e18775d5aa963 /crates | |
parent | bb77bc5c2f6c6b9681d9b3d0a068791db7eec0e2 (diff) | |
parent | 99711c1863fc712dc14ca61809055b283415acbe (diff) |
Merge #1040
1040: Trait beginnings r=matklad a=flodiebold
This adds some very simple trait method resolution, going through traits in scope, looking for methods of the given name, and checking very naively whether there's an impl for the given type and trait.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 7 | ||||
-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.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 95 | ||||
-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 |
12 files changed, 208 insertions, 34 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..143919cdc 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, ty::TraitRef | ||
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 | ||
@@ -98,6 +102,9 @@ pub trait HirDatabase: DefDatabase { | |||
98 | 102 | ||
99 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 103 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
100 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 104 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
105 | |||
106 | #[salsa::invoke(crate::ty::method_resolution::implements)] | ||
107 | fn implements(&self, trait_ref: TraitRef) -> bool; | ||
101 | } | 108 | } |
102 | 109 | ||
103 | #[test] | 110 | #[test] |
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..2609585b1 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 | .flatten() | ||
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.rs b/crates/ra_hir/src/ty.rs index 7d25ade47..d42c61e9d 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -14,7 +14,7 @@ pub(crate) mod display; | |||
14 | use std::sync::Arc; | 14 | use std::sync::Arc; |
15 | use std::{fmt, mem}; | 15 | use std::{fmt, mem}; |
16 | 16 | ||
17 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase}; | 17 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait}; |
18 | 18 | ||
19 | pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; | 19 | pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; |
20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; | 20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; |
@@ -91,7 +91,7 @@ pub enum TypeCtor { | |||
91 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 91 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
92 | /// type like `bool`, a struct, tuple, function pointer, reference or | 92 | /// type like `bool`, a struct, tuple, function pointer, reference or |
93 | /// several other things. | 93 | /// several other things. |
94 | #[derive(Clone, PartialEq, Eq, Debug)] | 94 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
95 | pub struct ApplicationTy { | 95 | pub struct ApplicationTy { |
96 | pub ctor: TypeCtor, | 96 | pub ctor: TypeCtor, |
97 | pub parameters: Substs, | 97 | pub parameters: Substs, |
@@ -103,7 +103,7 @@ pub struct ApplicationTy { | |||
103 | /// the same thing (but in a different way). | 103 | /// the same thing (but in a different way). |
104 | /// | 104 | /// |
105 | /// This should be cheap to clone. | 105 | /// This should be cheap to clone. |
106 | #[derive(Clone, PartialEq, Eq, Debug)] | 106 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
107 | pub enum Ty { | 107 | pub enum Ty { |
108 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 108 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
109 | /// type like `bool`, a struct, tuple, function pointer, reference or | 109 | /// type like `bool`, a struct, tuple, function pointer, reference or |
@@ -132,7 +132,7 @@ pub enum Ty { | |||
132 | } | 132 | } |
133 | 133 | ||
134 | /// A list of substitutions for generic parameters. | 134 | /// A list of substitutions for generic parameters. |
135 | #[derive(Clone, PartialEq, Eq, Debug)] | 135 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
136 | pub struct Substs(Arc<[Ty]>); | 136 | pub struct Substs(Arc<[Ty]>); |
137 | 137 | ||
138 | impl Substs { | 138 | impl Substs { |
@@ -169,6 +169,21 @@ impl Substs { | |||
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
172 | /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. | ||
173 | /// Name to be bikeshedded: TraitBound? TraitImplements? | ||
174 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
175 | pub struct TraitRef { | ||
176 | /// FIXME name? | ||
177 | trait_: Trait, | ||
178 | substs: Substs, | ||
179 | } | ||
180 | |||
181 | impl TraitRef { | ||
182 | pub fn self_ty(&self) -> &Ty { | ||
183 | &self.substs.0[0] | ||
184 | } | ||
185 | } | ||
186 | |||
172 | /// A function signature as seen by type inference: Several parameter types and | 187 | /// A function signature as seen by type inference: Several parameter types and |
173 | /// one return type. | 188 | /// one return type. |
174 | #[derive(Clone, PartialEq, Eq, Debug)] | 189 | #[derive(Clone, PartialEq, Eq, Debug)] |
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..3ac8dc46b 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -8,12 +8,12 @@ use rustc_hash::FxHashMap; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | HirDatabase, Module, Crate, Name, Function, Trait, | 10 | HirDatabase, Module, Crate, Name, Function, Trait, |
11 | ids::TraitId, | ||
12 | impl_block::{ImplId, ImplBlock, ImplItem}, | 11 | impl_block::{ImplId, ImplBlock, ImplItem}, |
13 | ty::{Ty, TypeCtor}, | 12 | ty::{Ty, TypeCtor}, |
14 | nameres::CrateModuleId, | 13 | nameres::CrateModuleId, resolve::Resolver, traits::TraitItem |
15 | 14 | ||
16 | }; | 15 | }; |
16 | use super::{ TraitRef, Substs}; | ||
17 | 17 | ||
18 | /// This is used as a key for indexing impls. | 18 | /// This is used as a key for indexing impls. |
19 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 19 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
@@ -38,7 +38,7 @@ pub struct CrateImplBlocks { | |||
38 | /// To make sense of the CrateModuleIds, we need the source root. | 38 | /// To make sense of the CrateModuleIds, we need the source root. |
39 | krate: Crate, | 39 | krate: Crate, |
40 | impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, | 40 | impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, |
41 | impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>, | 41 | impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>, |
42 | } | 42 | } |
43 | 43 | ||
44 | impl CrateImplBlocks { | 44 | impl CrateImplBlocks { |
@@ -56,8 +56,7 @@ impl CrateImplBlocks { | |||
56 | &'a self, | 56 | &'a self, |
57 | tr: &Trait, | 57 | tr: &Trait, |
58 | ) -> impl Iterator<Item = ImplBlock> + 'a { | 58 | ) -> impl Iterator<Item = ImplBlock> + 'a { |
59 | let id = tr.id; | 59 | self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( |
60 | self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map( | ||
61 | move |(module_id, impl_id)| { | 60 | move |(module_id, impl_id)| { |
62 | let module = Module { krate: self.krate, module_id: *module_id }; | 61 | let module = Module { krate: self.krate, module_id: *module_id }; |
63 | ImplBlock::from_id(module, *impl_id) | 62 | ImplBlock::from_id(module, *impl_id) |
@@ -73,18 +72,18 @@ impl CrateImplBlocks { | |||
73 | 72 | ||
74 | let target_ty = impl_block.target_ty(db); | 73 | let target_ty = impl_block.target_ty(db); |
75 | 74 | ||
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) { | 75 | if let Some(tr) = impl_block.target_trait(db) { |
84 | self.impls_by_trait | 76 | self.impls_by_trait |
85 | .entry(tr.id) | 77 | .entry(tr) |
86 | .or_insert_with(Vec::new) | 78 | .or_insert_with(Vec::new) |
87 | .push((module.module_id, impl_id)); | 79 | .push((module.module_id, impl_id)); |
80 | } else { | ||
81 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | ||
82 | self.impls | ||
83 | .entry(target_ty_fp) | ||
84 | .or_insert_with(Vec::new) | ||
85 | .push((module.module_id, impl_id)); | ||
86 | } | ||
88 | } | 87 | } |
89 | } | 88 | } |
90 | 89 | ||
@@ -109,6 +108,20 @@ impl CrateImplBlocks { | |||
109 | } | 108 | } |
110 | } | 109 | } |
111 | 110 | ||
111 | /// Rudimentary check whether an impl exists for a given type and trait; this | ||
112 | /// will actually be done by chalk. | ||
113 | pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool { | ||
114 | // FIXME use all trait impls in the whole crate graph | ||
115 | let krate = trait_ref.trait_.module(db).krate(db); | ||
116 | let krate = match krate { | ||
117 | Some(krate) => krate, | ||
118 | None => return false, | ||
119 | }; | ||
120 | let crate_impl_blocks = db.impls_in_crate(krate); | ||
121 | let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_); | ||
122 | impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty()) | ||
123 | } | ||
124 | |||
112 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | 125 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { |
113 | match ty { | 126 | match ty { |
114 | Ty::Apply(a_ty) => match a_ty.ctor { | 127 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -120,20 +133,64 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | |||
120 | } | 133 | } |
121 | 134 | ||
122 | impl Ty { | 135 | 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 | 136 | /// Look up the method with the given name, returning the actual autoderefed |
127 | /// receiver type (but without autoref applied yet). | 137 | /// receiver type (but without autoref applied yet). |
128 | pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { | 138 | pub fn lookup_method( |
129 | self.iterate_methods(db, |ty, f| { | 139 | self, |
140 | db: &impl HirDatabase, | ||
141 | name: &Name, | ||
142 | resolver: &Resolver, | ||
143 | ) -> Option<(Ty, Function)> { | ||
144 | // FIXME: trait methods should be used before autoderefs | ||
145 | let inherent_method = self.clone().iterate_methods(db, |ty, f| { | ||
130 | let sig = f.signature(db); | 146 | let sig = f.signature(db); |
131 | if sig.name() == name && sig.has_self_param() { | 147 | if sig.name() == name && sig.has_self_param() { |
132 | Some((ty.clone(), f)) | 148 | Some((ty.clone(), f)) |
133 | } else { | 149 | } else { |
134 | None | 150 | None |
135 | } | 151 | } |
136 | }) | 152 | }); |
153 | inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver)) | ||
154 | } | ||
155 | |||
156 | fn lookup_trait_method( | ||
157 | self, | ||
158 | db: &impl HirDatabase, | ||
159 | name: &Name, | ||
160 | resolver: &Resolver, | ||
161 | ) -> Option<(Ty, Function)> { | ||
162 | let mut candidates = Vec::new(); | ||
163 | for t in resolver.traits_in_scope() { | ||
164 | let data = t.trait_data(db); | ||
165 | for item in data.items() { | ||
166 | match item { | ||
167 | &TraitItem::Function(m) => { | ||
168 | let sig = m.signature(db); | ||
169 | if sig.name() == name && sig.has_self_param() { | ||
170 | candidates.push((t, m)); | ||
171 | } | ||
172 | } | ||
173 | _ => {} | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | // FIXME: | ||
178 | // - we might not actually be able to determine fully that the type | ||
179 | // implements the trait here; it's enough if we (well, Chalk) determine | ||
180 | // that it's possible. | ||
181 | // - when the trait method is picked, we need to register an | ||
182 | // 'obligation' somewhere so that we later check that it's really | ||
183 | // implemented | ||
184 | // - both points go for additional requirements from where clauses as | ||
185 | // well (in fact, the 'implements' condition could just be considered a | ||
186 | // 'where Self: Trait' clause) | ||
187 | candidates.retain(|(t, _m)| { | ||
188 | let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; | ||
189 | db.implements(trait_ref) | ||
190 | }); | ||
191 | // FIXME if there's multiple candidates here, that's an ambiguity error | ||
192 | let (_chosen_trait, chosen_method) = candidates.first()?; | ||
193 | Some((self.clone(), *chosen_method)) | ||
137 | } | 194 | } |
138 | 195 | ||
139 | // This would be nicer if it just returned an iterator, but that runs into | 196 | // 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..655f3c522 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()': i128"### |
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" ] |