diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-04 19:07:09 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-04 19:07:09 +0100 |
commit | 9c49f6c36e1e097f938946811d1e2f5eb70edca9 (patch) | |
tree | 544bfd290a08475b1d5250bcc5e0717779b53758 /crates/ra_hir/src/ty | |
parent | b6ffb1d2a3bcc94e41c95c7a086117e11ce487e5 (diff) | |
parent | a4eb1a546c7623f65823c5e249cd3c6d8c90fd8c (diff) |
Merge #1216
1216: Basic Chalk integration r=matklad a=flodiebold
This replaces the ad-hoc `implements` check by Chalk. It doesn't yet any new functionality (e.g. where clauses aren't passed to Chalk yet). The tests that exist actually work, but it needs some refactoring, currently crashes when running analysis on the RA repo, and depends on rust-lang/chalk#216 which isn't merged yet :smile:
The main work here is converting stuff back and forth and providing Chalk with the information it needs, and the canonicalization logic. Since canonicalization depends a lot on the inference table, I don't think we can currently reuse the logic from Chalk, so we need to implement it ourselves; it's not actually that complicated anyway ;) I realized that we need a `Ty::Bound` variant separate from `Ty::Param` -- these are two different things, and I think type parameters inside a function actually need to be represented in Chalk as `Placeholder` types.
~~Currently this crashes in the 'real' world because we don't yet do canonicalization when filtering method candidates. Proper canonicalization needs the inference table (to collapse different inference variables that have already been unified), but we need to be able to call the method candidate selection from the completion code... So I'm currently thinking how to best handle that :smile:~~
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 52 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 122 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 37 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 223 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 223 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 333 |
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 | }; |
45 | use super::{ | 45 | use 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 | ||
51 | mod unify; | ||
52 | |||
50 | /// The entry point of type inference. | 53 | /// The entry point of type inference. |
51 | pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { | 54 | pub 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 | |||
3 | use crate::db::HirDatabase; | ||
4 | use crate::ty::{Ty, Canonical, TraitRef, InferTy}; | ||
5 | use super::InferenceContext; | ||
6 | |||
7 | impl<'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 | |||
16 | pub(super) struct Canonicalizer<'a, 'b, D: HirDatabase> | ||
17 | where | ||
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 | |||
28 | pub(super) struct Canonicalized<T> { | ||
29 | pub value: Canonical<T>, | ||
30 | free_vars: Vec<InferTy>, | ||
31 | } | ||
32 | |||
33 | impl<'a, 'b, D: HirDatabase> Canonicalizer<'a, 'b, D> | ||
34 | where | ||
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 | |||
95 | impl<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. |
300 | fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { | 308 | fn 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 | ||
376 | fn 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 | |||
387 | fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { | 384 | fn 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 | ||
392 | fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { | 389 | fn 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 | ||
397 | fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty { | 394 | fn 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 | }; |
19 | use super::{TraitRef, Substs}; | 19 | use 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 | ||
133 | impl 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). | 135 | pub(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>( | 146 | pub(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>( | 178 | fn 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>( | 217 | fn 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 | ||
248 | impl 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 | 273 | fn canonical_trait_ref( |
276 | /// preliminary method candidate check. | 274 | db: &impl HirDatabase, |
277 | fn 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. |
2 | use std::collections::HashMap; | 2 | use std::sync::{Arc, Mutex}; |
3 | 3 | ||
4 | use crate::{db::HirDatabase, generics::HasGenericParams}; | 4 | use log::debug; |
5 | use super::{TraitRef, Substs, infer::{TypeVarId, InferTy}, Ty}; | 5 | use chalk_ir::cast::Cast; |
6 | 6 | ||
7 | // Copied (and simplified) from Chalk | 7 | use crate::{Crate, Trait, db::HirDatabase, ImplBlock}; |
8 | use super::{TraitRef, Ty, Canonical}; | ||
8 | 9 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 10 | use 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. | ||
12 | pub 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 | 12 | mod chalk; |
18 | /// for type inference. | 13 | |
19 | Ambig(Guidance), | 14 | pub(crate) type Solver = chalk_solve::Solver; |
15 | |||
16 | #[derive(Debug, Copy, Clone)] | ||
17 | struct ChalkContext<'a, DB> { | ||
18 | db: &'a DB, | ||
19 | krate: Crate, | ||
20 | } | 20 | } |
21 | 21 | ||
22 | #[derive(Clone, Debug, PartialEq, Eq)] | 22 | pub(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 }; |
25 | pub 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 | 29 | pub(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 | 48 | fn 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)] |
46 | pub enum Obligation { | 64 | pub 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. | 71 | pub(crate) fn implements( |
54 | pub(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 | ||
70 | pub(super) fn canonicalize(trait_ref: TraitRef) -> (TraitRef, Vec<TypeVarId>) { | 90 | fn 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 | ||
90 | fn unify_trait_refs(tr1: &TraitRef, tr2: &TraitRef) -> Option<Solution> { | 127 | #[derive(Clone, Debug, PartialEq, Eq)] |
91 | if tr1.trait_ != tr2.trait_ { | 128 | pub(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()) { | 132 | pub(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 | } | 147 | pub(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. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use log::debug; | ||
5 | |||
6 | use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; | ||
7 | use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; | ||
8 | |||
9 | use ra_db::salsa::{InternId, InternKey}; | ||
10 | |||
11 | use crate::{ | ||
12 | Trait, HasGenericParams, ImplBlock, | ||
13 | db::HirDatabase, | ||
14 | ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs}, | ||
15 | }; | ||
16 | use super::ChalkContext; | ||
17 | |||
18 | pub(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 | |||
24 | pub(super) fn from_chalk<T, ChalkT>(db: &impl HirDatabase, chalk: ChalkT) -> T | ||
25 | where | ||
26 | T: ToChalk<Chalk = ChalkT>, | ||
27 | { | ||
28 | T::from_chalk(db, chalk) | ||
29 | } | ||
30 | |||
31 | impl 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 | |||
78 | impl 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 | |||
97 | impl 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 | |||
113 | impl 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 | |||
125 | impl 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 | |||
137 | impl 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 | |||
149 | fn 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 | |||
156 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> | ||
157 | where | ||
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 | |||
292 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { | ||
293 | T::from_intern_id(InternId::from(chalk_id.index)) | ||
294 | } | ||
295 | fn 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 | |||
299 | impl 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 | |||
305 | impl 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 | |||
311 | impl 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 | |||
317 | impl 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 | |||
323 | impl 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 | |||
329 | impl 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 | } | ||