aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/autoderef.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/autoderef.rs')
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs52
1 files changed, 29 insertions, 23 deletions
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 5d8518041..44547197c 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -5,48 +5,56 @@
5 5
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::resolver::Resolver; 8use hir_def::lang_item::LangItemTarget;
9use hir_expand::name; 9use hir_expand::name;
10use log::{info, warn}; 10use log::{info, warn};
11use ra_db::CrateId;
11 12
12use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; 13use crate::{db::HirDatabase, Trait};
13use crate::{db::HirDatabase, generics::HasGenericParams}; 14
15use super::{
16 traits::{InEnvironment, Solution},
17 Canonical, Substs, Ty, TypeWalk,
18};
14 19
15const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const AUTODEREF_RECURSION_LIMIT: usize = 10;
16 21
17pub(crate) fn autoderef<'a>( 22pub(crate) fn autoderef<'a>(
18 db: &'a impl HirDatabase, 23 db: &'a impl HirDatabase,
19 resolver: &'a Resolver, 24 krate: Option<CrateId>,
20 ty: Canonical<Ty>, 25 ty: InEnvironment<Canonical<Ty>>,
21) -> impl Iterator<Item = Canonical<Ty>> + 'a { 26) -> impl Iterator<Item = Canonical<Ty>> + 'a {
22 successors(Some(ty), move |ty| deref(db, resolver, ty)).take(AUTODEREF_RECURSION_LIMIT) 27 let InEnvironment { value: ty, environment } = ty;
28 successors(Some(ty), move |ty| {
29 deref(db, krate?, InEnvironment { value: ty, environment: environment.clone() })
30 })
31 .take(AUTODEREF_RECURSION_LIMIT)
23} 32}
24 33
25pub(crate) fn deref( 34pub(crate) fn deref(
26 db: &impl HirDatabase, 35 db: &impl HirDatabase,
27 resolver: &Resolver, 36 krate: CrateId,
28 ty: &Canonical<Ty>, 37 ty: InEnvironment<&Canonical<Ty>>,
29) -> Option<Canonical<Ty>> { 38) -> Option<Canonical<Ty>> {
30 if let Some(derefed) = ty.value.builtin_deref() { 39 if let Some(derefed) = ty.value.value.builtin_deref() {
31 Some(Canonical { value: derefed, num_vars: ty.num_vars }) 40 Some(Canonical { value: derefed, num_vars: ty.value.num_vars })
32 } else { 41 } else {
33 deref_by_trait(db, resolver, ty) 42 deref_by_trait(db, krate, ty)
34 } 43 }
35} 44}
36 45
37fn deref_by_trait( 46fn deref_by_trait(
38 db: &impl HirDatabase, 47 db: &impl HirDatabase,
39 resolver: &Resolver, 48 krate: CrateId,
40 ty: &Canonical<Ty>, 49 ty: InEnvironment<&Canonical<Ty>>,
41) -> Option<Canonical<Ty>> { 50) -> Option<Canonical<Ty>> {
42 let krate = resolver.krate()?;
43 let deref_trait = match db.lang_item(krate.into(), "deref".into())? { 51 let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
44 crate::lang_item::LangItemTarget::Trait(t) => t, 52 LangItemTarget::TraitId(t) => Trait::from(t),
45 _ => return None, 53 _ => return None,
46 }; 54 };
47 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; 55 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
48 56
49 let generic_params = target.generic_params(db); 57 let generic_params = db.generic_params(target.id.into());
50 if generic_params.count_params_including_parent() != 1 { 58 if generic_params.count_params_including_parent() != 1 {
51 // the Target type + Deref trait should only have one generic parameter, 59 // the Target type + Deref trait should only have one generic parameter,
52 // namely Deref's Self type 60 // namely Deref's Self type
@@ -55,10 +63,8 @@ fn deref_by_trait(
55 63
56 // FIXME make the Canonical handling nicer 64 // FIXME make the Canonical handling nicer
57 65
58 let env = super::lower::trait_env(db, resolver);
59
60 let parameters = Substs::build_for_generics(&generic_params) 66 let parameters = Substs::build_for_generics(&generic_params)
61 .push(ty.value.clone().shift_bound_vars(1)) 67 .push(ty.value.value.clone().shift_bound_vars(1))
62 .build(); 68 .build();
63 69
64 let projection = super::traits::ProjectionPredicate { 70 let projection = super::traits::ProjectionPredicate {
@@ -68,9 +74,9 @@ fn deref_by_trait(
68 74
69 let obligation = super::Obligation::Projection(projection); 75 let obligation = super::Obligation::Projection(projection);
70 76
71 let in_env = super::traits::InEnvironment { value: obligation, environment: env }; 77 let in_env = InEnvironment { value: obligation, environment: ty.environment };
72 78
73 let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: in_env }; 79 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env };
74 80
75 let solution = db.trait_solve(krate.into(), canonical)?; 81 let solution = db.trait_solve(krate.into(), canonical)?;
76 82
@@ -88,14 +94,14 @@ fn deref_by_trait(
88 // the case. 94 // the case.
89 for i in 1..vars.0.num_vars { 95 for i in 1..vars.0.num_vars {
90 if vars.0.value[i] != Ty::Bound((i - 1) as u32) { 96 if vars.0.value[i] != Ty::Bound((i - 1) as u32) {
91 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty, solution); 97 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
92 return None; 98 return None;
93 } 99 }
94 } 100 }
95 Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) 101 Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars })
96 } 102 }
97 Solution::Ambig(_) => { 103 Solution::Ambig(_) => {
98 info!("Ambiguous solution for derefing {:?}: {:?}", ty, solution); 104 info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution);
99 None 105 None
100 } 106 }
101 } 107 }