diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-21 16:42:08 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-21 16:42:08 +0000 |
commit | 35868c4f7dc479dd5f731a2785ec6a203046ea9c (patch) | |
tree | e78313acecc4fa84a11a2d8e7da7c85c98f940e0 /crates/hir_ty | |
parent | 1ae20d2b894171f0b8368309da727cd365b95fc1 (diff) | |
parent | d8f8b495ad5c9e3676ddf7af53b23bb5b7f2fde0 (diff) |
Merge #8133
8133: Ignore type bindings in generic_predicates_for_param (fix panic on ena and crates depending on it) r=flodiebold a=flodiebold
This allows us to handle more cases without a query cycle, which includes certain cases that rustc accepted. That in turn means we avoid triggering salsa-rs/salsa#257 on valid code (it will still happen if the user writes an actual cycle).
We actually accept more definitions than rustc now; that's because rustc only ignores bindings when looking up super traits, whereas we now also ignore them when looking for predicates to disambiguate associated type shorthand. We could introduce a separate query for super traits if necessary, but for now I think this should be fine.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/display.rs | 21 | ||||
-rw-r--r-- | crates/hir_ty/src/lib.rs | 17 | ||||
-rw-r--r-- | crates/hir_ty/src/lower.rs | 25 | ||||
-rw-r--r-- | crates/hir_ty/src/tests.rs | 69 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/traits.rs | 50 | ||||
-rw-r--r-- | crates/hir_ty/src/traits/chalk.rs | 2 |
6 files changed, 169 insertions, 15 deletions
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 3845009ae..9d3b79be3 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -571,13 +571,22 @@ impl HirDisplay for Ty { | |||
571 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? | 571 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? |
572 | } | 572 | } |
573 | TypeParamProvenance::ArgumentImplTrait => { | 573 | TypeParamProvenance::ArgumentImplTrait => { |
574 | let bounds = f.db.generic_predicates_for_param(id); | ||
575 | let substs = Substitution::type_params_for_generics(f.db, &generics); | 574 | let substs = Substitution::type_params_for_generics(f.db, &generics); |
576 | write_bounds_like_dyn_trait_with_prefix( | 575 | let bounds = f |
577 | "impl", | 576 | .db |
578 | &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(), | 577 | .generic_predicates(id.parent) |
579 | f, | 578 | .into_iter() |
580 | )?; | 579 | .map(|pred| pred.clone().subst(&substs)) |
580 | .filter(|wc| match &wc { | ||
581 | WhereClause::Implemented(tr) => tr.self_type_parameter() == self, | ||
582 | WhereClause::AliasEq(AliasEq { | ||
583 | alias: AliasTy::Projection(proj), | ||
584 | ty: _, | ||
585 | }) => proj.self_type_parameter() == self, | ||
586 | _ => false, | ||
587 | }) | ||
588 | .collect::<Vec<_>>(); | ||
589 | write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?; | ||
581 | } | 590 | } |
582 | } | 591 | } |
583 | } | 592 | } |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index c46529879..ad908f957 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -106,6 +106,10 @@ impl ProjectionTy { | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | pub fn self_type_parameter(&self) -> &Ty { | ||
110 | &self.substitution[0] | ||
111 | } | ||
112 | |||
109 | fn trait_(&self, db: &dyn HirDatabase) -> TraitId { | 113 | fn trait_(&self, db: &dyn HirDatabase) -> TraitId { |
110 | match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container { | 114 | match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container { |
111 | AssocContainerId::TraitId(it) => it, | 115 | AssocContainerId::TraitId(it) => it, |
@@ -936,10 +940,19 @@ impl Ty { | |||
936 | let param_data = &generic_params.types[id.local_id]; | 940 | let param_data = &generic_params.types[id.local_id]; |
937 | match param_data.provenance { | 941 | match param_data.provenance { |
938 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | 942 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { |
943 | let substs = Substitution::type_params(db, id.parent); | ||
939 | let predicates = db | 944 | let predicates = db |
940 | .generic_predicates_for_param(id) | 945 | .generic_predicates(id.parent) |
941 | .into_iter() | 946 | .into_iter() |
942 | .map(|pred| pred.value.clone()) | 947 | .map(|pred| pred.clone().subst(&substs)) |
948 | .filter(|wc| match &wc { | ||
949 | WhereClause::Implemented(tr) => tr.self_type_parameter() == self, | ||
950 | WhereClause::AliasEq(AliasEq { | ||
951 | alias: AliasTy::Projection(proj), | ||
952 | ty: _, | ||
953 | }) => proj.self_type_parameter() == self, | ||
954 | _ => false, | ||
955 | }) | ||
943 | .collect_vec(); | 956 | .collect_vec(); |
944 | 957 | ||
945 | Some(predicates) | 958 | Some(predicates) |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index c914a3b8e..fd451a823 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -189,7 +189,10 @@ impl<'a> TyLoweringContext<'a> { | |||
189 | let self_ty = | 189 | let self_ty = |
190 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); | 190 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); |
191 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { | 191 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { |
192 | bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone())).collect() | 192 | bounds |
193 | .iter() | ||
194 | .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)) | ||
195 | .collect() | ||
193 | }); | 196 | }); |
194 | TyKind::Dyn(predicates).intern(&Interner) | 197 | TyKind::Dyn(predicates).intern(&Interner) |
195 | } | 198 | } |
@@ -666,6 +669,7 @@ impl<'a> TyLoweringContext<'a> { | |||
666 | pub(crate) fn lower_where_predicate( | 669 | pub(crate) fn lower_where_predicate( |
667 | &'a self, | 670 | &'a self, |
668 | where_predicate: &'a WherePredicate, | 671 | where_predicate: &'a WherePredicate, |
672 | ignore_bindings: bool, | ||
669 | ) -> impl Iterator<Item = WhereClause> + 'a { | 673 | ) -> impl Iterator<Item = WhereClause> + 'a { |
670 | match where_predicate { | 674 | match where_predicate { |
671 | WherePredicate::ForLifetime { target, bound, .. } | 675 | WherePredicate::ForLifetime { target, bound, .. } |
@@ -688,7 +692,9 @@ impl<'a> TyLoweringContext<'a> { | |||
688 | .intern(&Interner) | 692 | .intern(&Interner) |
689 | } | 693 | } |
690 | }; | 694 | }; |
691 | self.lower_type_bound(bound, self_ty).collect::<Vec<_>>().into_iter() | 695 | self.lower_type_bound(bound, self_ty, ignore_bindings) |
696 | .collect::<Vec<_>>() | ||
697 | .into_iter() | ||
692 | } | 698 | } |
693 | WherePredicate::Lifetime { .. } => vec![].into_iter(), | 699 | WherePredicate::Lifetime { .. } => vec![].into_iter(), |
694 | } | 700 | } |
@@ -698,6 +704,7 @@ impl<'a> TyLoweringContext<'a> { | |||
698 | &'a self, | 704 | &'a self, |
699 | bound: &'a TypeBound, | 705 | bound: &'a TypeBound, |
700 | self_ty: Ty, | 706 | self_ty: Ty, |
707 | ignore_bindings: bool, | ||
701 | ) -> impl Iterator<Item = WhereClause> + 'a { | 708 | ) -> impl Iterator<Item = WhereClause> + 'a { |
702 | let mut bindings = None; | 709 | let mut bindings = None; |
703 | let trait_ref = match bound { | 710 | let trait_ref = match bound { |
@@ -711,6 +718,7 @@ impl<'a> TyLoweringContext<'a> { | |||
711 | trait_ref.into_iter().chain( | 718 | trait_ref.into_iter().chain( |
712 | bindings | 719 | bindings |
713 | .into_iter() | 720 | .into_iter() |
721 | .filter(move |_| !ignore_bindings) | ||
714 | .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)), | 722 | .flat_map(move |tr| self.assoc_type_bindings_from_type_bound(bound, tr)), |
715 | ) | 723 | ) |
716 | } | 724 | } |
@@ -755,6 +763,7 @@ impl<'a> TyLoweringContext<'a> { | |||
755 | preds.extend(self.lower_type_bound( | 763 | preds.extend(self.lower_type_bound( |
756 | bound, | 764 | bound, |
757 | TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(&Interner), | 765 | TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(&Interner), |
766 | false, | ||
758 | )); | 767 | )); |
759 | } | 768 | } |
760 | preds | 769 | preds |
@@ -766,7 +775,7 @@ impl<'a> TyLoweringContext<'a> { | |||
766 | let self_ty = | 775 | let self_ty = |
767 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); | 776 | TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); |
768 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { | 777 | let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { |
769 | bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone())).collect() | 778 | bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect() |
770 | }); | 779 | }); |
771 | ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } | 780 | ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } |
772 | } | 781 | } |
@@ -896,7 +905,9 @@ pub(crate) fn generic_predicates_for_param_query( | |||
896 | }, | 905 | }, |
897 | WherePredicate::Lifetime { .. } => false, | 906 | WherePredicate::Lifetime { .. } => false, |
898 | }) | 907 | }) |
899 | .flat_map(|pred| ctx.lower_where_predicate(pred).map(|p| Binders::new(generics.len(), p))) | 908 | .flat_map(|pred| { |
909 | ctx.lower_where_predicate(pred, true).map(|p| Binders::new(generics.len(), p)) | ||
910 | }) | ||
900 | .collect() | 911 | .collect() |
901 | } | 912 | } |
902 | 913 | ||
@@ -918,7 +929,7 @@ pub(crate) fn trait_environment_query( | |||
918 | let mut traits_in_scope = Vec::new(); | 929 | let mut traits_in_scope = Vec::new(); |
919 | let mut clauses = Vec::new(); | 930 | let mut clauses = Vec::new(); |
920 | for pred in resolver.where_predicates_in_scope() { | 931 | for pred in resolver.where_predicates_in_scope() { |
921 | for pred in ctx.lower_where_predicate(pred) { | 932 | for pred in ctx.lower_where_predicate(pred, false) { |
922 | if let WhereClause::Implemented(tr) = &pred { | 933 | if let WhereClause::Implemented(tr) = &pred { |
923 | traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id())); | 934 | traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id())); |
924 | } | 935 | } |
@@ -966,7 +977,9 @@ pub(crate) fn generic_predicates_query( | |||
966 | let generics = generics(db.upcast(), def); | 977 | let generics = generics(db.upcast(), def); |
967 | resolver | 978 | resolver |
968 | .where_predicates_in_scope() | 979 | .where_predicates_in_scope() |
969 | .flat_map(|pred| ctx.lower_where_predicate(pred).map(|p| Binders::new(generics.len(), p))) | 980 | .flat_map(|pred| { |
981 | ctx.lower_where_predicate(pred, false).map(|p| Binders::new(generics.len(), p)) | ||
982 | }) | ||
970 | .collect() | 983 | .collect() |
971 | } | 984 | } |
972 | 985 | ||
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index 0a4141e69..ad283c1e0 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -369,3 +369,72 @@ fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) { | |||
369 | actual.push('\n'); | 369 | actual.push('\n'); |
370 | expect.assert_eq(&actual); | 370 | expect.assert_eq(&actual); |
371 | } | 371 | } |
372 | |||
373 | #[test] | ||
374 | fn salsa_bug() { | ||
375 | let (mut db, pos) = TestDB::with_position( | ||
376 | " | ||
377 | //- /lib.rs | ||
378 | trait Index { | ||
379 | type Output; | ||
380 | } | ||
381 | |||
382 | type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key; | ||
383 | |||
384 | pub trait UnificationStoreBase: Index<Output = Key<Self>> { | ||
385 | type Key; | ||
386 | |||
387 | fn len(&self) -> usize; | ||
388 | } | ||
389 | |||
390 | pub trait UnificationStoreMut: UnificationStoreBase { | ||
391 | fn push(&mut self, value: Self::Key); | ||
392 | } | ||
393 | |||
394 | fn main() { | ||
395 | let x = 1; | ||
396 | x.push(1);$0 | ||
397 | } | ||
398 | ", | ||
399 | ); | ||
400 | |||
401 | let module = db.module_for_file(pos.file_id); | ||
402 | let crate_def_map = module.def_map(&db); | ||
403 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
404 | db.infer(def); | ||
405 | }); | ||
406 | |||
407 | let new_text = " | ||
408 | //- /lib.rs | ||
409 | trait Index { | ||
410 | type Output; | ||
411 | } | ||
412 | |||
413 | type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key; | ||
414 | |||
415 | pub trait UnificationStoreBase: Index<Output = Key<Self>> { | ||
416 | type Key; | ||
417 | |||
418 | fn len(&self) -> usize; | ||
419 | } | ||
420 | |||
421 | pub trait UnificationStoreMut: UnificationStoreBase { | ||
422 | fn push(&mut self, value: Self::Key); | ||
423 | } | ||
424 | |||
425 | fn main() { | ||
426 | |||
427 | let x = 1; | ||
428 | x.push(1); | ||
429 | } | ||
430 | " | ||
431 | .to_string(); | ||
432 | |||
433 | db.set_file_text(pos.file_id, Arc::new(new_text)); | ||
434 | |||
435 | let module = db.module_for_file(pos.file_id); | ||
436 | let crate_def_map = module.def_map(&db); | ||
437 | visit_module(&db, &crate_def_map, module.local_id, &mut |def| { | ||
438 | db.infer(def); | ||
439 | }); | ||
440 | } | ||
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 8f2bdffc0..37cd04c6f 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -2272,6 +2272,56 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
2272 | } | 2272 | } |
2273 | 2273 | ||
2274 | #[test] | 2274 | #[test] |
2275 | fn unselected_projection_in_trait_env_cycle_3() { | ||
2276 | // this is a cycle for rustc; we currently accept it | ||
2277 | check_types( | ||
2278 | r#" | ||
2279 | //- /main.rs | ||
2280 | trait Trait { | ||
2281 | type Item; | ||
2282 | type OtherItem; | ||
2283 | } | ||
2284 | |||
2285 | fn test<T>() where T: Trait<OtherItem = T::Item> { | ||
2286 | let x: T::Item = no_matter; | ||
2287 | } //^ Trait::Item<T> | ||
2288 | "#, | ||
2289 | ); | ||
2290 | } | ||
2291 | |||
2292 | #[test] | ||
2293 | fn unselected_projection_in_trait_env_no_cycle() { | ||
2294 | // this is not a cycle | ||
2295 | check_types( | ||
2296 | r#" | ||
2297 | //- /main.rs | ||
2298 | trait Index { | ||
2299 | type Output; | ||
2300 | } | ||
2301 | |||
2302 | type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key; | ||
2303 | |||
2304 | pub trait UnificationStoreBase: Index<Output = Key<Self>> { | ||
2305 | type Key; | ||
2306 | |||
2307 | fn len(&self) -> usize; | ||
2308 | } | ||
2309 | |||
2310 | pub trait UnificationStoreMut: UnificationStoreBase { | ||
2311 | fn push(&mut self, value: Self::Key); | ||
2312 | } | ||
2313 | |||
2314 | fn test<T>(t: T) where T: UnificationStoreMut { | ||
2315 | let x; | ||
2316 | t.push(x); | ||
2317 | let y: Key<T>; | ||
2318 | (x, y); | ||
2319 | } //^ (UnificationStoreBase::Key<T>, UnificationStoreBase::Key<T>) | ||
2320 | "#, | ||
2321 | ); | ||
2322 | } | ||
2323 | |||
2324 | #[test] | ||
2275 | fn inline_assoc_type_bounds_1() { | 2325 | fn inline_assoc_type_bounds_1() { |
2276 | check_types( | 2326 | check_types( |
2277 | r#" | 2327 | r#" |
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs index 734679414..944145603 100644 --- a/crates/hir_ty/src/traits/chalk.rs +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -395,7 +395,7 @@ pub(crate) fn associated_ty_data_query( | |||
395 | let bounds = type_alias_data | 395 | let bounds = type_alias_data |
396 | .bounds | 396 | .bounds |
397 | .iter() | 397 | .iter() |
398 | .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone())) | 398 | .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false)) |
399 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) | 399 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) |
400 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) | 400 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) |
401 | .collect(); | 401 | .collect(); |