aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/autoderef.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/autoderef.rs')
-rw-r--r--crates/hir_ty/src/autoderef.rs64
1 files changed, 52 insertions, 12 deletions
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index 7ca4af80e..71bc436e6 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -6,14 +6,15 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::cast::Cast; 9use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
10use hir_def::lang_item::LangItemTarget; 10use hir_def::lang_item::LangItemTarget;
11use hir_expand::name::name; 11use hir_expand::name::name;
12use log::{info, warn}; 12use log::{info, warn};
13 13
14use crate::{ 14use crate::{
15 db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, 15 db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
16 InEnvironment, Interner, Solution, Ty, TyBuilder, TyKind, 16 DebruijnIndex, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution, Ty, TyBuilder,
17 TyKind,
17}; 18};
18 19
19const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -35,13 +36,21 @@ pub(crate) fn deref(
35 krate: CrateId, 36 krate: CrateId,
36 ty: InEnvironment<&Canonical<Ty>>, 37 ty: InEnvironment<&Canonical<Ty>>,
37) -> Option<Canonical<Ty>> { 38) -> Option<Canonical<Ty>> {
38 if let Some(derefed) = ty.goal.value.builtin_deref() { 39 if let Some(derefed) = builtin_deref(&ty.goal.value) {
39 Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) 40 Some(Canonical { value: derefed, binders: ty.goal.binders.clone() })
40 } else { 41 } else {
41 deref_by_trait(db, krate, ty) 42 deref_by_trait(db, krate, ty)
42 } 43 }
43} 44}
44 45
46fn builtin_deref(ty: &Ty) -> Option<Ty> {
47 match ty.kind(&Interner) {
48 TyKind::Ref(.., ty) => Some(ty.clone()),
49 TyKind::Raw(.., ty) => Some(ty.clone()),
50 _ => None,
51 }
52}
53
45fn deref_by_trait( 54fn deref_by_trait(
46 db: &dyn HirDatabase, 55 db: &dyn HirDatabase,
47 krate: CrateId, 56 krate: CrateId,
@@ -95,7 +104,7 @@ fn deref_by_trait(
95 binders: CanonicalVarKinds::from_iter( 104 binders: CanonicalVarKinds::from_iter(
96 &Interner, 105 &Interner,
97 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new( 106 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
98 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), 107 VariableKind::Ty(chalk_ir::TyVariableKind::General),
99 chalk_ir::UniverseIndex::ROOT, 108 chalk_ir::UniverseIndex::ROOT,
100 ))), 109 ))),
101 ), 110 ),
@@ -120,23 +129,25 @@ fn deref_by_trait(
120 // assumptions will be broken. We would need to properly introduce 129 // assumptions will be broken. We would need to properly introduce
121 // new variables in that case 130 // new variables in that case
122 131
123 for i in 1..vars.0.binders.len(&Interner) { 132 for i in 1..vars.binders.len(&Interner) {
124 if vars.0.value.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner) 133 if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
125 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 134 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
126 { 135 {
127 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution); 136 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
128 return None; 137 return None;
129 } 138 }
130 } 139 }
131 Some(Canonical { 140 // FIXME: we remove lifetime variables here since they can confuse
141 // the method resolution code later
142 Some(fixup_lifetime_variables(Canonical {
132 value: vars 143 value: vars
133 .0
134 .value 144 .value
135 .at(&Interner, vars.0.value.len(&Interner) - 1) 145 .subst
146 .at(&Interner, vars.value.subst.len(&Interner) - 1)
136 .assert_ty_ref(&Interner) 147 .assert_ty_ref(&Interner)
137 .clone(), 148 .clone(),
138 binders: vars.0.binders.clone(), 149 binders: vars.binders.clone(),
139 }) 150 }))
140 } 151 }
141 Solution::Ambig(_) => { 152 Solution::Ambig(_) => {
142 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); 153 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
@@ -144,3 +155,32 @@ fn deref_by_trait(
144 } 155 }
145 } 156 }
146} 157}
158
159fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
160 c: Canonical<T>,
161) -> Canonical<T> {
162 // Removes lifetime variables from the Canonical, replacing them by static lifetimes.
163 let mut i = 0;
164 let subst = Substitution::from_iter(
165 &Interner,
166 c.binders.iter(&Interner).map(|vk| match vk.kind {
167 VariableKind::Ty(_) => {
168 let index = i;
169 i += 1;
170 BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner)
171 }
172 VariableKind::Lifetime => static_lifetime().cast(&Interner),
173 VariableKind::Const(_) => unimplemented!(),
174 }),
175 );
176 let binders = CanonicalVarKinds::from_iter(
177 &Interner,
178 c.binders.iter(&Interner).filter(|vk| match vk.kind {
179 VariableKind::Ty(_) => true,
180 VariableKind::Lifetime => false,
181 VariableKind::Const(_) => true,
182 }),
183 );
184 let value = subst.apply(c.value, &Interner);
185 Canonical { binders, value }
186}