aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-03-21 16:42:08 +0000
committerGitHub <[email protected]>2021-03-21 16:42:08 +0000
commit35868c4f7dc479dd5f731a2785ec6a203046ea9c (patch)
treee78313acecc4fa84a11a2d8e7da7c85c98f940e0 /crates/hir_ty
parent1ae20d2b894171f0b8368309da727cd365b95fc1 (diff)
parentd8f8b495ad5c9e3676ddf7af53b23bb5b7f2fde0 (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.rs21
-rw-r--r--crates/hir_ty/src/lib.rs17
-rw-r--r--crates/hir_ty/src/lower.rs25
-rw-r--r--crates/hir_ty/src/tests.rs69
-rw-r--r--crates/hir_ty/src/tests/traits.rs50
-rw-r--r--crates/hir_ty/src/traits/chalk.rs2
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]
374fn 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]
2275fn 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
2280trait Trait {
2281 type Item;
2282 type OtherItem;
2283}
2284
2285fn 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]
2293fn unselected_projection_in_trait_env_no_cycle() {
2294 // this is not a cycle
2295 check_types(
2296 r#"
2297//- /main.rs
2298trait Index {
2299 type Output;
2300}
2301
2302type Key<S: UnificationStoreBase> = <S as UnificationStoreBase>::Key;
2303
2304pub trait UnificationStoreBase: Index<Output = Key<Self>> {
2305 type Key;
2306
2307 fn len(&self) -> usize;
2308}
2309
2310pub trait UnificationStoreMut: UnificationStoreBase {
2311 fn push(&mut self, value: Self::Key);
2312}
2313
2314fn 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]
2275fn inline_assoc_type_bounds_1() { 2325fn 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();