aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-03-25 21:00:16 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-03-25 21:00:16 +0000
commitdc94f3612583c5e960b334761ad0c18d328840ea (patch)
treec79204bca4912574614eafff8f9e18775d5aa963 /crates/ra_hir/src/ty
parentbb77bc5c2f6c6b9681d9b3d0a068791db7eec0e2 (diff)
parent99711c1863fc712dc14ca61809055b283415acbe (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/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer.rs3
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs95
-rw-r--r--crates/ra_hir/src/ty/tests.rs12
3 files changed, 84 insertions, 26 deletions
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
9use crate::{ 9use 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};
16use 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
44impl CrateImplBlocks { 44impl 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.
113pub(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
112fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { 125fn 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
122impl Ty { 135impl 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