aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer.rs52
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs122
-rw-r--r--crates/ra_hir/src/ty/lower.rs37
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs223
-rw-r--r--crates/ra_hir/src/ty/tests.rs2
-rw-r--r--crates/ra_hir/src/ty/traits.rs223
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs333
7 files changed, 755 insertions, 237 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index c7772a7f6..edce1afe7 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -44,9 +44,12 @@ use crate::{
44}; 44};
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
51mod unify;
52
50/// The entry point of type inference. 53/// The entry point of type inference.
51pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { 54pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> {
52 db.check_canceled(); 55 db.check_canceled();
@@ -321,30 +324,29 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
321 fn resolve_obligations_as_possible(&mut self) { 324 fn resolve_obligations_as_possible(&mut self) {
322 let obligations = mem::replace(&mut self.obligations, Vec::new()); 325 let obligations = mem::replace(&mut self.obligations, Vec::new());
323 for obligation in obligations { 326 for obligation in obligations {
324 // FIXME resolve types in the obligation first 327 let (solution, canonicalized) = match &obligation {
325 let (solution, var_mapping) = match &obligation {
326 Obligation::Trait(tr) => { 328 Obligation::Trait(tr) => {
327 let (tr, var_mapping) = super::traits::canonicalize(tr.clone()); 329 let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
328 (self.db.implements(tr), var_mapping) 330 (
331 super::traits::implements(
332 self.db,
333 self.resolver.krate().unwrap(),
334 canonicalized.value.clone(),
335 ),
336 canonicalized,
337 )
329 } 338 }
330 }; 339 };
331 match solution { 340 match solution {
332 Some(Solution::Unique(substs)) => { 341 Some(Solution::Unique(substs)) => {
333 for (i, subst) in substs.0.iter().enumerate() { 342 canonicalized.apply_solution(self, substs.0);
334 let uncanonical = var_mapping[i];
335 // FIXME the subst may contain type variables, which would need to be mapped back as well
336 self.unify(&Ty::Infer(InferTy::TypeVar(uncanonical)), subst);
337 }
338 } 343 }
339 Some(Solution::Ambig(Guidance::Definite(substs))) => { 344 Some(Solution::Ambig(Guidance::Definite(substs))) => {
340 for (i, subst) in substs.0.iter().enumerate() { 345 canonicalized.apply_solution(self, substs.0);
341 let uncanonical = var_mapping[i];
342 // FIXME the subst may contain type variables, which would need to be mapped back as well
343 self.unify(&Ty::Infer(InferTy::TypeVar(uncanonical)), subst);
344 }
345 self.obligations.push(obligation); 346 self.obligations.push(obligation);
346 } 347 }
347 Some(_) => { 348 Some(_) => {
349 // FIXME use this when trying to resolve everything at the end
348 self.obligations.push(obligation); 350 self.obligations.push(obligation);
349 } 351 }
350 None => { 352 None => {
@@ -737,14 +739,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
737 }; 739 };
738 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown)); 740 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
739 741
740 let inner_tys = args 742 let inner_tys: Substs = args
741 .iter() 743 .iter()
742 .zip(expectations_iter) 744 .zip(expectations_iter)
743 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) 745 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
744 .collect::<Vec<_>>() 746 .collect::<Vec<_>>()
745 .into(); 747 .into();
746 748
747 Ty::apply(TypeCtor::Tuple, Substs(inner_tys)) 749 Ty::apply(TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, inner_tys)
748 } 750 }
749 Pat::Ref { pat, mutability } => { 751 Pat::Ref { pat, mutability } => {
750 let expectation = match expected.as_reference() { 752 let expectation = match expected.as_reference() {
@@ -877,9 +879,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
877 generic_args: Option<&GenericArgs>, 879 generic_args: Option<&GenericArgs>,
878 ) -> Ty { 880 ) -> Ty {
879 let receiver_ty = self.infer_expr(receiver, &Expectation::none()); 881 let receiver_ty = self.infer_expr(receiver, &Expectation::none());
880 let resolved = receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); 882 let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone());
883 let resolved = method_resolution::lookup_method(
884 &canonicalized_receiver.value,
885 self.db,
886 method_name,
887 &self.resolver,
888 );
881 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 889 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
882 Some((ty, func)) => { 890 Some((ty, func)) => {
891 let ty = canonicalized_receiver.decanonicalize_ty(ty);
883 self.write_method_resolution(tgt_expr, func); 892 self.write_method_resolution(tgt_expr, func);
884 ( 893 (
885 ty, 894 ty,
@@ -1064,7 +1073,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1064 .autoderef(self.db) 1073 .autoderef(self.db)
1065 .find_map(|derefed_ty| match derefed_ty { 1074 .find_map(|derefed_ty| match derefed_ty {
1066 Ty::Apply(a_ty) => match a_ty.ctor { 1075 Ty::Apply(a_ty) => match a_ty.ctor {
1067 TypeCtor::Tuple => { 1076 TypeCtor::Tuple { .. } => {
1068 let i = name.to_string().parse::<usize>().ok(); 1077 let i = name.to_string().parse::<usize>().ok();
1069 i.and_then(|i| a_ty.parameters.0.get(i).cloned()) 1078 i.and_then(|i| a_ty.parameters.0.get(i).cloned())
1070 } 1079 }
@@ -1175,7 +1184,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1175 ty_vec.push(self.infer_expr(*arg, &Expectation::none())); 1184 ty_vec.push(self.infer_expr(*arg, &Expectation::none()));
1176 } 1185 }
1177 1186
1178 Ty::apply(TypeCtor::Tuple, Substs(ty_vec.into())) 1187 Ty::apply(
1188 TypeCtor::Tuple { cardinality: ty_vec.len() as u16 },
1189 Substs(ty_vec.into()),
1190 )
1179 } 1191 }
1180 Expr::Array(array) => { 1192 Expr::Array(array) => {
1181 let elem_ty = match &expected.ty { 1193 let elem_ty = match &expected.ty {
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
new file mode 100644
index 000000000..8ca7e957d
--- /dev/null
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -0,0 +1,122 @@
1//! Unification and canonicalization logic.
2
3use crate::db::HirDatabase;
4use crate::ty::{Ty, Canonical, TraitRef, InferTy};
5use super::InferenceContext;
6
7impl<'a, D: HirDatabase> InferenceContext<'a, D> {
8 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
9 where
10 'a: 'b,
11 {
12 Canonicalizer { ctx: self, free_vars: Vec::new(), var_stack: Vec::new() }
13 }
14}
15
16pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase>
17where
18 'a: 'b,
19{
20 ctx: &'b mut InferenceContext<'a, D>,
21 free_vars: Vec<InferTy>,
22 /// A stack of type variables that is used to detect recursive types (which
23 /// are an error, but we need to protect against them to avoid stack
24 /// overflows).
25 var_stack: Vec<super::TypeVarId>,
26}
27
28pub(super) struct Canonicalized<T> {
29 pub value: Canonical<T>,
30 free_vars: Vec<InferTy>,
31}
32
33impl<'a, 'b, D: HirDatabase> Canonicalizer<'a, 'b, D>
34where
35 'a: 'b,
36{
37 fn add(&mut self, free_var: InferTy) -> usize {
38 self.free_vars.iter().position(|&v| v == free_var).unwrap_or_else(|| {
39 let next_index = self.free_vars.len();
40 self.free_vars.push(free_var);
41 next_index
42 })
43 }
44
45 fn do_canonicalize_ty(&mut self, ty: Ty) -> Ty {
46 ty.fold(&mut |ty| match ty {
47 Ty::Infer(tv) => {
48 let inner = tv.to_inner();
49 if self.var_stack.contains(&inner) {
50 // recursive type
51 return tv.fallback_value();
52 }
53 if let Some(known_ty) = self.ctx.var_unification_table.probe_value(inner).known() {
54 self.var_stack.push(inner);
55 let result = self.do_canonicalize_ty(known_ty.clone());
56 self.var_stack.pop();
57 result
58 } else {
59 let free_var = InferTy::TypeVar(self.ctx.var_unification_table.find(inner));
60 let position = self.add(free_var);
61 Ty::Bound(position as u32)
62 }
63 }
64 _ => ty,
65 })
66 }
67
68 fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef {
69 let substs = trait_ref
70 .substs
71 .iter()
72 .map(|ty| self.do_canonicalize_ty(ty.clone()))
73 .collect::<Vec<_>>();
74 TraitRef { trait_: trait_ref.trait_, substs: substs.into() }
75 }
76
77 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
78 Canonicalized {
79 value: Canonical { value: result, num_vars: self.free_vars.len() },
80 free_vars: self.free_vars,
81 }
82 }
83
84 pub fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
85 let result = self.do_canonicalize_ty(ty);
86 self.into_canonicalized(result)
87 }
88
89 pub fn canonicalize_trait_ref(mut self, trait_ref: TraitRef) -> Canonicalized<TraitRef> {
90 let result = self.do_canonicalize_trait_ref(trait_ref);
91 self.into_canonicalized(result)
92 }
93}
94
95impl<T> Canonicalized<T> {
96 pub fn decanonicalize_ty(&self, ty: Ty) -> Ty {
97 ty.fold(&mut |ty| match ty {
98 Ty::Bound(idx) => {
99 if (idx as usize) < self.free_vars.len() {
100 Ty::Infer(self.free_vars[idx as usize].clone())
101 } else {
102 Ty::Bound(idx)
103 }
104 }
105 ty => ty,
106 })
107 }
108
109 pub fn apply_solution(
110 &self,
111 ctx: &mut InferenceContext<'_, impl HirDatabase>,
112 solution: Canonical<Vec<Ty>>,
113 ) {
114 // the solution may contain new variables, which we need to convert to new inference vars
115 let new_vars =
116 (0..solution.num_vars).map(|_| ctx.new_type_var()).collect::<Vec<_>>().into();
117 for (i, ty) in solution.value.into_iter().enumerate() {
118 let var = self.free_vars[i].clone();
119 ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars));
120 }
121 }
122}
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 7fac084ce..8bab7e54b 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -29,7 +29,10 @@ impl Ty {
29 TypeRef::Tuple(inner) => { 29 TypeRef::Tuple(inner) => {
30 let inner_tys = 30 let inner_tys =
31 inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); 31 inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
32 Ty::apply(TypeCtor::Tuple, Substs(inner_tys.into())) 32 Ty::apply(
33 TypeCtor::Tuple { cardinality: inner_tys.len() as u16 },
34 Substs(inner_tys.into()),
35 )
33 } 36 }
34 TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path), 37 TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
35 TypeRef::RawPtr(inner, mutability) => { 38 TypeRef::RawPtr(inner, mutability) => {
@@ -53,7 +56,7 @@ impl Ty {
53 let inner_tys = 56 let inner_tys =
54 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); 57 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
55 let sig = Substs(inner_tys.into()); 58 let sig = Substs(inner_tys.into());
56 Ty::apply(TypeCtor::FnPtr, sig) 59 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
57 } 60 }
58 TypeRef::Error => Ty::Unknown, 61 TypeRef::Error => Ty::Unknown,
59 } 62 }
@@ -238,6 +241,11 @@ impl TraitRef {
238 let segment = path.segments.last().expect("path should have at least one segment"); 241 let segment = path.segments.last().expect("path should have at least one segment");
239 substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) 242 substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true)
240 } 243 }
244
245 pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef {
246 let substs = Substs::identity(&trait_.generic_params(db));
247 TraitRef { trait_, substs }
248 }
241} 249}
242 250
243/// Build the declared type of an item. This depends on the namespace; e.g. for 251/// Build the declared type of an item. This depends on the namespace; e.g. for
@@ -299,7 +307,7 @@ fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
299/// function body. 307/// function body.
300fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { 308fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
301 let generics = def.generic_params(db); 309 let generics = def.generic_params(db);
302 let substs = make_substs(&generics); 310 let substs = Substs::identity(&generics);
303 Ty::apply(TypeCtor::FnDef(def.into()), substs) 311 Ty::apply(TypeCtor::FnDef(def.into()), substs)
304} 312}
305 313
@@ -341,7 +349,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
341 return type_for_struct(db, def); // Unit struct 349 return type_for_struct(db, def); // Unit struct
342 } 350 }
343 let generics = def.generic_params(db); 351 let generics = def.generic_params(db);
344 let substs = make_substs(&generics); 352 let substs = Substs::identity(&generics);
345 Ty::apply(TypeCtor::FnDef(def.into()), substs) 353 Ty::apply(TypeCtor::FnDef(def.into()), substs)
346} 354}
347 355
@@ -357,7 +365,7 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant)
357 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 365 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
358 .collect::<Vec<_>>(); 366 .collect::<Vec<_>>();
359 let generics = def.parent_enum(db).generic_params(db); 367 let generics = def.parent_enum(db).generic_params(db);
360 let substs = make_substs(&generics); 368 let substs = Substs::identity(&generics);
361 let ret = type_for_enum(db, def.parent_enum(db)).subst(&substs); 369 let ret = type_for_enum(db, def.parent_enum(db)).subst(&substs);
362 FnSig::from_params_and_return(params, ret) 370 FnSig::from_params_and_return(params, ret)
363} 371}
@@ -369,36 +377,25 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) ->
369 return type_for_enum(db, def.parent_enum(db)); // Unit variant 377 return type_for_enum(db, def.parent_enum(db)); // Unit variant
370 } 378 }
371 let generics = def.parent_enum(db).generic_params(db); 379 let generics = def.parent_enum(db).generic_params(db);
372 let substs = make_substs(&generics); 380 let substs = Substs::identity(&generics);
373 Ty::apply(TypeCtor::FnDef(def.into()), substs) 381 Ty::apply(TypeCtor::FnDef(def.into()), substs)
374} 382}
375 383
376fn make_substs(generics: &GenericParams) -> Substs {
377 Substs(
378 generics
379 .params_including_parent()
380 .into_iter()
381 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() })
382 .collect::<Vec<_>>()
383 .into(),
384 )
385}
386
387fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { 384fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
388 let generics = s.generic_params(db); 385 let generics = s.generic_params(db);
389 Ty::apply(TypeCtor::Adt(s.into()), make_substs(&generics)) 386 Ty::apply(TypeCtor::Adt(s.into()), Substs::identity(&generics))
390} 387}
391 388
392fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { 389fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
393 let generics = s.generic_params(db); 390 let generics = s.generic_params(db);
394 Ty::apply(TypeCtor::Adt(s.into()), make_substs(&generics)) 391 Ty::apply(TypeCtor::Adt(s.into()), Substs::identity(&generics))
395} 392}
396 393
397fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty { 394fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
398 let generics = t.generic_params(db); 395 let generics = t.generic_params(db);
399 let resolver = t.resolver(db); 396 let resolver = t.resolver(db);
400 let type_ref = t.type_ref(db); 397 let type_ref = t.type_ref(db);
401 let substs = make_substs(&generics); 398 let substs = Substs::identity(&generics);
402 let inner = Ty::from_hir(db, &resolver, &type_ref); 399 let inner = Ty::from_hir(db, &resolver, &type_ref);
403 inner.subst(&substs) 400 inner.subst(&substs)
404} 401}
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index ea6e0dc0f..607e9ba79 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, 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,124 +130,122 @@ 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 'traits: for t in resolver.traits_in_scope() { 185 let krate = resolver.krate()?;
187 let data = t.trait_data(db); 186 'traits: for t in resolver.traits_in_scope() {
188 // we'll be lazy about checking whether the type implements the 187 let data = t.trait_data(db);
189 // trait, but if we find out it doesn't, we'll skip the rest of the 188 // we'll be lazy about checking whether the type implements the
190 // iteration 189 // trait, but if we find out it doesn't, we'll skip the rest of the
191 let mut known_implemented = false; 190 // iteration
192 for item in data.items() { 191 let mut known_implemented = false;
193 match item { 192 for item in data.items() {
194 &TraitItem::Function(m) => { 193 match item {
195 let sig = m.signature(db); 194 &TraitItem::Function(m) => {
196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 195 let sig = m.signature(db);
197 if !known_implemented { 196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
198 let trait_ref = TraitRef { 197 if !known_implemented {
199 trait_: t, 198 let trait_ref = canonical_trait_ref(db, t, ty.clone());
200 substs: fresh_substs_for_trait(db, t, self.clone()), 199 // FIXME cache this implements check (without solution) in a query?
201 }; 200 if super::traits::implements(db, krate, trait_ref).is_none() {
202 let (trait_ref, _) = super::traits::canonicalize(trait_ref); 201 continue 'traits;
203 if db.implements(trait_ref).is_none() {
204 continue 'traits;
205 }
206 }
207 known_implemented = true;
208 if let Some(result) = callback(self, m) {
209 return Some(result);
210 } 202 }
211 } 203 }
204 known_implemented = true;
205 if let Some(result) = callback(&ty.value, m) {
206 return Some(result);
207 }
212 } 208 }
213 _ => {}
214 } 209 }
210 _ => {}
215 } 211 }
216 } 212 }
217 None
218 } 213 }
214 None
215}
219 216
220 fn iterate_inherent_methods<T>( 217fn iterate_inherent_methods<T>(
221 &self, 218 ty: &Canonical<Ty>,
222 db: &impl HirDatabase, 219 db: &impl HirDatabase,
223 name: Option<&Name>, 220 name: Option<&Name>,
224 krate: Crate, 221 krate: Crate,
225 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 222 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
226 ) -> Option<T> { 223) -> Option<T> {
227 let krate = match def_crate(db, krate, self) { 224 let krate = match def_crate(db, krate, &ty.value) {
228 Some(krate) => krate, 225 Some(krate) => krate,
229 None => return None, 226 None => return None,
230 }; 227 };
231 let impls = db.impls_in_crate(krate); 228 let impls = db.impls_in_crate(krate);
232 229
233 for impl_block in impls.lookup_impl_blocks(self) { 230 for impl_block in impls.lookup_impl_blocks(&ty.value) {
234 for item in impl_block.items(db) { 231 for item in impl_block.items(db) {
235 match item { 232 match item {
236 ImplItem::Method(f) => { 233 ImplItem::Method(f) => {
237 let sig = f.signature(db); 234 let sig = f.signature(db);
238 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 235 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
239 if let Some(result) = callback(self, f) { 236 if let Some(result) = callback(&ty.value, f) {
240 return Some(result); 237 return Some(result);
241 }
242 } 238 }
243 } 239 }
244 _ => {}
245 } 240 }
241 _ => {}
246 } 242 }
247 } 243 }
248 None
249 } 244 }
245 None
246}
250 247
248impl Ty {
251 // This would be nicer if it just returned an iterator, but that runs into 249 // This would be nicer if it just returned an iterator, but that runs into
252 // lifetime problems, because we need to borrow temp `CrateImplBlocks`. 250 // lifetime problems, because we need to borrow temp `CrateImplBlocks`.
253 pub fn iterate_impl_items<T>( 251 pub fn iterate_impl_items<T>(
@@ -271,15 +269,26 @@ impl Ty {
271} 269}
272 270
273/// This creates Substs for a trait with the given Self type and type variables 271/// This creates Substs for a trait with the given Self type and type variables
274/// for all other parameters. This is kind of a hack since these aren't 'real' 272/// for all other parameters, to query Chalk with it.
275/// type variables; the resulting trait reference is just used for the 273fn canonical_trait_ref(
276/// preliminary method candidate check. 274 db: &impl HirDatabase,
277fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs { 275 trait_: Trait,
276 self_ty: Canonical<Ty>,
277) -> Canonical<TraitRef> {
278 let mut substs = Vec::new(); 278 let mut substs = Vec::new();
279 let generics = tr.generic_params(db); 279 let generics = trait_.generic_params(db);
280 substs.push(self_ty); 280 let num_vars = self_ty.num_vars;
281 substs.extend(generics.params_including_parent().into_iter().skip(1).enumerate().map( 281 substs.push(self_ty.value);
282 |(i, _p)| Ty::Infer(super::infer::InferTy::TypeVar(super::infer::TypeVarId(i as u32))), 282 substs.extend(
283 )); 283 generics
284 substs.into() 284 .params_including_parent()
285 .into_iter()
286 .skip(1)
287 .enumerate()
288 .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)),
289 );
290 Canonical {
291 num_vars: substs.len() - 1 + self_ty.num_vars,
292 value: TraitRef { trait_, substs: substs.into() },
293 }
285} 294}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c76a5012f..0aecde37c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2140,7 +2140,7 @@ fn test() {
2140[102; 127) '{ ...d(); }': () 2140[102; 127) '{ ...d(); }': ()
2141[108; 109) 'S': S<u32>(T) -> S<T> 2141[108; 109) 'S': S<u32>(T) -> S<T>
2142[108; 115) 'S(1u32)': S<u32> 2142[108; 115) 'S(1u32)': S<u32>
2143[108; 124) 'S(1u32...thod()': {unknown} 2143[108; 124) 'S(1u32...thod()': u32
2144[110; 114) '1u32': u32"### 2144[110; 114) '1u32': u32"###
2145 ); 2145 );
2146} 2146}
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 06f483899..a1ed0c028 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -1,47 +1,65 @@
1//! Stuff that will probably mostly replaced by Chalk. 1//! Trait solving using Chalk.
2use std::collections::HashMap; 2use std::sync::{Arc, Mutex};
3 3
4use crate::{db::HirDatabase, generics::HasGenericParams}; 4use log::debug;
5use super::{TraitRef, Substs, infer::{TypeVarId, InferTy}, Ty}; 5use chalk_ir::cast::Cast;
6 6
7// Copied (and simplified) from Chalk 7use crate::{Crate, Trait, db::HirDatabase, ImplBlock};
8use super::{TraitRef, Ty, Canonical};
8 9
9#[derive(Clone, Debug, PartialEq, Eq)] 10use self::chalk::{ToChalk, from_chalk};
10/// A (possible) solution for a proposed goal. Usually packaged in a `Result`,
11/// where `Err` represents definite *failure* to prove a goal.
12pub enum Solution {
13 /// The goal indeed holds, and there is a unique value for all existential
14 /// variables.
15 Unique(Substs),
16 11
17 /// The goal may be provable in multiple ways, but regardless we may have some guidance 12mod chalk;
18 /// for type inference. 13
19 Ambig(Guidance), 14pub(crate) type Solver = chalk_solve::Solver;
15
16#[derive(Debug, Copy, Clone)]
17struct ChalkContext<'a, DB> {
18 db: &'a DB,
19 krate: Crate,
20} 20}
21 21
22#[derive(Clone, Debug, PartialEq, Eq)] 22pub(crate) fn solver(_db: &impl HirDatabase, _krate: Crate) -> Arc<Mutex<Solver>> {
23/// When a goal holds ambiguously (e.g., because there are multiple possible 23 // krate parameter is just so we cache a unique solver per crate
24/// solutions), we issue a set of *guidance* back to type inference. 24 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: 10 };
25pub enum Guidance { 25 Arc::new(Mutex::new(solver_choice.into_solver()))
26 /// The existential variables *must* have the given values if the goal is 26}
27 /// ever to hold, but that alone isn't enough to guarantee the goal will
28 /// actually hold.
29 Definite(Substs),
30 27
31 /// There are multiple plausible values for the existentials, but the ones 28/// Collects impls for the given trait in the whole dependency tree of `krate`.
32 /// here are suggested as the preferred choice heuristically. These should 29pub(crate) fn impls_for_trait(
33 /// be used for inference fallback only. 30 db: &impl HirDatabase,
34 Suggested(Substs), 31 krate: Crate,
32 trait_: Trait,
33) -> Arc<[ImplBlock]> {
34 let mut impls = Vec::new();
35 // We call the query recursively here. On the one hand, this means we can
36 // reuse results from queries for different crates; on the other hand, this
37 // will only ever get called for a few crates near the root of the tree (the
38 // ones the user is editing), so this may actually be a waste of memory. I'm
39 // doing it like this mainly for simplicity for now.
40 for dep in krate.dependencies(db) {
41 impls.extend(db.impls_for_trait(dep.krate, trait_).iter());
42 }
43 let crate_impl_blocks = db.impls_in_crate(krate);
44 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_));
45 impls.into()
46}
35 47
36 /// There's no useful information to feed back to type inference 48fn solve(
37 Unknown, 49 db: &impl HirDatabase,
50 krate: Crate,
51 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal>>,
52) -> Option<chalk_solve::Solution> {
53 let context = ChalkContext { db, krate };
54 let solver = db.solver(krate);
55 let solution = solver.lock().unwrap().solve(&context, goal);
56 debug!("solve({:?}) => {:?}", goal, solution);
57 solution
38} 58}
39 59
40/// Something that needs to be proven (by Chalk) during type checking, e.g. that 60/// Something that needs to be proven (by Chalk) during type checking, e.g. that
41/// a certain type implements a certain trait. Proving the Obligation might 61/// a certain type implements a certain trait. Proving the Obligation might
42/// result in additional information about inference variables. 62/// result in additional information about inference variables.
43///
44/// This might be handled by Chalk when we integrate it?
45#[derive(Clone, Debug, PartialEq, Eq)] 63#[derive(Clone, Debug, PartialEq, Eq)]
46pub enum Obligation { 64pub enum Obligation {
47 /// Prove that a certain type implements a trait (the type is the `Self` type 65 /// Prove that a certain type implements a trait (the type is the `Self` type
@@ -49,67 +67,94 @@ pub enum Obligation {
49 Trait(TraitRef), 67 Trait(TraitRef),
50} 68}
51 69
52/// Rudimentary check whether an impl exists for a given type and trait; this 70/// Check using Chalk whether trait is implemented for given parameters including `Self` type.
53/// will actually be done by chalk. 71pub(crate) fn implements(
54pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> Option<Solution> { 72 db: &impl HirDatabase,
55 // FIXME use all trait impls in the whole crate graph 73 krate: Crate,
56 let krate = trait_ref.trait_.module(db).krate(db); 74 trait_ref: Canonical<TraitRef>,
57 let krate = match krate { 75) -> Option<Solution> {
58 Some(krate) => krate, 76 let goal: chalk_ir::Goal = trait_ref.value.to_chalk(db).cast();
59 None => return None, 77 debug!("goal: {:?}", goal);
60 }; 78 let env = chalk_ir::Environment::new();
61 let crate_impl_blocks = db.impls_in_crate(krate); 79 let in_env = chalk_ir::InEnvironment::new(&env, goal);
62 let mut impl_blocks = crate_impl_blocks 80 let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
63 .lookup_impl_blocks_for_trait(&trait_ref.trait_) 81 let canonical =
64 // we don't handle where clauses at all, waiting for Chalk for that 82 chalk_ir::Canonical { value: in_env, binders: vec![parameter; trait_ref.num_vars] };
65 .filter(|impl_block| impl_block.generic_params(db).where_predicates.is_empty()); 83 // We currently don't deal with universes (I think / hope they're not yet
66 impl_blocks 84 // relevant for our use cases?)
67 .find_map(|impl_block| unify_trait_refs(&trait_ref, &impl_block.target_trait_ref(db)?)) 85 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
86 let solution = solve(db, krate, &u_canonical);
87 solution.map(|solution| solution_from_chalk(db, solution))
68} 88}
69 89
70pub(super) fn canonicalize(trait_ref: TraitRef) -> (TraitRef, Vec<TypeVarId>) { 90fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution {
71 let mut canonical = HashMap::new(); // mapping uncanonical -> canonical 91 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| {
72 let mut uncanonical = Vec::new(); // mapping canonical -> uncanonical (which is dense) 92 let value = subst
73 let mut substs = trait_ref.substs.0.to_vec(); 93 .value
74 for ty in &mut substs { 94 .parameters
75 ty.walk_mut(&mut |ty| match ty { 95 .into_iter()
76 Ty::Infer(InferTy::TypeVar(tv)) => { 96 .map(|p| {
77 let tv: &mut TypeVarId = tv; 97 let ty = match p {
78 *tv = *canonical.entry(*tv).or_insert_with(|| { 98 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
79 let i = uncanonical.len(); 99 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
80 uncanonical.push(*tv); 100 };
81 TypeVarId(i as u32) 101 ty
82 }); 102 })
83 } 103 .collect();
84 _ => {} 104 let result = Canonical { value, num_vars: subst.binders.len() };
85 }); 105 SolutionVariables(result)
106 };
107 match solution {
108 chalk_solve::Solution::Unique(constr_subst) => {
109 let subst = chalk_ir::Canonical {
110 value: constr_subst.value.subst,
111 binders: constr_subst.binders,
112 };
113 Solution::Unique(convert_subst(subst))
114 }
115 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => {
116 Solution::Ambig(Guidance::Definite(convert_subst(subst)))
117 }
118 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => {
119 Solution::Ambig(Guidance::Suggested(convert_subst(subst)))
120 }
121 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => {
122 Solution::Ambig(Guidance::Unknown)
123 }
86 } 124 }
87 (TraitRef { substs: substs.into(), ..trait_ref }, uncanonical)
88} 125}
89 126
90fn unify_trait_refs(tr1: &TraitRef, tr2: &TraitRef) -> Option<Solution> { 127#[derive(Clone, Debug, PartialEq, Eq)]
91 if tr1.trait_ != tr2.trait_ { 128pub(crate) struct SolutionVariables(pub Canonical<Vec<Ty>>);
92 return None; 129
93 } 130#[derive(Clone, Debug, PartialEq, Eq)]
94 let mut solution_substs = Vec::new(); 131/// A (possible) solution for a proposed goal.
95 for (t1, t2) in tr1.substs.0.iter().zip(tr2.substs.0.iter()) { 132pub(crate) enum Solution {
96 // this is very bad / hacky 'unification' logic, just enough to make the simple tests pass 133 /// The goal indeed holds, and there is a unique value for all existential
97 match (t1, t2) { 134 /// variables.
98 (_, Ty::Infer(InferTy::TypeVar(_))) | (_, Ty::Unknown) | (_, Ty::Param { .. }) => { 135 Unique(SolutionVariables),
99 // type variable (or similar) in the impl, we just assume it works 136
100 } 137 /// The goal may be provable in multiple ways, but regardless we may have some guidance
101 (Ty::Infer(InferTy::TypeVar(v1)), _) => { 138 /// for type inference. In this case, we don't return any lifetime
102 // type variable in the query and fixed type in the impl, record its value 139 /// constraints, since we have not "committed" to any particular solution
103 solution_substs.resize_with(v1.0 as usize + 1, || Ty::Unknown); 140 /// yet.
104 solution_substs[v1.0 as usize] = t2.clone(); 141 Ambig(Guidance),
105 } 142}
106 _ => { 143
107 // check that they're equal (actually we'd have to recurse etc.) 144#[derive(Clone, Debug, PartialEq, Eq)]
108 if t1 != t2 { 145/// When a goal holds ambiguously (e.g., because there are multiple possible
109 return None; 146/// solutions), we issue a set of *guidance* back to type inference.
110 } 147pub(crate) enum Guidance {
111 } 148 /// The existential variables *must* have the given values if the goal is
112 } 149 /// ever to hold, but that alone isn't enough to guarantee the goal will
113 } 150 /// actually hold.
114 Some(Solution::Unique(solution_substs.into())) 151 Definite(SolutionVariables),
152
153 /// There are multiple plausible values for the existentials, but the ones
154 /// here are suggested as the preferred choice heuristically. These should
155 /// be used for inference fallback only.
156 Suggested(SolutionVariables),
157
158 /// There's no useful information to feed back to type inference
159 Unknown,
115} 160}
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
new file mode 100644
index 000000000..8b77d21b4
--- /dev/null
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -0,0 +1,333 @@
1//! Conversion code from/to Chalk.
2use std::sync::Arc;
3
4use log::debug;
5
6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};
8
9use ra_db::salsa::{InternId, InternKey};
10
11use crate::{
12 Trait, HasGenericParams, ImplBlock,
13 db::HirDatabase,
14 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs},
15};
16use super::ChalkContext;
17
18pub(super) trait ToChalk {
19 type Chalk;
20 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
21 fn from_chalk(db: &impl HirDatabase, chalk: Self::Chalk) -> Self;
22}
23
24pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T
25where
26 T: ToChalk<Chalk = ChalkT>,
27{
28 T::from_chalk(db, chalk)
29}
30
31impl ToChalk for Ty {
32 type Chalk = chalk_ir::Ty;
33 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
34 match self {
35 Ty::Apply(apply_ty) => {
36 let struct_id = apply_ty.ctor.to_chalk(db);
37 let name = TypeName::TypeKindId(struct_id.into());
38 let parameters = apply_ty.parameters.to_chalk(db);
39 chalk_ir::ApplicationTy { name, parameters }.cast()
40 }
41 Ty::Param { idx, .. } => {
42 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
43 }
44 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
45 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
46 // FIXME this is clearly incorrect, but probably not too incorrect
47 // and I'm not sure what to actually do with Ty::Unknown
48 Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(),
49 }
50 }
51 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
52 match chalk {
53 chalk_ir::Ty::Apply(apply_ty) => {
54 match apply_ty.name {
55 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => {
56 let ctor = from_chalk(db, struct_id);
57 let parameters = from_chalk(db, apply_ty.parameters);
58 Ty::Apply(ApplicationTy { ctor, parameters })
59 }
60 // FIXME handle TypeKindId::Trait/Type here
61 TypeName::TypeKindId(_) => unimplemented!(),
62 TypeName::AssociatedType(_) => unimplemented!(),
63 TypeName::Placeholder(idx) => {
64 assert_eq!(idx.ui, UniverseIndex::ROOT);
65 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
66 }
67 }
68 }
69 chalk_ir::Ty::Projection(_) => unimplemented!(),
70 chalk_ir::Ty::UnselectedProjection(_) => unimplemented!(),
71 chalk_ir::Ty::ForAll(_) => unimplemented!(),
72 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
73 chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),
74 }
75 }
76}
77
78impl ToChalk for Substs {
79 type Chalk = Vec<chalk_ir::Parameter>;
80
81 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter> {
82 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
83 }
84
85 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs {
86 parameters
87 .into_iter()
88 .map(|p| match p {
89 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
90 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
91 })
92 .collect::<Vec<_>>()
93 .into()
94 }
95}
96
97impl ToChalk for TraitRef {
98 type Chalk = chalk_ir::TraitRef;
99
100 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef {
101 let trait_id = self.trait_.to_chalk(db);
102 let parameters = self.substs.to_chalk(db);
103 chalk_ir::TraitRef { trait_id, parameters }
104 }
105
106 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self {
107 let trait_ = from_chalk(db, trait_ref.trait_id);
108 let substs = from_chalk(db, trait_ref.parameters);
109 TraitRef { trait_, substs }
110 }
111}
112
113impl ToChalk for Trait {
114 type Chalk = chalk_ir::TraitId;
115
116 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId {
117 self.id.into()
118 }
119
120 fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait {
121 Trait { id: trait_id.into() }
122 }
123}
124
125impl ToChalk for TypeCtor {
126 type Chalk = chalk_ir::StructId;
127
128 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId {
129 db.intern_type_ctor(self).into()
130 }
131
132 fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor {
133 db.lookup_intern_type_ctor(struct_id.into())
134 }
135}
136
137impl ToChalk for ImplBlock {
138 type Chalk = chalk_ir::ImplId;
139
140 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
141 db.intern_impl_block(self).into()
142 }
143
144 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock {
145 db.lookup_intern_impl_block(impl_id.into())
146 }
147}
148
149fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
150 chalk_ir::Binders {
151 value,
152 binders: std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(),
153 }
154}
155
156impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
157where
158 DB: HirDatabase,
159{
160 fn associated_ty_data(&self, _ty: TypeId) -> Arc<AssociatedTyDatum> {
161 unimplemented!()
162 }
163 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
164 debug!("trait_datum {:?}", trait_id);
165 let trait_: Trait = from_chalk(self.db, trait_id);
166 let generic_params = trait_.generic_params(self.db);
167 let bound_vars = Substs::bound_vars(&generic_params);
168 let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db);
169 let flags = chalk_rust_ir::TraitFlags {
170 // FIXME set these flags correctly
171 auto: false,
172 marker: false,
173 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
174 fundamental: false,
175 };
176 let where_clauses = Vec::new(); // FIXME add where clauses
177 let associated_ty_ids = Vec::new(); // FIXME add associated tys
178 let trait_datum_bound =
179 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
180 let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) };
181 Arc::new(trait_datum)
182 }
183 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
184 debug!("struct_datum {:?}", struct_id);
185 let type_ctor = from_chalk(self.db, struct_id);
186 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
187 // FIXME extract this to a method on Ty
188 let (num_params, upstream) = match type_ctor {
189 TypeCtor::Bool
190 | TypeCtor::Char
191 | TypeCtor::Int(_)
192 | TypeCtor::Float(_)
193 | TypeCtor::Never
194 | TypeCtor::Str => (0, true),
195 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true),
196 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, true),
197 TypeCtor::Tuple { cardinality } => (cardinality as usize, true),
198 TypeCtor::FnDef(_) => unimplemented!(),
199 TypeCtor::Adt(adt) => {
200 let generic_params = adt.generic_params(self.db);
201 (
202 generic_params.count_params_including_parent(),
203 adt.krate(self.db) != Some(self.krate),
204 )
205 }
206 };
207 let flags = chalk_rust_ir::StructFlags {
208 upstream,
209 // FIXME set fundamental flag correctly
210 fundamental: false,
211 };
212 let where_clauses = Vec::new(); // FIXME add where clauses
213 let self_ty = chalk_ir::ApplicationTy {
214 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()),
215 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
216 };
217 let struct_datum_bound = chalk_rust_ir::StructDatumBound {
218 self_ty,
219 fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
220 where_clauses,
221 flags,
222 };
223 let struct_datum = StructDatum { binders: make_binders(struct_datum_bound, num_params) };
224 Arc::new(struct_datum)
225 }
226 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
227 debug!("impl_datum {:?}", impl_id);
228 let impl_block: ImplBlock = from_chalk(self.db, impl_id);
229 let generic_params = impl_block.generic_params(self.db);
230 let bound_vars = Substs::bound_vars(&generic_params);
231 let trait_ref = impl_block
232 .target_trait_ref(self.db)
233 .expect("FIXME handle unresolved impl block trait ref")
234 .subst(&bound_vars);
235 let impl_type = if impl_block.module().krate(self.db) == Some(self.krate) {
236 chalk_rust_ir::ImplType::Local
237 } else {
238 chalk_rust_ir::ImplType::External
239 };
240 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
241 // FIXME handle negative impls (impl !Sync for Foo)
242 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)),
243 where_clauses: Vec::new(), // FIXME add where clauses
244 associated_ty_values: Vec::new(), // FIXME add associated type values
245 impl_type,
246 };
247 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) };
248 Arc::new(impl_datum)
249 }
250 fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> {
251 debug!("impls_for_trait {:?}", trait_id);
252 let trait_ = from_chalk(self.db, trait_id);
253 self.db
254 .impls_for_trait(self.krate, trait_)
255 .iter()
256 // FIXME temporary hack -- as long as we're not lowering where clauses
257 // correctly, ignore impls with them completely so as to not treat
258 // impl<T> Trait for T where T: ... as a blanket impl on all types
259 .filter(|impl_block| impl_block.generic_params(self.db).where_predicates.is_empty())
260 .map(|impl_block| impl_block.to_chalk(self.db))
261 .collect()
262 }
263 fn impl_provided_for(
264 &self,
265 auto_trait_id: chalk_ir::TraitId,
266 struct_id: chalk_ir::StructId,
267 ) -> bool {
268 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
269 false // FIXME
270 }
271 fn type_name(&self, _id: TypeKindId) -> Identifier {
272 unimplemented!()
273 }
274 fn split_projection<'p>(
275 &self,
276 projection: &'p ProjectionTy,
277 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) {
278 debug!("split_projection {:?}", projection);
279 unimplemented!()
280 }
281 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> {
282 debug!("custom_clauses");
283 vec![]
284 }
285 fn all_structs(&self) -> Vec<chalk_ir::StructId> {
286 debug!("all_structs");
287 // FIXME
288 vec![]
289 }
290}
291
292fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
293 T::from_intern_id(InternId::from(chalk_id.index))
294}
295fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
296 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
297}
298
299impl From<chalk_ir::TraitId> for crate::ids::TraitId {
300 fn from(trait_id: chalk_ir::TraitId) -> Self {
301 id_from_chalk(trait_id.0)
302 }
303}
304
305impl From<crate::ids::TraitId> for chalk_ir::TraitId {
306 fn from(trait_id: crate::ids::TraitId) -> Self {
307 chalk_ir::TraitId(id_to_chalk(trait_id))
308 }
309}
310
311impl From<chalk_ir::StructId> for crate::ids::TypeCtorId {
312 fn from(struct_id: chalk_ir::StructId) -> Self {
313 id_from_chalk(struct_id.0)
314 }
315}
316
317impl From<crate::ids::TypeCtorId> for chalk_ir::StructId {
318 fn from(type_ctor_id: crate::ids::TypeCtorId) -> Self {
319 chalk_ir::StructId(id_to_chalk(type_ctor_id))
320 }
321}
322
323impl From<chalk_ir::ImplId> for crate::ids::GlobalImplId {
324 fn from(impl_id: chalk_ir::ImplId) -> Self {
325 id_from_chalk(impl_id.0)
326 }
327}
328
329impl From<crate::ids::GlobalImplId> for chalk_ir::ImplId {
330 fn from(impl_id: crate::ids::GlobalImplId) -> Self {
331 chalk_ir::ImplId(id_to_chalk(impl_id))
332 }
333}