diff options
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 72 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 11 |
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 | }; |
10 | use ra_prof::profile; | 10 | use ra_prof::profile; |
11 | use ra_syntax::ast::{ | 11 | use 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 | ||
15 | use crate::{ | 16 | use 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 | ||
115 | impl TypeAliasData { | 117 | impl 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] |
2097 | fn associated_type_bound() { | ||
2098 | let t = type_at( | ||
2099 | r#" | ||
2100 | //- /main.rs | ||
2101 | pub trait Trait { | ||
2102 | type Item: OtherTrait<u32>; | ||
2103 | } | ||
2104 | pub trait OtherTrait<T> { | ||
2105 | fn foo(&self) -> T; | ||
2106 | } | ||
2107 | |||
2108 | // this is just a workaround for chalk#234 | ||
2109 | pub struct S<T>; | ||
2110 | impl<T: Trait> Trait for S<T> { | ||
2111 | type Item = <T as Trait>::Item; | ||
2112 | } | ||
2113 | |||
2114 | fn 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] | ||
2097 | fn dyn_trait_through_chalk() { | 2124 | fn 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 | ||
676 | fn 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 | |||
676 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | 725 | impl<'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(); |