diff options
Diffstat (limited to 'crates/ra_hir/src')
-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 |
10 files changed, 199 insertions, 32 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 | ||