diff options
Diffstat (limited to 'crates/hir_ty/src/autoderef.rs')
-rw-r--r-- | crates/hir_ty/src/autoderef.rs | 63 |
1 files changed, 33 insertions, 30 deletions
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs index dc5fc759a..f8e9db9ae 100644 --- a/crates/hir_ty/src/autoderef.rs +++ b/crates/hir_ty/src/autoderef.rs | |||
@@ -12,12 +12,8 @@ use hir_expand::name::name; | |||
12 | use log::{info, warn}; | 12 | use log::{info, warn}; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | db::HirDatabase, | 15 | db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, |
16 | to_assoc_type_id, to_chalk_trait_id, | 16 | InEnvironment, Interner, ProjectionTyExt, Solution, Ty, TyBuilder, TyKind, |
17 | traits::{InEnvironment, Solution}, | ||
18 | utils::generics, | ||
19 | AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner, | ||
20 | ProjectionTy, Substitution, TraitRef, Ty, TyKind, | ||
21 | }; | 17 | }; |
22 | 18 | ||
23 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 19 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
@@ -39,13 +35,21 @@ pub(crate) fn deref( | |||
39 | krate: CrateId, | 35 | krate: CrateId, |
40 | ty: InEnvironment<&Canonical<Ty>>, | 36 | ty: InEnvironment<&Canonical<Ty>>, |
41 | ) -> Option<Canonical<Ty>> { | 37 | ) -> Option<Canonical<Ty>> { |
42 | if let Some(derefed) = ty.goal.value.builtin_deref() { | 38 | if let Some(derefed) = builtin_deref(&ty.goal.value) { |
43 | Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) | 39 | Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) |
44 | } else { | 40 | } else { |
45 | deref_by_trait(db, krate, ty) | 41 | deref_by_trait(db, krate, ty) |
46 | } | 42 | } |
47 | } | 43 | } |
48 | 44 | ||
45 | fn builtin_deref(ty: &Ty) -> Option<Ty> { | ||
46 | match ty.kind(&Interner) { | ||
47 | TyKind::Ref(.., ty) => Some(ty.clone()), | ||
48 | TyKind::Raw(.., ty) => Some(ty.clone()), | ||
49 | _ => None, | ||
50 | } | ||
51 | } | ||
52 | |||
49 | fn deref_by_trait( | 53 | fn deref_by_trait( |
50 | db: &dyn HirDatabase, | 54 | db: &dyn HirDatabase, |
51 | krate: CrateId, | 55 | krate: CrateId, |
@@ -57,21 +61,20 @@ fn deref_by_trait( | |||
57 | }; | 61 | }; |
58 | let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; | 62 | let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; |
59 | 63 | ||
60 | let generic_params = generics(db.upcast(), target.into()); | 64 | let projection = { |
61 | if generic_params.len() != 1 { | 65 | let b = TyBuilder::assoc_type_projection(db, target); |
62 | // the Target type + Deref trait should only have one generic parameter, | 66 | if b.remaining() != 1 { |
63 | // namely Deref's Self type | 67 | // the Target type + Deref trait should only have one generic parameter, |
64 | return None; | 68 | // namely Deref's Self type |
65 | } | 69 | return None; |
70 | } | ||
71 | b.push(ty.goal.value.clone()).build() | ||
72 | }; | ||
66 | 73 | ||
67 | // FIXME make the Canonical / bound var handling nicer | 74 | // FIXME make the Canonical / bound var handling nicer |
68 | 75 | ||
69 | let parameters = | ||
70 | Substitution::build_for_generics(&generic_params).push(ty.goal.value.clone()).build(); | ||
71 | |||
72 | // Check that the type implements Deref at all | 76 | // Check that the type implements Deref at all |
73 | let trait_ref = | 77 | let trait_ref = projection.trait_ref(db); |
74 | TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() }; | ||
75 | let implements_goal = Canonical { | 78 | let implements_goal = Canonical { |
76 | binders: ty.goal.binders.clone(), | 79 | binders: ty.goal.binders.clone(), |
77 | value: InEnvironment { | 80 | value: InEnvironment { |
@@ -84,11 +87,8 @@ fn deref_by_trait( | |||
84 | } | 87 | } |
85 | 88 | ||
86 | // Now do the assoc type projection | 89 | // Now do the assoc type projection |
87 | let projection = AliasEq { | 90 | let alias_eq = AliasEq { |
88 | alias: AliasTy::Projection(ProjectionTy { | 91 | alias: AliasTy::Projection(projection), |
89 | associated_ty_id: to_assoc_type_id(target), | ||
90 | substitution: parameters, | ||
91 | }), | ||
92 | ty: TyKind::BoundVar(BoundVar::new( | 92 | ty: TyKind::BoundVar(BoundVar::new( |
93 | DebruijnIndex::INNERMOST, | 93 | DebruijnIndex::INNERMOST, |
94 | ty.goal.binders.len(&Interner), | 94 | ty.goal.binders.len(&Interner), |
@@ -96,9 +96,7 @@ fn deref_by_trait( | |||
96 | .intern(&Interner), | 96 | .intern(&Interner), |
97 | }; | 97 | }; |
98 | 98 | ||
99 | let obligation = projection.cast(&Interner); | 99 | let in_env = InEnvironment { goal: alias_eq.cast(&Interner), environment: ty.environment }; |
100 | |||
101 | let in_env = InEnvironment { goal: obligation, environment: ty.environment }; | ||
102 | 100 | ||
103 | let canonical = Canonical { | 101 | let canonical = Canonical { |
104 | value: in_env, | 102 | value: in_env, |
@@ -130,8 +128,8 @@ fn deref_by_trait( | |||
130 | // assumptions will be broken. We would need to properly introduce | 128 | // assumptions will be broken. We would need to properly introduce |
131 | // new variables in that case | 129 | // new variables in that case |
132 | 130 | ||
133 | for i in 1..vars.0.binders.len(&Interner) { | 131 | for i in 1..vars.binders.len(&Interner) { |
134 | if vars.0.value[i - 1].interned(&Interner) | 132 | if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner) |
135 | != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) | 133 | != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) |
136 | { | 134 | { |
137 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution); | 135 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution); |
@@ -139,8 +137,13 @@ fn deref_by_trait( | |||
139 | } | 137 | } |
140 | } | 138 | } |
141 | Some(Canonical { | 139 | Some(Canonical { |
142 | value: vars.0.value[vars.0.value.len() - 1].clone(), | 140 | value: vars |
143 | binders: vars.0.binders.clone(), | 141 | .value |
142 | .subst | ||
143 | .at(&Interner, vars.value.subst.len(&Interner) - 1) | ||
144 | .assert_ty_ref(&Interner) | ||
145 | .clone(), | ||
146 | binders: vars.binders.clone(), | ||
144 | }) | 147 | }) |
145 | } | 148 | } |
146 | Solution::Ambig(_) => { | 149 | Solution::Ambig(_) => { |