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.rs63
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;
12use log::{info, warn}; 12use log::{info, warn};
13 13
14use crate::{ 14use 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
23const AUTODEREF_RECURSION_LIMIT: usize = 10; 19const 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
45fn 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
49fn deref_by_trait( 53fn 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(_) => {