aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/data.rs18
-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
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs11
5 files changed, 119 insertions, 16 deletions
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index b3c91fea2..ccb682f9a 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -9,7 +9,8 @@ use hir_expand::{
9}; 9};
10use ra_prof::profile; 10use ra_prof::profile;
11use ra_syntax::ast::{ 11use ra_syntax::ast::{
12 self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner, 12 self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner,
13 VisibilityOwner,
13}; 14};
14 15
15use crate::{ 16use crate::{
@@ -110,6 +111,7 @@ pub struct TypeAliasData {
110 pub name: Name, 111 pub name: Name,
111 pub type_ref: Option<TypeRef>, 112 pub type_ref: Option<TypeRef>,
112 pub visibility: RawVisibility, 113 pub visibility: RawVisibility,
114 pub bounds: Vec<TypeBound>,
113} 115}
114 116
115impl TypeAliasData { 117impl TypeAliasData {
@@ -122,9 +124,17 @@ impl TypeAliasData {
122 let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); 124 let name = node.value.name().map_or_else(Name::missing, |n| n.as_name());
123 let type_ref = node.value.type_ref().map(TypeRef::from_ast); 125 let type_ref = node.value.type_ref().map(TypeRef::from_ast);
124 let vis_default = RawVisibility::default_for_container(loc.container); 126 let vis_default = RawVisibility::default_for_container(loc.container);
125 let visibility = 127 let visibility = RawVisibility::from_ast_with_default(
126 RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); 128 db,
127 Arc::new(TypeAliasData { name, type_ref, visibility }) 129 vis_default,
130 node.as_ref().map(|n| n.visibility()),
131 );
132 let bounds = if let Some(bound_list) = node.value.type_bound_list() {
133 bound_list.bounds().map(TypeBound::from_ast).collect()
134 } else {
135 Vec::new()
136 };
137 Arc::new(TypeAliasData { name, type_ref, visibility, bounds })
128 } 138 }
129} 139}
130 140
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,
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 9fb5cb058..31e9b22e7 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -607,12 +607,13 @@ impl<'a> TreeSink for TtTreeSink<'a> {
607 let text: SmolStr = match self.cursor.token_tree() { 607 let text: SmolStr = match self.cursor.token_tree() {
608 Some(tt::TokenTree::Leaf(leaf)) => { 608 Some(tt::TokenTree::Leaf(leaf)) => {
609 // Mark the range if needed 609 // Mark the range if needed
610 let id = match leaf { 610 let (text, id) = match leaf {
611 tt::Leaf::Ident(ident) => ident.id, 611 tt::Leaf::Ident(ident) => (ident.text.clone(), ident.id),
612 tt::Leaf::Punct(punct) => punct.id, 612 tt::Leaf::Punct(punct) => {
613 tt::Leaf::Literal(lit) => lit.id, 613 (SmolStr::new_inline_from_ascii(1, &[punct.char as u8]), punct.id)
614 }
615 tt::Leaf::Literal(lit) => (lit.text.clone(), lit.id),
614 }; 616 };
615 let text = SmolStr::new(format!("{}", leaf));
616 let range = TextRange::offset_len(self.text_pos, TextUnit::of_str(&text)); 617 let range = TextRange::offset_len(self.text_pos, TextUnit::of_str(&text));
617 self.token_map.insert(id, range); 618 self.token_map.insert(id, range);
618 self.cursor = self.cursor.bump(); 619 self.cursor = self.cursor.bump();