aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs27
-rw-r--r--crates/ra_hir_ty/src/traits.rs7
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs72
3 files changed, 99 insertions, 7 deletions
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 81c5e6299..b3a2fc439 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -2094,6 +2094,33 @@ fn main() {
2094} 2094}
2095 2095
2096#[test] 2096#[test]
2097fn associated_type_bound() {
2098 let t = type_at(
2099 r#"
2100//- /main.rs
2101pub trait Trait {
2102 type Item: OtherTrait<u32>;
2103}
2104pub trait OtherTrait<T> {
2105 fn foo(&self) -> T;
2106}
2107
2108// this is just a workaround for chalk#234
2109pub struct S<T>;
2110impl<T: Trait> Trait for S<T> {
2111 type Item = <T as Trait>::Item;
2112}
2113
2114fn test<T: Trait>() {
2115 let y: <S<T> as Trait>::Item = no_matter;
2116 y.foo()<|>;
2117}
2118"#,
2119 );
2120 assert_eq!(t, "u32");
2121}
2122
2123#[test]
2097fn dyn_trait_through_chalk() { 2124fn dyn_trait_through_chalk() {
2098 let t = type_at( 2125 let t = type_at(
2099 r#" 2126 r#"
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 43d8d1e80..44fbdb197 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -194,13 +194,16 @@ fn solve(
194 } 194 }
195 remaining > 0 195 remaining > 0
196 }; 196 };
197 let mut solve = || solver.solve_limited(&context, goal, should_continue); 197 let mut solve = || {
198 let solution = solver.solve_limited(&context, goal, should_continue);
199 log::debug!("solve({:?}) => {:?}", goal, solution);
200 solution
201 };
198 // don't set the TLS for Chalk unless Chalk debugging is active, to make 202 // don't set the TLS for Chalk unless Chalk debugging is active, to make
199 // extra sure we only use it for debugging 203 // extra sure we only use it for debugging
200 let solution = 204 let solution =
201 if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; 205 if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() };
202 206
203 log::debug!("solve({:?}) => {:?}", goal, solution);
204 solution 207 solution
205} 208}
206 209
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index f6994a1f6..55eb0ffcb 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -673,6 +673,55 @@ fn convert_where_clauses(
673 result 673 result
674} 674}
675 675
676fn generic_predicate_to_inline_bound(
677 db: &dyn HirDatabase,
678 pred: &GenericPredicate,
679 self_ty: &Ty,
680) -> Option<chalk_rust_ir::InlineBound<Interner>> {
681 // An InlineBound is like a GenericPredicate, except the self type is left out.
682 // We don't have a special type for this, but Chalk does.
683 match pred {
684 GenericPredicate::Implemented(trait_ref) => {
685 if &trait_ref.substs[0] != self_ty {
686 // we can only convert predicates back to type bounds if they
687 // have the expected self type
688 return None;
689 }
690 let args_no_self = trait_ref.substs[1..]
691 .iter()
692 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
693 .collect();
694 let trait_bound =
695 chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self };
696 Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound))
697 }
698 GenericPredicate::Projection(proj) => {
699 if &proj.projection_ty.parameters[0] != self_ty {
700 return None;
701 }
702 let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container {
703 AssocContainerId::TraitId(t) => t,
704 _ => panic!("associated type not in trait"),
705 };
706 let args_no_self = proj.projection_ty.parameters[1..]
707 .iter()
708 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
709 .collect();
710 let alias_eq_bound = chalk_rust_ir::AliasEqBound {
711 value: proj.ty.clone().to_chalk(db),
712 trait_bound: chalk_rust_ir::TraitBound {
713 trait_id: trait_.to_chalk(db),
714 args_no_self,
715 },
716 associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db),
717 parameters: Vec::new(), // FIXME we don't support generic associated types yet
718 };
719 Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound))
720 }
721 GenericPredicate::Error => None,
722 }
723}
724
676impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { 725impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
677 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { 726 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
678 self.db.associated_ty_data(id) 727 self.db.associated_ty_data(id)
@@ -761,12 +810,25 @@ pub(crate) fn associated_ty_data_query(
761 AssocContainerId::TraitId(t) => t, 810 AssocContainerId::TraitId(t) => t,
762 _ => panic!("associated type not in trait"), 811 _ => panic!("associated type not in trait"),
763 }; 812 };
813
814 // Lower bounds -- we could/should maybe move this to a separate query in `lower`
815 let type_alias_data = db.type_alias_data(type_alias);
764 let generic_params = generics(db.upcast(), type_alias.into()); 816 let generic_params = generics(db.upcast(), type_alias.into());
765 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { 817 let bound_vars = Substs::bound_vars(&generic_params);
766 // FIXME add bounds and where clauses 818 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
767 bounds: vec![], 819 let ctx = crate::TyLoweringContext::new(db, &resolver)
768 where_clauses: vec![], 820 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
769 }; 821 let self_ty = Ty::Bound(crate::BoundVar::new(crate::DebruijnIndex::INNERMOST, 0));
822 let bounds = type_alias_data
823 .bounds
824 .iter()
825 .flat_map(|bound| GenericPredicate::from_type_bound(&ctx, bound, self_ty.clone()))
826 .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
827 .map(|bound| make_binders(bound.shifted_in(&Interner), 0))
828 .collect();
829
830 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
831 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
770 let datum = AssociatedTyDatum { 832 let datum = AssociatedTyDatum {
771 trait_id: trait_.to_chalk(db), 833 trait_id: trait_.to_chalk(db),
772 id, 834 id,