aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/source_binder.rs11
-rw-r--r--crates/ra_hir/src/ty.rs11
-rw-r--r--crates/ra_hir/src/ty/infer.rs13
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs24
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs219
-rw-r--r--crates/ra_hir/src/ty/traits.rs7
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs13
7 files changed, 165 insertions, 133 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 2959e3eca..24350bda7 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -350,7 +350,16 @@ impl SourceAnalyzer {
350 name: Option<&Name>, 350 name: Option<&Name>,
351 callback: impl FnMut(&Ty, Function) -> Option<T>, 351 callback: impl FnMut(&Ty, Function) -> Option<T>,
352 ) -> Option<T> { 352 ) -> Option<T> {
353 ty.iterate_method_candidates(db, &self.resolver, name, callback) 353 // There should be no inference vars in types passed here
354 // TODO check that?
355 let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
356 crate::ty::method_resolution::iterate_method_candidates(
357 &canonical,
358 db,
359 &self.resolver,
360 name,
361 callback,
362 )
354 } 363 }
355 364
356 #[cfg(test)] 365 #[cfg(test)]
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index e7c39487d..6a79af35b 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -234,6 +234,17 @@ impl TraitRef {
234 } 234 }
235} 235}
236 236
237/// Basically a claim (currently not validated / checked) that the contained
238/// type / trait ref contains no inference variables; any inference variables it
239/// contained have been replaced by bound variables, and `num_vars` tells us how
240/// many there are. This is used to erase irrelevant differences between types
241/// before using them in queries.
242#[derive(Debug, Clone, PartialEq, Eq, Hash)]
243pub(crate) struct Canonical<T> {
244 pub value: T,
245 pub num_vars: usize,
246}
247
237/// A function signature as seen by type inference: Several parameter types and 248/// A function signature as seen by type inference: Several parameter types and
238/// one return type. 249/// one return type.
239#[derive(Clone, PartialEq, Eq, Debug)] 250#[derive(Clone, PartialEq, Eq, Debug)]
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index a6d08dbcb..41ae569f7 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -45,12 +45,11 @@ use crate::{
45use super::{ 45use super::{
46 Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, 46 Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef,
47 traits::{Solution, Obligation, Guidance}, 47 traits::{Solution, Obligation, Guidance},
48 method_resolution,
48}; 49};
49 50
50mod unify; 51mod unify;
51 52
52pub(super) use unify::Canonical;
53
54/// The entry point of type inference. 53/// The entry point of type inference.
55pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { 54pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> {
56 db.check_canceled(); 55 db.check_canceled();
@@ -878,9 +877,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
878 generic_args: Option<&GenericArgs>, 877 generic_args: Option<&GenericArgs>,
879 ) -> Ty { 878 ) -> Ty {
880 let receiver_ty = self.infer_expr(receiver, &Expectation::none()); 879 let receiver_ty = self.infer_expr(receiver, &Expectation::none());
881 let resolved = receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); 880 let mut canonicalizer = self.canonicalizer();
881 let canonical_receiver = canonicalizer.canonicalize_ty(receiver_ty.clone());
882 let resolved = method_resolution::lookup_method(
883 &canonical_receiver,
884 canonicalizer.ctx.db,
885 method_name,
886 &canonicalizer.ctx.resolver,
887 );
882 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 888 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
883 Some((ty, func)) => { 889 Some((ty, func)) => {
890 let ty = canonicalizer.decanonicalize_ty(ty);
884 self.write_method_resolution(tgt_expr, func); 891 self.write_method_resolution(tgt_expr, func);
885 ( 892 (
886 ty, 893 ty,
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index 5edb95c31..820a64789 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -1,6 +1,8 @@
1//! Unification and canonicalization logic. 1//! Unification and canonicalization logic.
2 2
3use super::{InferenceContext, Ty, TraitRef, InferTy, HirDatabase}; 3use crate::db::HirDatabase;
4use crate::ty::{Ty, Canonical, TraitRef, InferTy};
5use super::InferenceContext;
4 6
5impl<'a, D: HirDatabase> InferenceContext<'a, D> { 7impl<'a, D: HirDatabase> InferenceContext<'a, D> {
6 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> 8 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
@@ -13,13 +15,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
13 15
14// TODO improve the interface of this 16// TODO improve the interface of this
15 17
16// TODO move further up?
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub(crate) struct Canonical<T> {
19 pub value: T,
20 pub num_vars: usize,
21}
22
23pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase> 18pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase>
24where 19where
25 'a: 'b, 20 'a: 'b,
@@ -68,6 +63,19 @@ where
68 Canonical { value, num_vars: self.free_vars.len() } 63 Canonical { value, num_vars: self.free_vars.len() }
69 } 64 }
70 65
66 pub fn decanonicalize_ty(&self, ty: Ty) -> Ty {
67 ty.fold(&mut |ty| match ty {
68 Ty::Bound(idx) => {
69 if (idx as usize) < self.free_vars.len() {
70 Ty::Infer(self.free_vars[idx as usize].clone())
71 } else {
72 Ty::Bound(idx)
73 }
74 }
75 ty => ty,
76 })
77 }
78
71 pub fn apply_solution(&mut self, solution: Canonical<Vec<Ty>>) { 79 pub fn apply_solution(&mut self, solution: Canonical<Vec<Ty>>) {
72 // the solution may contain new variables, which we need to convert to new inference vars 80 // the solution may contain new variables, which we need to convert to new inference vars
73 let new_vars = 81 let new_vars =
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index ea7da0b62..bc5033be6 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -16,7 +16,7 @@ use crate::{
16 generics::HasGenericParams, 16 generics::HasGenericParams,
17 ty::primitive::{UncertainIntTy, UncertainFloatTy} 17 ty::primitive::{UncertainIntTy, UncertainFloatTy}
18}; 18};
19use super::{TraitRef, infer::Canonical, Substs}; 19use super::{TraitRef, Canonical};
20 20
21/// This is used as a key for indexing impls. 21/// This is used as a key for indexing impls.
22#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 22#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -130,132 +130,123 @@ fn def_crate(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<Crate>
130 } 130 }
131} 131}
132 132
133impl Ty { 133/// Look up the method with the given name, returning the actual autoderefed
134 /// Look up the method with the given name, returning the actual autoderefed 134/// receiver type (but without autoref applied yet).
135 /// receiver type (but without autoref applied yet). 135pub(crate) fn lookup_method(
136 pub(crate) fn lookup_method( 136 ty: &Canonical<Ty>,
137 self, 137 db: &impl HirDatabase,
138 db: &impl HirDatabase, 138 name: &Name,
139 name: &Name, 139 resolver: &Resolver,
140 resolver: &Resolver, 140) -> Option<(Ty, Function)> {
141 ) -> Option<(Ty, Function)> { 141 iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f)))
142 self.iterate_method_candidates(db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) 142}
143 }
144 143
145 // This would be nicer if it just returned an iterator, but that runs into 144// This would be nicer if it just returned an iterator, but that runs into
146 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 145// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
147 pub(crate) fn iterate_method_candidates<T>( 146pub(crate) fn iterate_method_candidates<T>(
148 self, 147 ty: &Canonical<Ty>,
149 db: &impl HirDatabase, 148 db: &impl HirDatabase,
150 resolver: &Resolver, 149 resolver: &Resolver,
151 name: Option<&Name>, 150 name: Option<&Name>,
152 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 151 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
153 ) -> Option<T> { 152) -> Option<T> {
154 // For method calls, rust first does any number of autoderef, and then one 153 // For method calls, rust first does any number of autoderef, and then one
155 // autoref (i.e. when the method takes &self or &mut self). We just ignore 154 // autoref (i.e. when the method takes &self or &mut self). We just ignore
156 // the autoref currently -- when we find a method matching the given name, 155 // the autoref currently -- when we find a method matching the given name,
157 // we assume it fits. 156 // we assume it fits.
158 157
159 // Also note that when we've got a receiver like &S, even if the method we 158 // Also note that when we've got a receiver like &S, even if the method we
160 // find in the end takes &self, we still do the autoderef step (just as 159 // find in the end takes &self, we still do the autoderef step (just as
161 // rustc does an autoderef and then autoref again). 160 // rustc does an autoderef and then autoref again).
162 161
163 let krate = resolver.krate()?; 162 let krate = resolver.krate()?;
164 for derefed_ty in self.autoderef(db) { 163 for derefed_ty in ty.value.clone().autoderef(db) {
165 if let Some(result) = 164 let derefed_ty = Canonical { value: derefed_ty, num_vars: ty.num_vars };
166 derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback) 165 if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback)
167 { 166 {
168 return Some(result); 167 return Some(result);
169 } 168 }
170 if let Some(result) = 169 if let Some(result) =
171 derefed_ty.iterate_trait_method_candidates(db, resolver, name, &mut callback) 170 iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback)
172 { 171 {
173 return Some(result); 172 return Some(result);
174 }
175 } 173 }
176 None
177 } 174 }
175 None
176}
178 177
179 fn iterate_trait_method_candidates<T>( 178fn iterate_trait_method_candidates<T>(
180 &self, 179 ty: &Canonical<Ty>,
181 db: &impl HirDatabase, 180 db: &impl HirDatabase,
182 resolver: &Resolver, 181 resolver: &Resolver,
183 name: Option<&Name>, 182 name: Option<&Name>,
184 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 183 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
185 ) -> Option<T> { 184) -> Option<T> {
186 let krate = resolver.krate()?; 185 let krate = resolver.krate()?;
187 'traits: for t in resolver.traits_in_scope() { 186 'traits: for t in resolver.traits_in_scope() {
188 let data = t.trait_data(db); 187 let data = t.trait_data(db);
189 // we'll be lazy about checking whether the type implements the 188 // we'll be lazy about checking whether the type implements the
190 // trait, but if we find out it doesn't, we'll skip the rest of the 189 // trait, but if we find out it doesn't, we'll skip the rest of the
191 // iteration 190 // iteration
192 let mut known_implemented = false; 191 let mut known_implemented = false;
193 for item in data.items() { 192 for item in data.items() {
194 match item { 193 match item {
195 &TraitItem::Function(m) => { 194 &TraitItem::Function(m) => {
196 let sig = m.signature(db); 195 let sig = m.signature(db);
197 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
198 if !known_implemented { 197 if !known_implemented {
199 // TODO the self type may contain type 198 let trait_ref = canonical_trait_ref(db, t, ty.clone());
200 // variables, so we need to do proper 199 // FIXME cache this implements check (without solution) in a query?
201 // canonicalization here 200 if super::traits::implements(db, krate, trait_ref).is_none() {
202 let trait_ref = TraitRef { 201 continue 'traits;
203 trait_: t,
204 substs: fresh_substs_for_trait(db, t, self.clone()),
205 };
206 let canonical = Canonical {
207 num_vars: trait_ref.substs.len(),
208 value: trait_ref,
209 };
210 // FIXME cache this implements check (without solution) in a query?
211 if super::traits::implements(db, krate, canonical).is_none() {
212 continue 'traits;
213 }
214 }
215 known_implemented = true;
216 if let Some(result) = callback(self, m) {
217 return Some(result);
218 } 202 }
219 } 203 }
204 known_implemented = true;
205 // TODO the self type is now canonicalized...
206 if let Some(result) = callback(&ty.value, m) {
207 return Some(result);
208 }
220 } 209 }
221 _ => {}
222 } 210 }
211 _ => {}
223 } 212 }
224 } 213 }
225 None
226 } 214 }
215 None
216}
227 217
228 fn iterate_inherent_methods<T>( 218fn iterate_inherent_methods<T>(
229 &self, 219 ty: &Canonical<Ty>,
230 db: &impl HirDatabase, 220 db: &impl HirDatabase,
231 name: Option<&Name>, 221 name: Option<&Name>,
232 krate: Crate, 222 krate: Crate,
233 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 223 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
234 ) -> Option<T> { 224) -> Option<T> {
235 let krate = match def_crate(db, krate, self) { 225 let krate = match def_crate(db, krate, &ty.value) {
236 Some(krate) => krate, 226 Some(krate) => krate,
237 None => return None, 227 None => return None,
238 }; 228 };
239 let impls = db.impls_in_crate(krate); 229 let impls = db.impls_in_crate(krate);
240 230
241 for impl_block in impls.lookup_impl_blocks(self) { 231 for impl_block in impls.lookup_impl_blocks(&ty.value) {
242 for item in impl_block.items(db) { 232 for item in impl_block.items(db) {
243 match item { 233 match item {
244 ImplItem::Method(f) => { 234 ImplItem::Method(f) => {
245 let sig = f.signature(db); 235 let sig = f.signature(db);
246 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 236 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
247 if let Some(result) = callback(self, f) { 237 if let Some(result) = callback(&ty.value, f) {
248 return Some(result); 238 return Some(result);
249 }
250 } 239 }
251 } 240 }
252 _ => {}
253 } 241 }
242 _ => {}
254 } 243 }
255 } 244 }
256 None
257 } 245 }
246 None
247}
258 248
249impl Ty {
259 // This would be nicer if it just returned an iterator, but that runs into 250 // This would be nicer if it just returned an iterator, but that runs into
260 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 251 // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
261 pub fn iterate_impl_items<T>( 252 pub fn iterate_impl_items<T>(
@@ -280,17 +271,25 @@ impl Ty {
280 271
281/// This creates Substs for a trait with the given Self type and type variables 272/// This creates Substs for a trait with the given Self type and type variables
282/// for all other parameters, to query Chalk with it. 273/// for all other parameters, to query Chalk with it.
283fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs { 274fn canonical_trait_ref(
275 db: &impl HirDatabase,
276 trait_: Trait,
277 self_ty: Canonical<Ty>,
278) -> Canonical<TraitRef> {
284 let mut substs = Vec::new(); 279 let mut substs = Vec::new();
285 let generics = tr.generic_params(db); 280 let generics = trait_.generic_params(db);
286 substs.push(self_ty); 281 let num_vars = self_ty.num_vars;
282 substs.push(self_ty.value);
287 substs.extend( 283 substs.extend(
288 generics 284 generics
289 .params_including_parent() 285 .params_including_parent()
290 .into_iter() 286 .into_iter()
291 .skip(1) 287 .skip(1)
292 .enumerate() 288 .enumerate()
293 .map(|(i, _p)| Ty::Bound(i as u32)), 289 .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
294 ); 290 );
295 substs.into() 291 Canonical {
292 num_vars: substs.len() - 1 + self_ty.num_vars,
293 value: TraitRef { trait_, substs: substs.into() },
294 }
296} 295}
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index ac31ca2f6..c707110ad 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex};
4use chalk_ir::cast::Cast; 4use chalk_ir::cast::Cast;
5 5
6use crate::{Crate, Trait, db::HirDatabase, ImplBlock}; 6use crate::{Crate, Trait, db::HirDatabase, ImplBlock};
7use super::{TraitRef, Ty, infer::Canonical}; 7use super::{TraitRef, Ty, Canonical};
8 8
9use self::chalk::{ToChalk, from_chalk}; 9use self::chalk::{ToChalk, from_chalk};
10 10
@@ -86,10 +86,7 @@ pub(crate) fn implements(
86 solution.map(|solution| solution_from_chalk(db, solution)) 86 solution.map(|solution| solution_from_chalk(db, solution))
87} 87}
88 88
89fn solution_from_chalk( 89fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution {
90 db: &impl HirDatabase,
91 solution: chalk_solve::Solution,
92) -> Solution {
93 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| { 90 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| {
94 let value = subst 91 let value = subst
95 .value 92 .value
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 36cc52704..18f301789 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -32,8 +32,7 @@ impl ToChalk for Ty {
32 match self { 32 match self {
33 Ty::Apply(apply_ty) => chalk_ir::Ty::Apply(apply_ty.to_chalk(db)), 33 Ty::Apply(apply_ty) => chalk_ir::Ty::Apply(apply_ty.to_chalk(db)),
34 Ty::Param { idx, .. } => { 34 Ty::Param { idx, .. } => {
35 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize } 35 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
36 .to_ty()
37 } 36 }
38 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), 37 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
39 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 38 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
@@ -74,9 +73,7 @@ impl ToChalk for ApplicationTy {
74 73
75 fn from_chalk(db: &impl HirDatabase, apply_ty: chalk_ir::ApplicationTy) -> ApplicationTy { 74 fn from_chalk(db: &impl HirDatabase, apply_ty: chalk_ir::ApplicationTy) -> ApplicationTy {
76 let ctor = match apply_ty.name { 75 let ctor = match apply_ty.name {
77 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { 76 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => from_chalk(db, struct_id),
78 from_chalk(db, struct_id)
79 }
80 TypeName::TypeKindId(_) => unimplemented!(), 77 TypeName::TypeKindId(_) => unimplemented!(),
81 TypeName::Placeholder(_) => unimplemented!(), 78 TypeName::Placeholder(_) => unimplemented!(),
82 TypeName::AssociatedType(_) => unimplemented!(), 79 TypeName::AssociatedType(_) => unimplemented!(),
@@ -267,7 +264,11 @@ where
267 .map(|impl_block| impl_block.to_chalk(self.db)) 264 .map(|impl_block| impl_block.to_chalk(self.db))
268 .collect() 265 .collect()
269 } 266 }
270 fn impl_provided_for(&self, auto_trait_id: chalk_ir::TraitId, struct_id: chalk_ir::StructId) -> bool { 267 fn impl_provided_for(
268 &self,
269 auto_trait_id: chalk_ir::TraitId,
270 struct_id: chalk_ir::StructId,
271 ) -> bool {
271 eprintln!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); 272 eprintln!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
272 false // FIXME 273 false // FIXME
273 } 274 }