aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir/src/generics.rs11
-rw-r--r--crates/ra_hir/src/resolve.rs7
-rw-r--r--crates/ra_hir/src/ty.rs4
-rw-r--r--crates/ra_hir/src/ty/lower.rs97
-rw-r--r--crates/ra_hir/src/ty/tests.rs64
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs6
7 files changed, 173 insertions, 23 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index f7f124904..05259dcbb 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -164,6 +164,13 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
164 #[salsa::invoke(crate::ty::callable_item_sig)] 164 #[salsa::invoke(crate::ty::callable_item_sig)]
165 fn callable_item_signature(&self, def: CallableDef) -> FnSig; 165 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
166 166
167 #[salsa::invoke(crate::ty::generic_predicates_for_param_query)]
168 fn generic_predicates_for_param(
169 &self,
170 def: GenericDef,
171 param_idx: u32,
172 ) -> Arc<[GenericPredicate]>;
173
167 #[salsa::invoke(crate::ty::generic_predicates_query)] 174 #[salsa::invoke(crate::ty::generic_predicates_query)]
168 fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>; 175 fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>;
169 176
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 77fb76bfc..ccb777492 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -26,8 +26,9 @@ pub struct GenericParam {
26} 26}
27 27
28/// Data about the generic parameters of a function, struct, impl, etc. 28/// Data about the generic parameters of a function, struct, impl, etc.
29#[derive(Clone, PartialEq, Eq, Debug, Default)] 29#[derive(Clone, PartialEq, Eq, Debug)]
30pub struct GenericParams { 30pub struct GenericParams {
31 pub(crate) def: GenericDef,
31 pub(crate) parent_params: Option<Arc<GenericParams>>, 32 pub(crate) parent_params: Option<Arc<GenericParams>>,
32 pub(crate) params: Vec<GenericParam>, 33 pub(crate) params: Vec<GenericParam>,
33 pub(crate) where_predicates: Vec<WherePredicate>, 34 pub(crate) where_predicates: Vec<WherePredicate>,
@@ -69,7 +70,6 @@ impl GenericParams {
69 db: &(impl DefDatabase + AstDatabase), 70 db: &(impl DefDatabase + AstDatabase),
70 def: GenericDef, 71 def: GenericDef,
71 ) -> Arc<GenericParams> { 72 ) -> Arc<GenericParams> {
72 let mut generics = GenericParams::default();
73 let parent = match def { 73 let parent = match def {
74 GenericDef::Function(it) => it.container(db).map(GenericDef::from), 74 GenericDef::Function(it) => it.container(db).map(GenericDef::from),
75 GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), 75 GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
@@ -77,7 +77,12 @@ impl GenericParams {
77 GenericDef::Adt(_) | GenericDef::Trait(_) => None, 77 GenericDef::Adt(_) | GenericDef::Trait(_) => None,
78 GenericDef::ImplBlock(_) => None, 78 GenericDef::ImplBlock(_) => None,
79 }; 79 };
80 generics.parent_params = parent.map(|p| db.generic_params(p)); 80 let mut generics = GenericParams {
81 def,
82 params: Vec::new(),
83 parent_params: parent.map(|p| db.generic_params(p)),
84 where_predicates: Vec::new(),
85 };
81 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; 86 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
82 // FIXME: add `: Sized` bound for everything except for `Self` in traits 87 // FIXME: add `: Sized` bound for everything except for `Self` in traits
83 match def { 88 match def {
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 254d1a964..39f8e1d8a 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -344,6 +344,13 @@ impl Resolver {
344 }) 344 })
345 .flat_map(|params| params.where_predicates.iter()) 345 .flat_map(|params| params.where_predicates.iter())
346 } 346 }
347
348 pub(crate) fn generic_def(&self) -> Option<crate::generics::GenericDef> {
349 self.scopes.iter().find_map(|scope| match scope {
350 Scope::GenericParams(params) => Some(params.def),
351 _ => None,
352 })
353 }
347} 354}
348 355
349impl Resolver { 356impl Resolver {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index a223e120a..36bfb10ce 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -23,8 +23,8 @@ pub(crate) use autoderef::autoderef;
23pub(crate) use infer::{infer_query, InferTy, InferenceResult}; 23pub(crate) use infer::{infer_query, InferTy, InferenceResult};
24pub use lower::CallableDef; 24pub use lower::CallableDef;
25pub(crate) use lower::{ 25pub(crate) use lower::{
26 callable_item_sig, generic_defaults_query, generic_predicates_query, type_for_def, 26 callable_item_sig, generic_defaults_query, generic_predicates_for_param_query,
27 type_for_field, TypableDef, 27 generic_predicates_query, type_for_def, type_for_field, TypableDef,
28}; 28};
29pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 29pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
30 30
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index a83842b0f..8d71abc95 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -86,6 +86,35 @@ impl Ty {
86 } 86 }
87 } 87 }
88 88
89 /// This is only for `generic_predicates_for_param`, where we can't just
90 /// lower the self types of the predicates since that could lead to cycles.
91 /// So we just check here if the `type_ref` resolves to a generic param, and which.
92 fn from_hir_only_param(
93 db: &impl HirDatabase,
94 resolver: &Resolver,
95 type_ref: &TypeRef,
96 ) -> Option<u32> {
97 let path = match type_ref {
98 TypeRef::Path(path) => path,
99 _ => return None,
100 };
101 if let crate::PathKind::Type(_) = &path.kind {
102 return None;
103 }
104 if path.segments.len() > 1 {
105 return None;
106 }
107 let resolution = match resolver.resolve_path_in_type_ns(db, path) {
108 Some((it, None)) => it,
109 _ => return None,
110 };
111 if let TypeNs::GenericParam(idx) = resolution {
112 Some(idx)
113 } else {
114 None
115 }
116 }
117
89 pub(crate) fn from_type_relative_path( 118 pub(crate) fn from_type_relative_path(
90 db: &impl HirDatabase, 119 db: &impl HirDatabase,
91 resolver: &Resolver, 120 resolver: &Resolver,
@@ -189,11 +218,37 @@ impl Ty {
189 } 218 }
190 219
191 fn select_associated_type( 220 fn select_associated_type(
192 _db: &impl HirDatabase, 221 db: &impl HirDatabase,
193 _resolver: &Resolver, 222 resolver: &Resolver,
194 _self_ty: Ty, 223 self_ty: Ty,
195 _segment: &PathSegment, 224 segment: &PathSegment,
196 ) -> Ty { 225 ) -> Ty {
226 let param_idx = match self_ty {
227 Ty::Param { idx, .. } => idx,
228 _ => return Ty::Unknown, // Error: Ambiguous associated type
229 };
230 let def = match resolver.generic_def() {
231 Some(def) => def,
232 None => return Ty::Unknown, // this can't actually happen
233 };
234 let predicates = db.generic_predicates_for_param(def, param_idx);
235 let traits_from_env = predicates.iter().filter_map(|pred| match pred {
236 GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_),
237 _ => None,
238 });
239 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db));
240 for t in traits {
241 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) {
242 let generics = t.generic_params(db);
243 let mut substs = Vec::new();
244 substs.push(self_ty.clone());
245 substs.extend(
246 iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1),
247 );
248 // FIXME handle type parameters on the segment
249 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() });
250 }
251 }
197 Ty::Unknown 252 Ty::Unknown
198 } 253 }
199 254
@@ -269,9 +324,10 @@ pub(super) fn substs_from_path_segment(
269 add_self_param: bool, 324 add_self_param: bool,
270) -> Substs { 325) -> Substs {
271 let mut substs = Vec::new(); 326 let mut substs = Vec::new();
272 let def_generics = def_generic.map(|def| def.generic_params(db)).unwrap_or_default(); 327 let def_generics = def_generic.map(|def| def.generic_params(db));
273 328
274 let parent_param_count = def_generics.count_parent_params(); 329 let (parent_param_count, param_count) =
330 def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len()));
275 substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); 331 substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count));
276 if add_self_param { 332 if add_self_param {
277 // FIXME this add_self_param argument is kind of a hack: Traits have the 333 // FIXME this add_self_param argument is kind of a hack: Traits have the
@@ -283,7 +339,7 @@ pub(super) fn substs_from_path_segment(
283 if let Some(generic_args) = &segment.args_and_bindings { 339 if let Some(generic_args) = &segment.args_and_bindings {
284 // if args are provided, it should be all of them, but we can't rely on that 340 // if args are provided, it should be all of them, but we can't rely on that
285 let self_param_correction = if add_self_param { 1 } else { 0 }; 341 let self_param_correction = if add_self_param { 1 } else { 0 };
286 let param_count = def_generics.params.len() - self_param_correction; 342 let param_count = param_count - self_param_correction;
287 for arg in generic_args.args.iter().take(param_count) { 343 for arg in generic_args.args.iter().take(param_count) {
288 match arg { 344 match arg {
289 GenericArg::Type(type_ref) => { 345 GenericArg::Type(type_ref) => {
@@ -295,10 +351,10 @@ pub(super) fn substs_from_path_segment(
295 } 351 }
296 // add placeholders for args that were not provided 352 // add placeholders for args that were not provided
297 let supplied_params = substs.len(); 353 let supplied_params = substs.len();
298 for _ in supplied_params..def_generics.count_params_including_parent() { 354 for _ in supplied_params..parent_param_count + param_count {
299 substs.push(Ty::Unknown); 355 substs.push(Ty::Unknown);
300 } 356 }
301 assert_eq!(substs.len(), def_generics.count_params_including_parent()); 357 assert_eq!(substs.len(), parent_param_count + param_count);
302 358
303 // handle defaults 359 // handle defaults
304 if let Some(def_generic) = def_generic { 360 if let Some(def_generic) = def_generic {
@@ -491,6 +547,29 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
491 Ty::from_hir(db, &resolver, type_ref) 547 Ty::from_hir(db, &resolver, type_ref)
492} 548}
493 549
550/// This query exists only to be used when resolving short-hand associated types
551/// like `T::Item`.
552///
553/// See the analogous query in rustc and its comment:
554/// https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46
555/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
556/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
557/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
558pub(crate) fn generic_predicates_for_param_query(
559 db: &impl HirDatabase,
560 def: GenericDef,
561 param_idx: u32,
562) -> Arc<[GenericPredicate]> {
563 let resolver = def.resolver(db);
564 let predicates = resolver
565 .where_predicates_in_scope()
566 // we have to filter out all other predicates *first*, before attempting to lower them
567 .filter(|pred| Ty::from_hir_only_param(db, &resolver, &pred.type_ref) == Some(param_idx))
568 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
569 .collect::<Vec<_>>();
570 predicates.into()
571}
572
494pub(crate) fn trait_env( 573pub(crate) fn trait_env(
495 db: &impl HirDatabase, 574 db: &impl HirDatabase,
496 resolver: &Resolver, 575 resolver: &Resolver,
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 3b0a99460..3ac1fbdd5 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2740,17 +2740,17 @@ fn test() {
2740 [202; 203) 't': T 2740 [202; 203) 't': T
2741 [221; 223) '{}': () 2741 [221; 223) '{}': ()
2742 [234; 300) '{ ...(S); }': () 2742 [234; 300) '{ ...(S); }': ()
2743 [244; 245) 'x': {unknown} 2743 [244; 245) 'x': u32
2744 [248; 252) 'foo1': fn foo1<S>(T) -> {unknown} 2744 [248; 252) 'foo1': fn foo1<S>(T) -> <T as Iterable>::Item
2745 [248; 255) 'foo1(S)': {unknown} 2745 [248; 255) 'foo1(S)': u32
2746 [253; 254) 'S': S 2746 [253; 254) 'S': S
2747 [265; 266) 'y': u32 2747 [265; 266) 'y': u32
2748 [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item 2748 [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
2749 [269; 276) 'foo2(S)': u32 2749 [269; 276) 'foo2(S)': u32
2750 [274; 275) 'S': S 2750 [274; 275) 'S': S
2751 [286; 287) 'z': {unknown} 2751 [286; 287) 'z': u32
2752 [290; 294) 'foo3': fn foo3<S>(T) -> {unknown} 2752 [290; 294) 'foo3': fn foo3<S>(T) -> <T as Iterable>::Item
2753 [290; 297) 'foo3(S)': {unknown} 2753 [290; 297) 'foo3(S)': u32
2754 [295; 296) 'S': S 2754 [295; 296) 'S': S
2755 "### 2755 "###
2756 ); 2756 );
@@ -4080,7 +4080,7 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
4080} 4080}
4081 4081
4082#[test] 4082#[test]
4083fn unselected_projection_in_trait_env() { 4083fn unselected_projection_in_trait_env_1() {
4084 let t = type_at( 4084 let t = type_at(
4085 r#" 4085 r#"
4086//- /main.rs 4086//- /main.rs
@@ -4102,7 +4102,33 @@ fn test<T: Trait>() where T::Item: Trait2 {
4102} 4102}
4103 4103
4104#[test] 4104#[test]
4105fn unselected_projection_in_trait_env_cycle() { 4105fn unselected_projection_in_trait_env_2() {
4106 let t = type_at(
4107 r#"
4108//- /main.rs
4109trait Trait<T> {
4110 type Item;
4111}
4112
4113trait Trait2 {
4114 fn foo(&self) -> u32;
4115}
4116
4117fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
4118 let x: T::Item = no_matter;
4119 x.foo()<|>;
4120}
4121"#,
4122 );
4123 assert_eq!(t, "u32");
4124}
4125
4126#[test]
4127// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4128// in Unknown, and we should be able to do that once Salsa allows us to handle
4129// the cycle. But at least it doesn't overflow for now.
4130#[should_panic]
4131fn unselected_projection_in_trait_env_cycle_1() {
4106 let t = type_at( 4132 let t = type_at(
4107 r#" 4133 r#"
4108//- /main.rs 4134//- /main.rs
@@ -4121,6 +4147,28 @@ fn test<T: Trait>() where T: Trait2<T::Item> {
4121 assert_eq!(t, "{unknown}"); 4147 assert_eq!(t, "{unknown}");
4122} 4148}
4123 4149
4150#[test]
4151// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4152// in Unknown, and we should be able to do that once Salsa allows us to handle
4153// the cycle. But at least it doesn't overflow for now.
4154#[should_panic]
4155fn unselected_projection_in_trait_env_cycle_2() {
4156 let t = type_at(
4157 r#"
4158//- /main.rs
4159trait Trait<T> {
4160 type Item;
4161}
4162
4163fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
4164 let x: T::Item = no_matter<|>;
4165}
4166"#,
4167 );
4168 // this is a legitimate cycle
4169 assert_eq!(t, "{unknown}");
4170}
4171
4124fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 4172fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
4125 let file = db.parse(pos.file_id).ok().unwrap(); 4173 let file = db.parse(pos.file_id).ok().unwrap();
4126 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 4174 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 693d9b28f..cfecf75ee 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -104,7 +104,11 @@ impl ToChalk for Ty {
104 } 104 }
105 } 105 }
106 } 106 }
107 chalk_ir::Ty::Projection(_) => unimplemented!(), 107 chalk_ir::Ty::Projection(proj) => {
108 let associated_ty = from_chalk(db, proj.associated_ty_id);
109 let parameters = from_chalk(db, proj.parameters);
110 Ty::Projection(ProjectionTy { associated_ty, parameters })
111 }
108 chalk_ir::Ty::ForAll(_) => unimplemented!(), 112 chalk_ir::Ty::ForAll(_) => unimplemented!(),
109 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), 113 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
110 chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"), 114 chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),