aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/Cargo.toml6
-rw-r--r--crates/ra_hir/src/db.rs30
-rw-r--r--crates/ra_hir/src/ids.rs6
-rw-r--r--crates/ra_hir/src/ty.rs89
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs22
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs6
-rw-r--r--crates/ra_hir/src/ty/tests.rs55
-rw-r--r--crates/ra_hir/src/ty/traits.rs29
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs319
9 files changed, 373 insertions, 189 deletions
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 324961328..20f6e3649 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -23,9 +23,9 @@ hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
23test_utils = { path = "../test_utils" } 23test_utils = { path = "../test_utils" }
24ra_prof = { path = "../ra_prof" } 24ra_prof = { path = "../ra_prof" }
25 25
26chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } 26chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" }
27chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } 27chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" }
28chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } 28chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "a88cad7f0a69e05ba8f40b74c58a1c229c1b2478" }
29lalrpop-intern = "0.15.1" 29lalrpop-intern = "0.15.1"
30 30
31[dev-dependencies] 31[dev-dependencies]
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 276b0774f..d75d71d66 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -13,8 +13,10 @@ use crate::{
13 lang_item::{LangItemTarget, LangItems}, 13 lang_item::{LangItemTarget, LangItems},
14 traits::TraitData, 14 traits::TraitData,
15 ty::{ 15 ty::{
16 method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, 16 method_resolution::CrateImplBlocks,
17 InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, 17 traits::{AssocTyValue, Impl},
18 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
19 TypeCtor,
18 }, 20 },
19 type_alias::TypeAliasData, 21 type_alias::TypeAliasData,
20 Const, ConstData, Crate, DefWithBody, FnData, Function, ImplBlock, Module, Static, StructField, 22 Const, ConstData, Crate, DefWithBody, FnData, Function, ImplBlock, Module, Static, StructField,
@@ -119,26 +121,42 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
119 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; 121 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
120 #[salsa::interned] 122 #[salsa::interned]
121 fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId; 123 fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId;
124 #[salsa::interned]
125 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> ids::AssocTyValueId;
122 126
123 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] 127 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)]
124 fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc<chalk_rust_ir::AssociatedTyDatum>; 128 fn associated_ty_data(
129 &self,
130 id: chalk_ir::TypeId,
131 ) -> Arc<chalk_rust_ir::AssociatedTyDatum<chalk_ir::family::ChalkIr>>;
125 132
126 #[salsa::invoke(crate::ty::traits::chalk::trait_datum_query)] 133 #[salsa::invoke(crate::ty::traits::chalk::trait_datum_query)]
127 fn trait_datum( 134 fn trait_datum(
128 &self, 135 &self,
129 krate: Crate, 136 krate: Crate,
130 trait_id: chalk_ir::TraitId, 137 trait_id: chalk_ir::TraitId,
131 ) -> Arc<chalk_rust_ir::TraitDatum>; 138 ) -> Arc<chalk_rust_ir::TraitDatum<chalk_ir::family::ChalkIr>>;
132 139
133 #[salsa::invoke(crate::ty::traits::chalk::struct_datum_query)] 140 #[salsa::invoke(crate::ty::traits::chalk::struct_datum_query)]
134 fn struct_datum( 141 fn struct_datum(
135 &self, 142 &self,
136 krate: Crate, 143 krate: Crate,
137 struct_id: chalk_ir::StructId, 144 struct_id: chalk_ir::StructId,
138 ) -> Arc<chalk_rust_ir::StructDatum>; 145 ) -> Arc<chalk_rust_ir::StructDatum<chalk_ir::family::ChalkIr>>;
139 146
140 #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)] 147 #[salsa::invoke(crate::ty::traits::chalk::impl_datum_query)]
141 fn impl_datum(&self, krate: Crate, impl_id: chalk_ir::ImplId) -> Arc<chalk_rust_ir::ImplDatum>; 148 fn impl_datum(
149 &self,
150 krate: Crate,
151 impl_id: chalk_ir::ImplId,
152 ) -> Arc<chalk_rust_ir::ImplDatum<chalk_ir::family::ChalkIr>>;
153
154 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_value_query)]
155 fn associated_ty_value(
156 &self,
157 krate: Crate,
158 id: chalk_rust_ir::AssociatedTyValueId,
159 ) -> Arc<chalk_rust_ir::AssociatedTyValue<chalk_ir::family::ChalkIr>>;
142 160
143 #[salsa::invoke(crate::ty::traits::trait_solve_query)] 161 #[salsa::invoke(crate::ty::traits::trait_solve_query)]
144 fn trait_solve( 162 fn trait_solve(
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index fe083c0c6..2b59365fb 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -37,3 +37,9 @@ impl_intern_key!(TypeCtorId);
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct GlobalImplId(salsa::InternId); 38pub struct GlobalImplId(salsa::InternId);
39impl_intern_key!(GlobalImplId); 39impl_intern_key!(GlobalImplId);
40
41/// This exists just for Chalk, because it needs a unique ID for each associated
42/// type value in an impl (even synthetic ones).
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub struct AssocTyValueId(salsa::InternId);
45impl_intern_key!(AssocTyValueId);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index ff6030ac4..a54135188 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -224,8 +224,8 @@ impl TypeWalk for ProjectionTy {
224 self.parameters.walk(f); 224 self.parameters.walk(f);
225 } 225 }
226 226
227 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 227 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
228 self.parameters.walk_mut(f); 228 self.parameters.walk_mut_binders(f, binders);
229 } 229 }
230} 230}
231 231
@@ -291,6 +291,20 @@ pub enum Ty {
291#[derive(Clone, PartialEq, Eq, Debug, Hash)] 291#[derive(Clone, PartialEq, Eq, Debug, Hash)]
292pub struct Substs(Arc<[Ty]>); 292pub struct Substs(Arc<[Ty]>);
293 293
294impl TypeWalk for Substs {
295 fn walk(&self, f: &mut impl FnMut(&Ty)) {
296 for t in self.0.iter() {
297 t.walk(f);
298 }
299 }
300
301 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
302 for t in make_mut_slice(&mut self.0) {
303 t.walk_mut_binders(f, binders);
304 }
305 }
306}
307
294impl Substs { 308impl Substs {
295 pub fn empty() -> Substs { 309 pub fn empty() -> Substs {
296 Substs(Arc::new([])) 310 Substs(Arc::new([]))
@@ -304,18 +318,6 @@ impl Substs {
304 Substs(self.0[..std::cmp::min(self.0.len(), n)].into()) 318 Substs(self.0[..std::cmp::min(self.0.len(), n)].into())
305 } 319 }
306 320
307 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
308 for t in self.0.iter() {
309 t.walk(f);
310 }
311 }
312
313 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
314 for t in make_mut_slice(&mut self.0) {
315 t.walk_mut(f);
316 }
317 }
318
319 pub fn as_single(&self) -> &Ty { 321 pub fn as_single(&self) -> &Ty {
320 if self.0.len() != 1 { 322 if self.0.len() != 1 {
321 panic!("expected substs of len 1, got {:?}", self); 323 panic!("expected substs of len 1, got {:?}", self);
@@ -440,8 +442,8 @@ impl TypeWalk for TraitRef {
440 self.substs.walk(f); 442 self.substs.walk(f);
441 } 443 }
442 444
443 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 445 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
444 self.substs.walk_mut(f); 446 self.substs.walk_mut_binders(f, binders);
445 } 447 }
446} 448}
447 449
@@ -491,10 +493,12 @@ impl TypeWalk for GenericPredicate {
491 } 493 }
492 } 494 }
493 495
494 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 496 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
495 match self { 497 match self {
496 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), 498 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
497 GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f), 499 GenericPredicate::Projection(projection_pred) => {
500 projection_pred.walk_mut_binders(f, binders)
501 }
498 GenericPredicate::Error => {} 502 GenericPredicate::Error => {}
499 } 503 }
500 } 504 }
@@ -544,9 +548,9 @@ impl TypeWalk for FnSig {
544 } 548 }
545 } 549 }
546 550
547 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 551 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
548 for t in make_mut_slice(&mut self.params_and_return) { 552 for t in make_mut_slice(&mut self.params_and_return) {
549 t.walk_mut(f); 553 t.walk_mut_binders(f, binders);
550 } 554 }
551 } 555 }
552} 556}
@@ -671,7 +675,20 @@ impl Ty {
671/// types, similar to Chalk's `Fold` trait. 675/// types, similar to Chalk's `Fold` trait.
672pub trait TypeWalk { 676pub trait TypeWalk {
673 fn walk(&self, f: &mut impl FnMut(&Ty)); 677 fn walk(&self, f: &mut impl FnMut(&Ty));
674 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)); 678 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
679 self.walk_mut_binders(&mut |ty, _binders| f(ty), 0);
680 }
681 /// Walk the type, counting entered binders.
682 ///
683 /// `Ty::Bound` variables use DeBruijn indexing, which means that 0 refers
684 /// to the innermost binder, 1 to the next, etc.. So when we want to
685 /// substitute a certain bound variable, we can't just walk the whole type
686 /// and blindly replace each instance of a certain index; when we 'enter'
687 /// things that introduce new bound variables, we have to keep track of
688 /// that. Currently, the only thing that introduces bound variables on our
689 /// side are `Ty::Dyn` and `Ty::Opaque`, which each introduce a bound
690 /// variable for the self type.
691 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize);
675 692
676 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self 693 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
677 where 694 where
@@ -700,14 +717,22 @@ pub trait TypeWalk {
700 } 717 }
701 718
702 /// Substitutes `Ty::Bound` vars (as opposed to type parameters). 719 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
703 fn subst_bound_vars(self, substs: &Substs) -> Self 720 fn subst_bound_vars(mut self, substs: &Substs) -> Self
704 where 721 where
705 Self: Sized, 722 Self: Sized,
706 { 723 {
707 self.fold(&mut |ty| match ty { 724 self.walk_mut_binders(
708 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), 725 &mut |ty, binders| match ty {
709 ty => ty, 726 &mut Ty::Bound(idx) => {
710 }) 727 if idx as usize >= binders && (idx as usize - binders) < substs.len() {
728 *ty = substs.0[idx as usize - binders].clone();
729 }
730 }
731 _ => {}
732 },
733 0,
734 );
735 self
711 } 736 }
712 737
713 /// Shifts up `Ty::Bound` vars by `n`. 738 /// Shifts up `Ty::Bound` vars by `n`.
@@ -748,22 +773,22 @@ impl TypeWalk for Ty {
748 f(self); 773 f(self);
749 } 774 }
750 775
751 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 776 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
752 match self { 777 match self {
753 Ty::Apply(a_ty) => { 778 Ty::Apply(a_ty) => {
754 a_ty.parameters.walk_mut(f); 779 a_ty.parameters.walk_mut_binders(f, binders);
755 } 780 }
756 Ty::Projection(p_ty) => { 781 Ty::Projection(p_ty) => {
757 p_ty.parameters.walk_mut(f); 782 p_ty.parameters.walk_mut_binders(f, binders);
758 } 783 }
759 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 784 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
760 for p in make_mut_slice(predicates) { 785 for p in make_mut_slice(predicates) {
761 p.walk_mut(f); 786 p.walk_mut_binders(f, binders + 1);
762 } 787 }
763 } 788 }
764 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 789 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
765 } 790 }
766 f(self); 791 f(self, binders);
767 } 792 }
768} 793}
769 794
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index ca33cc7f8..64d9394cf 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -134,17 +134,19 @@ where
134} 134}
135 135
136impl<T> Canonicalized<T> { 136impl<T> Canonicalized<T> {
137 pub fn decanonicalize_ty(&self, ty: Ty) -> Ty { 137 pub fn decanonicalize_ty(&self, mut ty: Ty) -> Ty {
138 ty.fold(&mut |ty| match ty { 138 ty.walk_mut_binders(
139 Ty::Bound(idx) => { 139 &mut |ty, binders| match ty {
140 if (idx as usize) < self.free_vars.len() { 140 &mut Ty::Bound(idx) => {
141 Ty::Infer(self.free_vars[idx as usize]) 141 if idx as usize >= binders && (idx as usize - binders) < self.free_vars.len() {
142 } else { 142 *ty = Ty::Infer(self.free_vars[idx as usize - binders]);
143 Ty::Bound(idx) 143 }
144 } 144 }
145 } 145 _ => {}
146 ty => ty, 146 },
147 }) 147 0,
148 );
149 ty
148 } 150 }
149 151
150 pub fn apply_solution( 152 pub fn apply_solution(
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 9aad2d3fe..d20aeaacf 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -228,14 +228,10 @@ fn iterate_trait_method_candidates<T>(
228 'traits: for t in traits { 228 'traits: for t in traits {
229 let data = t.trait_data(db); 229 let data = t.trait_data(db);
230 230
231 // FIXME this is a bit of a hack, since Chalk should say the same thing
232 // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
233 let inherently_implemented = ty.value.inherent_trait() == Some(t);
234
235 // we'll be lazy about checking whether the type implements the 231 // we'll be lazy about checking whether the type implements the
236 // trait, but if we find out it doesn't, we'll skip the rest of the 232 // trait, but if we find out it doesn't, we'll skip the rest of the
237 // iteration 233 // iteration
238 let mut known_implemented = inherently_implemented; 234 let mut known_implemented = false;
239 for &item in data.items() { 235 for &item in data.items() {
240 if !is_valid_candidate(db, name, mode, item) { 236 if !is_valid_candidate(db, name, mode, item) {
241 continue; 237 continue;
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 9a26e02fa..ca1693679 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3983,11 +3983,11 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
3983 [180; 183) 'bar': fn bar() -> impl Trait<u64> 3983 [180; 183) 'bar': fn bar() -> impl Trait<u64>
3984 [180; 185) 'bar()': impl Trait<u64> 3984 [180; 185) 'bar()': impl Trait<u64>
3985 [191; 192) 'x': impl Trait<u64> 3985 [191; 192) 'x': impl Trait<u64>
3986 [191; 198) 'x.foo()': {unknown} 3986 [191; 198) 'x.foo()': u64
3987 [204; 205) 'y': &impl Trait<u64> 3987 [204; 205) 'y': &impl Trait<u64>
3988 [204; 211) 'y.foo()': {unknown} 3988 [204; 211) 'y.foo()': u64
3989 [217; 218) 'z': impl Trait<u64> 3989 [217; 218) 'z': impl Trait<u64>
3990 [217; 224) 'z.foo()': {unknown} 3990 [217; 224) 'z.foo()': u64
3991 [230; 231) 'x': impl Trait<u64> 3991 [230; 231) 'x': impl Trait<u64>
3992 [230; 238) 'x.foo2()': i64 3992 [230; 238) 'x.foo2()': i64
3993 [244; 245) 'y': &impl Trait<u64> 3993 [244; 245) 'y': &impl Trait<u64>
@@ -4033,11 +4033,11 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
4033 [177; 180) 'bar': fn bar() -> dyn Trait<u64> 4033 [177; 180) 'bar': fn bar() -> dyn Trait<u64>
4034 [177; 182) 'bar()': dyn Trait<u64> 4034 [177; 182) 'bar()': dyn Trait<u64>
4035 [188; 189) 'x': dyn Trait<u64> 4035 [188; 189) 'x': dyn Trait<u64>
4036 [188; 195) 'x.foo()': {unknown} 4036 [188; 195) 'x.foo()': u64
4037 [201; 202) 'y': &dyn Trait<u64> 4037 [201; 202) 'y': &dyn Trait<u64>
4038 [201; 208) 'y.foo()': {unknown} 4038 [201; 208) 'y.foo()': u64
4039 [214; 215) 'z': dyn Trait<u64> 4039 [214; 215) 'z': dyn Trait<u64>
4040 [214; 221) 'z.foo()': {unknown} 4040 [214; 221) 'z.foo()': u64
4041 [227; 228) 'x': dyn Trait<u64> 4041 [227; 228) 'x': dyn Trait<u64>
4042 [227; 235) 'x.foo2()': i64 4042 [227; 235) 'x.foo2()': i64
4043 [241; 242) 'y': &dyn Trait<u64> 4043 [241; 242) 'y': &dyn Trait<u64>
@@ -4185,6 +4185,49 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
4185} 4185}
4186 4186
4187#[test] 4187#[test]
4188fn impl_trait_assoc_binding_projection_bug() {
4189 let (db, pos) = TestDB::with_position(
4190 r#"
4191//- /main.rs crate:main deps:std
4192pub trait Language {
4193 type Kind;
4194}
4195pub enum RustLanguage {}
4196impl Language for RustLanguage {
4197 type Kind = SyntaxKind;
4198}
4199struct SyntaxNode<L> {}
4200fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
4201
4202trait Clone {
4203 fn clone(&self) -> Self;
4204}
4205
4206fn api_walkthrough() {
4207 for node in foo() {
4208 node.clone()<|>;
4209 }
4210}
4211
4212//- /std.rs crate:std
4213#[prelude_import] use iter::*;
4214mod iter {
4215 trait IntoIterator {
4216 type Item;
4217 }
4218 trait Iterator {
4219 type Item;
4220 }
4221 impl<T: Iterator> IntoIterator for T {
4222 type Item = <T as Iterator>::Item;
4223 }
4224}
4225"#,
4226 );
4227 assert_eq!("{unknown}", type_at_pos(&db, pos));
4228}
4229
4230#[test]
4188fn projection_eq_within_chalk() { 4231fn projection_eq_within_chalk() {
4189 // std::env::set_var("CHALK_DEBUG", "1"); 4232 // std::env::set_var("CHALK_DEBUG", "1");
4190 assert_snapshot!( 4233 assert_snapshot!(
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 4f1eab150..45f725438 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -8,7 +8,7 @@ use ra_prof::profile;
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 10use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
11use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait}; 11use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait, TypeAlias};
12 12
13use self::chalk::{from_chalk, ToChalk}; 13use self::chalk::{from_chalk, ToChalk};
14 14
@@ -17,7 +17,7 @@ pub(crate) mod chalk;
17#[derive(Debug, Clone)] 17#[derive(Debug, Clone)]
18pub struct TraitSolver { 18pub struct TraitSolver {
19 krate: Crate, 19 krate: Crate,
20 inner: Arc<Mutex<chalk_solve::Solver>>, 20 inner: Arc<Mutex<chalk_solve::Solver<ChalkIr>>>,
21} 21}
22 22
23/// We need eq for salsa 23/// We need eq for salsa
@@ -34,7 +34,7 @@ impl TraitSolver {
34 &self, 34 &self,
35 db: &impl HirDatabase, 35 db: &impl HirDatabase,
36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>, 36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>,
37 ) -> Option<chalk_solve::Solution> { 37 ) -> Option<chalk_solve::Solution<ChalkIr>> {
38 let context = ChalkContext { db, krate: self.krate }; 38 let context = ChalkContext { db, krate: self.krate };
39 debug!("solve goal: {:?}", goal); 39 debug!("solve goal: {:?}", goal);
40 let mut solver = match self.inner.lock() { 40 let mut solver = match self.inner.lock() {
@@ -165,9 +165,9 @@ impl TypeWalk for ProjectionPredicate {
165 self.ty.walk(f); 165 self.ty.walk(f);
166 } 166 }
167 167
168 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 168 fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize) {
169 self.projection_ty.walk_mut(f); 169 self.projection_ty.walk_mut_binders(f, binders);
170 self.ty.walk_mut(f); 170 self.ty.walk_mut_binders(f, binders);
171 } 171 }
172} 172}
173 173
@@ -188,6 +188,7 @@ pub(crate) fn trait_solve_query(
188 } 188 }
189 189
190 let canonical = goal.to_chalk(db).cast(); 190 let canonical = goal.to_chalk(db).cast();
191
191 // We currently don't deal with universes (I think / hope they're not yet 192 // We currently don't deal with universes (I think / hope they're not yet
192 // relevant for our use cases?) 193 // relevant for our use cases?)
193 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 194 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
@@ -195,7 +196,10 @@ pub(crate) fn trait_solve_query(
195 solution.map(|solution| solution_from_chalk(db, solution)) 196 solution.map(|solution| solution_from_chalk(db, solution))
196} 197}
197 198
198fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { 199fn solution_from_chalk(
200 db: &impl HirDatabase,
201 solution: chalk_solve::Solution<ChalkIr>,
202) -> Solution {
199 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| { 203 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| {
200 let value = subst 204 let value = subst
201 .value 205 .value
@@ -300,3 +304,14 @@ pub enum Impl {
300 /// Closure types implement the Fn traits synthetically. 304 /// Closure types implement the Fn traits synthetically.
301 ClosureFnTraitImpl(ClosureFnTraitImplData), 305 ClosureFnTraitImpl(ClosureFnTraitImplData),
302} 306}
307
308/// An associated type value. Usually this comes from a `type` declaration
309/// inside an impl block, but for built-in impls we have to synthesize it.
310/// (We only need this because Chalk wants a unique ID for each of these.)
311#[derive(Debug, Clone, PartialEq, Eq, Hash)]
312pub enum AssocTyValue {
313 /// A normal assoc type value from an impl block.
314 TypeAlias(TypeAlias),
315 /// The output type of the Fn trait implementation.
316 ClosureFnTraitImplOutput(ClosureFnTraitImplData),
317}
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 68304b950..9bf93981a 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -7,22 +7,19 @@ use chalk_ir::{
7 cast::Cast, family::ChalkIr, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId, 7 cast::Cast, family::ChalkIr, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId,
8 TypeKindId, TypeName, UniverseIndex, 8 TypeKindId, TypeName, UniverseIndex,
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11 11
12use hir_expand::name; 12use hir_expand::name;
13 13
14use ra_db::salsa::{InternId, InternKey}; 14use ra_db::salsa::{InternId, InternKey};
15 15
16use super::{Canonical, ChalkContext, Impl, Obligation}; 16use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
17use crate::{ 17use crate::{
18 db::HirDatabase, 18 db::HirDatabase,
19 generics::{GenericDef, HasGenericParams}, 19 generics::{GenericDef, HasGenericParams},
20 ty::display::HirDisplay, 20 ty::display::HirDisplay,
21 ty::{ 21 ty::{ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk},
22 ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 22 Crate, HasBody, ImplBlock, Trait, TypeAlias,
23 TypeWalk,
24 },
25 AssocItem, Crate, HasBody, ImplBlock, Trait, TypeAlias,
26}; 23};
27 24
28/// This represents a trait whose name we could not resolve. 25/// This represents a trait whose name we could not resolve.
@@ -59,29 +56,36 @@ impl ToChalk for Ty {
59 } 56 }
60 }; 57 };
61 let parameters = apply_ty.parameters.to_chalk(db); 58 let parameters = apply_ty.parameters.to_chalk(db);
62 chalk_ir::ApplicationTy { name, parameters }.cast() 59 chalk_ir::ApplicationTy { name, parameters }.cast().intern()
63 } 60 }
64 Ty::Projection(proj_ty) => { 61 Ty::Projection(proj_ty) => {
65 let associated_ty_id = proj_ty.associated_ty.to_chalk(db); 62 let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
66 let parameters = proj_ty.parameters.to_chalk(db); 63 let parameters = proj_ty.parameters.to_chalk(db);
67 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast() 64 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern()
68 } 65 }
69 Ty::Param { idx, .. } => { 66 Ty::Param { idx, .. } => {
70 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>() 67 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>()
71 } 68 }
72 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), 69 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(),
73 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 70 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
74 // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed 71 Ty::Dyn(predicates) => {
75 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { 72 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect();
73 chalk_ir::TyData::Dyn(make_binders(where_clauses, 1)).intern()
74 }
75 Ty::Opaque(predicates) => {
76 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect();
77 chalk_ir::TyData::Opaque(make_binders(where_clauses, 1)).intern()
78 }
79 Ty::Unknown => {
76 let parameters = Vec::new(); 80 let parameters = Vec::new();
77 let name = TypeName::Error; 81 let name = TypeName::Error;
78 chalk_ir::ApplicationTy { name, parameters }.cast() 82 chalk_ir::ApplicationTy { name, parameters }.cast().intern()
79 } 83 }
80 } 84 }
81 } 85 }
82 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self { 86 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self {
83 match chalk { 87 match chalk.data().clone() {
84 chalk_ir::Ty::Apply(apply_ty) => { 88 chalk_ir::TyData::Apply(apply_ty) => {
85 // FIXME this is kind of hacky due to the fact that 89 // FIXME this is kind of hacky due to the fact that
86 // TypeName::Placeholder is a Ty::Param on our side 90 // TypeName::Placeholder is a Ty::Param on our side
87 match apply_ty.name { 91 match apply_ty.name {
@@ -104,21 +108,21 @@ impl ToChalk for Ty {
104 } 108 }
105 } 109 }
106 } 110 }
107 chalk_ir::Ty::Projection(proj) => { 111 chalk_ir::TyData::Projection(proj) => {
108 let associated_ty = from_chalk(db, proj.associated_ty_id); 112 let associated_ty = from_chalk(db, proj.associated_ty_id);
109 let parameters = from_chalk(db, proj.parameters); 113 let parameters = from_chalk(db, proj.parameters);
110 Ty::Projection(ProjectionTy { associated_ty, parameters }) 114 Ty::Projection(ProjectionTy { associated_ty, parameters })
111 } 115 }
112 chalk_ir::Ty::ForAll(_) => unimplemented!(), 116 chalk_ir::TyData::ForAll(_) => unimplemented!(),
113 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), 117 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32),
114 chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown, 118 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
115 chalk_ir::Ty::Dyn(where_clauses) => { 119 chalk_ir::TyData::Dyn(where_clauses) => {
116 assert_eq!(where_clauses.binders.len(), 1); 120 assert_eq!(where_clauses.binders.len(), 1);
117 let predicates = 121 let predicates =
118 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 122 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
119 Ty::Dyn(predicates) 123 Ty::Dyn(predicates)
120 } 124 }
121 chalk_ir::Ty::Opaque(where_clauses) => { 125 chalk_ir::TyData::Opaque(where_clauses) => {
122 assert_eq!(where_clauses.binders.len(), 1); 126 assert_eq!(where_clauses.binders.len(), 1);
123 let predicates = 127 let predicates =
124 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 128 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
@@ -211,6 +215,21 @@ impl ToChalk for TypeAlias {
211 } 215 }
212} 216}
213 217
218impl ToChalk for AssocTyValue {
219 type Chalk = chalk_rust_ir::AssociatedTyValueId;
220
221 fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValueId {
222 db.intern_assoc_ty_value(self).into()
223 }
224
225 fn from_chalk(
226 db: &impl HirDatabase,
227 assoc_ty_value_id: chalk_rust_ir::AssociatedTyValueId,
228 ) -> AssocTyValue {
229 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into())
230 }
231}
232
214impl ToChalk for GenericPredicate { 233impl ToChalk for GenericPredicate {
215 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>; 234 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>;
216 235
@@ -399,20 +418,20 @@ fn convert_where_clauses(
399 result 418 result
400} 419}
401 420
402impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> 421impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB>
403where 422where
404 DB: HirDatabase, 423 DB: HirDatabase,
405{ 424{
406 fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum> { 425 fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum<ChalkIr>> {
407 self.db.associated_ty_data(id) 426 self.db.associated_ty_data(id)
408 } 427 }
409 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { 428 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum<ChalkIr>> {
410 self.db.trait_datum(self.krate, trait_id) 429 self.db.trait_datum(self.krate, trait_id)
411 } 430 }
412 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { 431 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum<ChalkIr>> {
413 self.db.struct_datum(self.krate, struct_id) 432 self.db.struct_datum(self.krate, struct_id)
414 } 433 }
415 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> { 434 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum<ChalkIr>> {
416 self.db.impl_datum(self.krate, impl_id) 435 self.db.impl_datum(self.krate, impl_id)
417 } 436 }
418 fn impls_for_trait( 437 fn impls_for_trait(
@@ -462,13 +481,11 @@ where
462 fn type_name(&self, _id: TypeKindId) -> Identifier { 481 fn type_name(&self, _id: TypeKindId) -> Identifier {
463 unimplemented!() 482 unimplemented!()
464 } 483 }
465 fn split_projection<'p>( 484 fn associated_ty_value(
466 &self, 485 &self,
467 projection: &'p chalk_ir::ProjectionTy<ChalkIr>, 486 id: chalk_rust_ir::AssociatedTyValueId,
468 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter<ChalkIr>], &'p [Parameter<ChalkIr>]) { 487 ) -> Arc<AssociatedTyValue<ChalkIr>> {
469 debug!("split_projection {:?}", projection); 488 self.db.associated_ty_value(self.krate, id)
470 // we don't support GATs, so I think this should always be correct currently
471 (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[])
472 } 489 }
473 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> { 490 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> {
474 vec![] 491 vec![]
@@ -485,7 +502,7 @@ where
485pub(crate) fn associated_ty_data_query( 502pub(crate) fn associated_ty_data_query(
486 db: &impl HirDatabase, 503 db: &impl HirDatabase,
487 id: TypeId, 504 id: TypeId,
488) -> Arc<AssociatedTyDatum> { 505) -> Arc<AssociatedTyDatum<ChalkIr>> {
489 debug!("associated_ty_data {:?}", id); 506 debug!("associated_ty_data {:?}", id);
490 let type_alias: TypeAlias = from_chalk(db, id); 507 let type_alias: TypeAlias = from_chalk(db, id);
491 let trait_ = match type_alias.container(db) { 508 let trait_ = match type_alias.container(db) {
@@ -493,19 +510,16 @@ pub(crate) fn associated_ty_data_query(
493 _ => panic!("associated type not in trait"), 510 _ => panic!("associated type not in trait"),
494 }; 511 };
495 let generic_params = type_alias.generic_params(db); 512 let generic_params = type_alias.generic_params(db);
496 let parameter_kinds = generic_params 513 let bound_data = chalk_rust_ir::AssociatedTyDatumBound {
497 .params_including_parent() 514 // FIXME add bounds and where clauses
498 .into_iter() 515 bounds: vec![],
499 .map(|p| chalk_ir::ParameterKind::Ty(lalrpop_intern::intern(&p.name.to_string()))) 516 where_clauses: vec![],
500 .collect(); 517 };
501 let datum = AssociatedTyDatum { 518 let datum = AssociatedTyDatum {
502 trait_id: trait_.to_chalk(db), 519 trait_id: trait_.to_chalk(db),
503 id, 520 id,
504 name: lalrpop_intern::intern(&type_alias.name(db).to_string()), 521 name: lalrpop_intern::intern(&type_alias.name(db).to_string()),
505 parameter_kinds, 522 binders: make_binders(bound_data, generic_params.count_params_including_parent()),
506 // FIXME add bounds and where clauses
507 bounds: vec![],
508 where_clauses: vec![],
509 }; 523 };
510 Arc::new(datum) 524 Arc::new(datum)
511} 525}
@@ -514,17 +528,10 @@ pub(crate) fn trait_datum_query(
514 db: &impl HirDatabase, 528 db: &impl HirDatabase,
515 krate: Crate, 529 krate: Crate,
516 trait_id: chalk_ir::TraitId, 530 trait_id: chalk_ir::TraitId,
517) -> Arc<TraitDatum> { 531) -> Arc<TraitDatum<ChalkIr>> {
518 debug!("trait_datum {:?}", trait_id); 532 debug!("trait_datum {:?}", trait_id);
519 if trait_id == UNKNOWN_TRAIT { 533 if trait_id == UNKNOWN_TRAIT {
520 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { 534 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() };
521 trait_ref: chalk_ir::TraitRef {
522 trait_id: UNKNOWN_TRAIT,
523 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
524 },
525 associated_ty_ids: Vec::new(),
526 where_clauses: Vec::new(),
527 };
528 535
529 let flags = chalk_rust_ir::TraitFlags { 536 let flags = chalk_rust_ir::TraitFlags {
530 auto: false, 537 auto: false,
@@ -532,18 +539,24 @@ pub(crate) fn trait_datum_query(
532 upstream: true, 539 upstream: true,
533 fundamental: false, 540 fundamental: false,
534 non_enumerable: true, 541 non_enumerable: true,
542 coinductive: false,
535 }; 543 };
536 return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1), flags }); 544 return Arc::new(TraitDatum {
545 id: trait_id,
546 binders: make_binders(trait_datum_bound, 1),
547 flags,
548 associated_ty_ids: vec![],
549 });
537 } 550 }
538 let trait_: Trait = from_chalk(db, trait_id); 551 let trait_: Trait = from_chalk(db, trait_id);
539 debug!("trait {:?} = {:?}", trait_id, trait_.name(db)); 552 debug!("trait {:?} = {:?}", trait_id, trait_.name(db));
540 let generic_params = trait_.generic_params(db); 553 let generic_params = trait_.generic_params(db);
541 let bound_vars = Substs::bound_vars(&generic_params); 554 let bound_vars = Substs::bound_vars(&generic_params);
542 let trait_ref = trait_.trait_ref(db).subst(&bound_vars).to_chalk(db);
543 let flags = chalk_rust_ir::TraitFlags { 555 let flags = chalk_rust_ir::TraitFlags {
544 auto: trait_.is_auto(db), 556 auto: trait_.is_auto(db),
545 upstream: trait_.module(db).krate() != krate, 557 upstream: trait_.module(db).krate() != krate,
546 non_enumerable: true, 558 non_enumerable: true,
559 coinductive: false, // only relevant for Chalk testing
547 // FIXME set these flags correctly 560 // FIXME set these flags correctly
548 marker: false, 561 marker: false,
549 fundamental: false, 562 fundamental: false,
@@ -558,10 +571,13 @@ pub(crate) fn trait_datum_query(
558 }) 571 })
559 .map(|type_alias| type_alias.to_chalk(db)) 572 .map(|type_alias| type_alias.to_chalk(db))
560 .collect(); 573 .collect();
561 let trait_datum_bound = 574 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses };
562 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, associated_ty_ids }; 575 let trait_datum = TraitDatum {
563 let trait_datum = 576 id: trait_id,
564 TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()), flags }; 577 binders: make_binders(trait_datum_bound, bound_vars.len()),
578 flags,
579 associated_ty_ids,
580 };
565 Arc::new(trait_datum) 581 Arc::new(trait_datum)
566} 582}
567 583
@@ -569,7 +585,7 @@ pub(crate) fn struct_datum_query(
569 db: &impl HirDatabase, 585 db: &impl HirDatabase,
570 krate: Crate, 586 krate: Crate,
571 struct_id: chalk_ir::StructId, 587 struct_id: chalk_ir::StructId,
572) -> Arc<StructDatum> { 588) -> Arc<StructDatum<ChalkIr>> {
573 debug!("struct_datum {:?}", struct_id); 589 debug!("struct_datum {:?}", struct_id);
574 let type_ctor: TypeCtor = from_chalk(db, struct_id); 590 let type_ctor: TypeCtor = from_chalk(db, struct_id);
575 debug!("struct {:?} = {:?}", struct_id, type_ctor); 591 debug!("struct {:?} = {:?}", struct_id, type_ctor);
@@ -588,17 +604,12 @@ pub(crate) fn struct_datum_query(
588 // FIXME set fundamental flag correctly 604 // FIXME set fundamental flag correctly
589 fundamental: false, 605 fundamental: false,
590 }; 606 };
591 let self_ty = chalk_ir::ApplicationTy {
592 name: TypeName::TypeKindId(type_ctor.to_chalk(db).into()),
593 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
594 };
595 let struct_datum_bound = chalk_rust_ir::StructDatumBound { 607 let struct_datum_bound = chalk_rust_ir::StructDatumBound {
596 self_ty,
597 fields: Vec::new(), // FIXME add fields (only relevant for auto traits) 608 fields: Vec::new(), // FIXME add fields (only relevant for auto traits)
598 where_clauses, 609 where_clauses,
599 flags,
600 }; 610 };
601 let struct_datum = StructDatum { binders: make_binders(struct_datum_bound, num_params) }; 611 let struct_datum =
612 StructDatum { id: struct_id, binders: make_binders(struct_datum_bound, num_params), flags };
602 Arc::new(struct_datum) 613 Arc::new(struct_datum)
603} 614}
604 615
@@ -606,16 +617,15 @@ pub(crate) fn impl_datum_query(
606 db: &impl HirDatabase, 617 db: &impl HirDatabase,
607 krate: Crate, 618 krate: Crate,
608 impl_id: ImplId, 619 impl_id: ImplId,
609) -> Arc<ImplDatum> { 620) -> Arc<ImplDatum<ChalkIr>> {
610 let _p = ra_prof::profile("impl_datum"); 621 let _p = ra_prof::profile("impl_datum");
611 debug!("impl_datum {:?}", impl_id); 622 debug!("impl_datum {:?}", impl_id);
612 let impl_: Impl = from_chalk(db, impl_id); 623 let impl_: Impl = from_chalk(db, impl_id);
613 match impl_ { 624 match impl_ {
614 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), 625 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
615 Impl::ClosureFnTraitImpl(data) => { 626 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
616 closure_fn_trait_impl_datum(db, krate, impl_id, data).unwrap_or_else(invalid_impl_datum)
617 }
618 } 627 }
628 .unwrap_or_else(invalid_impl_datum)
619} 629}
620 630
621fn impl_block_datum( 631fn impl_block_datum(
@@ -623,13 +633,11 @@ fn impl_block_datum(
623 krate: Crate, 633 krate: Crate,
624 impl_id: ImplId, 634 impl_id: ImplId,
625 impl_block: ImplBlock, 635 impl_block: ImplBlock,
626) -> Arc<ImplDatum> { 636) -> Option<Arc<ImplDatum<ChalkIr>>> {
627 let generic_params = impl_block.generic_params(db); 637 let generic_params = impl_block.generic_params(db);
628 let bound_vars = Substs::bound_vars(&generic_params); 638 let bound_vars = Substs::bound_vars(&generic_params);
629 let trait_ref = impl_block 639 let trait_ref = impl_block.target_trait_ref(db)?.subst(&bound_vars);
630 .target_trait_ref(db) 640 let trait_ = trait_ref.trait_;
631 .expect("FIXME handle unresolved impl block trait ref")
632 .subst(&bound_vars);
633 let impl_type = if impl_block.krate(db) == krate { 641 let impl_type = if impl_block.krate(db) == krate {
634 chalk_rust_ir::ImplType::Local 642 chalk_rust_ir::ImplType::Local
635 } else { 643 } else {
@@ -644,28 +652,7 @@ fn impl_block_datum(
644 trait_ref.display(db), 652 trait_ref.display(db),
645 where_clauses 653 where_clauses
646 ); 654 );
647 let trait_ = trait_ref.trait_;
648 let trait_ref = trait_ref.to_chalk(db); 655 let trait_ref = trait_ref.to_chalk(db);
649 let associated_ty_values = impl_block
650 .items(db)
651 .into_iter()
652 .filter_map(|item| match item {
653 AssocItem::TypeAlias(t) => Some(t),
654 _ => None,
655 })
656 .filter_map(|t| {
657 let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?;
658 let ty = db.type_for_def(t.into(), Namespace::Types).subst(&bound_vars);
659 Some(chalk_rust_ir::AssociatedTyValue {
660 impl_id,
661 associated_ty_id: assoc_ty.to_chalk(db),
662 value: chalk_ir::Binders {
663 value: chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) },
664 binders: vec![], // we don't support GATs yet
665 },
666 })
667 })
668 .collect();
669 656
670 let polarity = if negative { 657 let polarity = if negative {
671 chalk_rust_ir::Polarity::Negative 658 chalk_rust_ir::Polarity::Negative
@@ -673,31 +660,41 @@ fn impl_block_datum(
673 chalk_rust_ir::Polarity::Positive 660 chalk_rust_ir::Polarity::Positive
674 }; 661 };
675 662
676 let impl_datum_bound = 663 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses };
677 chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses, associated_ty_values }; 664 let associated_ty_value_ids = impl_block
665 .items(db)
666 .into_iter()
667 .filter_map(|item| match item {
668 crate::AssocItem::TypeAlias(type_alias) => Some(type_alias),
669 _ => None,
670 })
671 .filter(|type_alias| {
672 // don't include associated types that don't exist in the trait
673 trait_.associated_type_by_name(db, &type_alias.name(db)).is_some()
674 })
675 .map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db))
676 .collect();
678 debug!("impl_datum: {:?}", impl_datum_bound); 677 debug!("impl_datum: {:?}", impl_datum_bound);
679 let impl_datum = ImplDatum { 678 let impl_datum = ImplDatum {
680 binders: make_binders(impl_datum_bound, bound_vars.len()), 679 binders: make_binders(impl_datum_bound, bound_vars.len()),
681 impl_type, 680 impl_type,
682 polarity, 681 polarity,
682 associated_ty_value_ids,
683 }; 683 };
684 Arc::new(impl_datum) 684 Some(Arc::new(impl_datum))
685} 685}
686 686
687fn invalid_impl_datum() -> Arc<ImplDatum> { 687fn invalid_impl_datum() -> Arc<ImplDatum<ChalkIr>> {
688 let trait_ref = chalk_ir::TraitRef { 688 let trait_ref = chalk_ir::TraitRef {
689 trait_id: UNKNOWN_TRAIT, 689 trait_id: UNKNOWN_TRAIT,
690 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()], 690 parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()],
691 };
692 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
693 trait_ref,
694 where_clauses: Vec::new(),
695 associated_ty_values: Vec::new(),
696 }; 691 };
692 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses: Vec::new() };
697 let impl_datum = ImplDatum { 693 let impl_datum = ImplDatum {
698 binders: make_binders(impl_datum_bound, 1), 694 binders: make_binders(impl_datum_bound, 1),
699 impl_type: chalk_rust_ir::ImplType::External, 695 impl_type: chalk_rust_ir::ImplType::External,
700 polarity: chalk_rust_ir::Polarity::Positive, 696 polarity: chalk_rust_ir::Polarity::Positive,
697 associated_ty_value_ids: Vec::new(),
701 }; 698 };
702 Arc::new(impl_datum) 699 Arc::new(impl_datum)
703} 700}
@@ -705,15 +702,19 @@ fn invalid_impl_datum() -> Arc<ImplDatum> {
705fn closure_fn_trait_impl_datum( 702fn closure_fn_trait_impl_datum(
706 db: &impl HirDatabase, 703 db: &impl HirDatabase,
707 krate: Crate, 704 krate: Crate,
708 impl_id: ImplId,
709 data: super::ClosureFnTraitImplData, 705 data: super::ClosureFnTraitImplData,
710) -> Option<Arc<ImplDatum>> { 706) -> Option<Arc<ImplDatum<ChalkIr>>> {
711 // for some closure |X, Y| -> Z: 707 // for some closure |X, Y| -> Z:
712 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } 708 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
713 709
714 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
715 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait 710 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
716 711
712 // validate FnOnce trait, since we need it in the assoc ty value definition
713 // and don't want to return a valid value only to find out later that FnOnce
714 // is broken
715 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
716 fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?;
717
717 let num_args: u16 = match &data.def.body(db)[data.expr] { 718 let num_args: u16 = match &data.def.body(db)[data.expr] {
718 crate::expr::Expr::Lambda { args, .. } => args.len() as u16, 719 crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
719 _ => { 720 _ => {
@@ -726,7 +727,6 @@ fn closure_fn_trait_impl_datum(
726 TypeCtor::Tuple { cardinality: num_args }, 727 TypeCtor::Tuple { cardinality: num_args },
727 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(), 728 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
728 ); 729 );
729 let output_ty = Ty::Bound(num_args.into());
730 let sig_ty = Ty::apply( 730 let sig_ty = Ty::apply(
731 TypeCtor::FnPtr { num_args }, 731 TypeCtor::FnPtr { num_args },
732 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(), 732 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
@@ -739,32 +739,99 @@ fn closure_fn_trait_impl_datum(
739 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), 739 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
740 }; 740 };
741 741
742 let output_ty_id = fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?; 742 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
743
744 let output_ty_value = chalk_rust_ir::AssociatedTyValue {
745 associated_ty_id: output_ty_id.to_chalk(db),
746 impl_id,
747 value: make_binders(
748 chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) },
749 0,
750 ),
751 };
752 743
753 let impl_type = chalk_rust_ir::ImplType::External; 744 let impl_type = chalk_rust_ir::ImplType::External;
754 745
755 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 746 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
756 trait_ref: trait_ref.to_chalk(db), 747 trait_ref: trait_ref.to_chalk(db),
757 where_clauses: Vec::new(), 748 where_clauses: Vec::new(),
758 associated_ty_values: vec![output_ty_value],
759 }; 749 };
760 let impl_datum = ImplDatum { 750 let impl_datum = ImplDatum {
761 binders: make_binders(impl_datum_bound, num_args as usize + 1), 751 binders: make_binders(impl_datum_bound, num_args as usize + 1),
762 impl_type, 752 impl_type,
763 polarity: chalk_rust_ir::Polarity::Positive, 753 polarity: chalk_rust_ir::Polarity::Positive,
754 associated_ty_value_ids: vec![output_ty_id],
764 }; 755 };
765 Some(Arc::new(impl_datum)) 756 Some(Arc::new(impl_datum))
766} 757}
767 758
759pub(crate) fn associated_ty_value_query(
760 db: &impl HirDatabase,
761 krate: Crate,
762 id: chalk_rust_ir::AssociatedTyValueId,
763) -> Arc<chalk_rust_ir::AssociatedTyValue<ChalkIr>> {
764 let data: AssocTyValue = from_chalk(db, id);
765 match data {
766 AssocTyValue::TypeAlias(type_alias) => {
767 type_alias_associated_ty_value(db, krate, type_alias)
768 }
769 AssocTyValue::ClosureFnTraitImplOutput(data) => {
770 closure_fn_trait_output_assoc_ty_value(db, krate, data)
771 }
772 }
773}
774
775fn type_alias_associated_ty_value(
776 db: &impl HirDatabase,
777 _krate: Crate,
778 type_alias: TypeAlias,
779) -> Arc<AssociatedTyValue<ChalkIr>> {
780 let impl_block = type_alias.impl_block(db).expect("assoc ty value should be in impl");
781 let impl_id = Impl::ImplBlock(impl_block).to_chalk(db);
782 let trait_ = impl_block
783 .target_trait_ref(db)
784 .expect("assoc ty value should not exist") // we don't return any assoc ty values if the impl'd trait can't be resolved
785 .trait_;
786 let assoc_ty = trait_
787 .associated_type_by_name(db, &type_alias.name(db))
788 .expect("assoc ty value should not exist"); // validated when building the impl data as well
789 let generic_params = impl_block.generic_params(db);
790 let bound_vars = Substs::bound_vars(&generic_params);
791 let ty = db.type_for_def(type_alias.into(), crate::ty::Namespace::Types).subst(&bound_vars);
792 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) };
793 let value = chalk_rust_ir::AssociatedTyValue {
794 impl_id,
795 associated_ty_id: assoc_ty.to_chalk(db),
796 value: make_binders(value_bound, bound_vars.len()),
797 };
798 Arc::new(value)
799}
800
801fn closure_fn_trait_output_assoc_ty_value(
802 db: &impl HirDatabase,
803 krate: Crate,
804 data: super::ClosureFnTraitImplData,
805) -> Arc<AssociatedTyValue<ChalkIr>> {
806 let impl_id = Impl::ClosureFnTraitImpl(data.clone()).to_chalk(db);
807
808 let num_args: u16 = match &data.def.body(db)[data.expr] {
809 crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
810 _ => {
811 log::warn!("closure for closure type {:?} not found", data);
812 0
813 }
814 };
815
816 let output_ty = Ty::Bound(num_args.into());
817
818 let fn_once_trait =
819 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
820
821 let output_ty_id = fn_once_trait
822 .associated_type_by_name(db, &name::OUTPUT_TYPE)
823 .expect("assoc ty value should not exist");
824
825 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
826
827 let value = chalk_rust_ir::AssociatedTyValue {
828 associated_ty_id: output_ty_id.to_chalk(db),
829 impl_id,
830 value: make_binders(value_bound, num_args as usize + 1),
831 };
832 Arc::new(value)
833}
834
768fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { 835fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
769 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; 836 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
770 match target { 837 match target {
@@ -803,3 +870,15 @@ impl From<crate::ids::GlobalImplId> for chalk_ir::ImplId {
803 chalk_ir::ImplId(id_to_chalk(impl_id)) 870 chalk_ir::ImplId(id_to_chalk(impl_id))
804 } 871 }
805} 872}
873
874impl From<chalk_rust_ir::AssociatedTyValueId> for crate::ids::AssocTyValueId {
875 fn from(id: chalk_rust_ir::AssociatedTyValueId) -> Self {
876 id_from_chalk(id.0)
877 }
878}
879
880impl From<crate::ids::AssocTyValueId> for chalk_rust_ir::AssociatedTyValueId {
881 fn from(assoc_ty_value_id: crate::ids::AssocTyValueId) -> Self {
882 chalk_rust_ir::AssociatedTyValueId(id_to_chalk(assoc_ty_value_id))
883 }
884}