aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_ty/src/db.rs1
-rw-r--r--crates/hir_ty/src/lower.rs34
-rw-r--r--crates/hir_ty/src/tests/regression.rs38
-rw-r--r--crates/hir_ty/src/utils.rs52
4 files changed, 100 insertions, 25 deletions
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index cf67d4266..9da0a02e3 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -70,6 +70,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
70 fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>; 70 fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>;
71 71
72 #[salsa::invoke(crate::lower::generic_defaults_query)] 72 #[salsa::invoke(crate::lower::generic_defaults_query)]
73 #[salsa::cycle(crate::lower::generic_defaults_recover)]
73 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; 74 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
74 75
75 #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] 76 #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 7fd46becd..c99dd8d0a 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -414,17 +414,16 @@ impl<'a> TyLoweringContext<'a> {
414 self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty); 414 self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty);
415 let ty = if remaining_segments.len() == 1 { 415 let ty = if remaining_segments.len() == 1 {
416 let segment = remaining_segments.first().unwrap(); 416 let segment = remaining_segments.first().unwrap();
417 let found = associated_type_by_name_including_super_traits( 417 let found = self
418 self.db, 418 .db
419 trait_ref, 419 .trait_data(trait_ref.hir_trait_id())
420 &segment.name, 420 .associated_type_by_name(&segment.name);
421 );
422 match found { 421 match found {
423 Some((super_trait_ref, associated_ty)) => { 422 Some(associated_ty) => {
424 // FIXME handle type parameters on the segment 423 // FIXME handle type parameters on the segment
425 TyKind::Alias(AliasTy::Projection(ProjectionTy { 424 TyKind::Alias(AliasTy::Projection(ProjectionTy {
426 associated_ty_id: to_assoc_type_id(associated_ty), 425 associated_ty_id: to_assoc_type_id(associated_ty),
427 substitution: super_trait_ref.substitution, 426 substitution: trait_ref.substitution,
428 })) 427 }))
429 .intern(&Interner) 428 .intern(&Interner)
430 } 429 }
@@ -1089,6 +1088,27 @@ pub(crate) fn generic_defaults_query(
1089 defaults 1088 defaults
1090} 1089}
1091 1090
1091pub(crate) fn generic_defaults_recover(
1092 db: &dyn HirDatabase,
1093 _cycle: &[String],
1094 def: &GenericDefId,
1095) -> Arc<[Binders<Ty>]> {
1096 let generic_params = generics(db.upcast(), *def);
1097
1098 // we still need one default per parameter
1099 let defaults = generic_params
1100 .iter()
1101 .enumerate()
1102 .map(|(idx, _)| {
1103 let ty = TyKind::Error.intern(&Interner);
1104
1105 crate::make_only_type_binders(idx, ty)
1106 })
1107 .collect();
1108
1109 defaults
1110}
1111
1092fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { 1112fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
1093 let data = db.function_data(def); 1113 let data = db.function_data(def);
1094 let resolver = def.resolver(db.upcast()); 1114 let resolver = def.resolver(db.upcast());
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 9cd9f473d..d14f5c9bb 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1012,3 +1012,41 @@ fn lifetime_from_chalk_during_deref() {
1012 "#, 1012 "#,
1013 ) 1013 )
1014} 1014}
1015
1016#[test]
1017fn issue_8686() {
1018 check_infer(
1019 r#"
1020pub trait Try: FromResidual {
1021 type Output;
1022 type Residual;
1023}
1024pub trait FromResidual<R = <Self as Try>::Residual> {
1025 fn from_residual(residual: R) -> Self;
1026}
1027
1028struct ControlFlow<B, C>;
1029impl<B, C> Try for ControlFlow<B, C> {
1030 type Output = C;
1031 type Residual = ControlFlow<B, !>;
1032}
1033impl<B, C> FromResidual for ControlFlow<B, C> {
1034 fn from_residual(r: ControlFlow<B, !>) -> Self { ControlFlow }
1035}
1036
1037fn test() {
1038 ControlFlow::from_residual(ControlFlow::<u32, !>);
1039}
1040 "#,
1041 expect![[r#"
1042 144..152 'residual': R
1043 365..366 'r': ControlFlow<B, !>
1044 395..410 '{ ControlFlow }': ControlFlow<B, C>
1045 397..408 'ControlFlow': ControlFlow<B, C>
1046 424..482 '{ ...!>); }': ()
1047 430..456 'Contro...sidual': fn from_residual<ControlFlow<u32, {unknown}>, ControlFlow<u32, !>>(ControlFlow<u32, !>) -> ControlFlow<u32, {unknown}>
1048 430..479 'Contro...2, !>)': ControlFlow<u32, {unknown}>
1049 457..478 'Contro...32, !>': ControlFlow<u32, !>
1050 "#]],
1051 );
1052}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 2f04ee57a..2f490fb92 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -1,6 +1,8 @@
1//! Helper functions for working with def, which don't need to be a separate 1//! Helper functions for working with def, which don't need to be a separate
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`). 2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3 3
4use std::iter;
5
4use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex}; 6use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
5use hir_def::{ 7use hir_def::{
6 db::DefDatabase, 8 db::DefDatabase,
@@ -14,8 +16,12 @@ use hir_def::{
14 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, 16 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
15}; 17};
16use hir_expand::name::{name, Name}; 18use hir_expand::name::{name, Name};
19use rustc_hash::FxHashSet;
17 20
18use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, WhereClause}; 21use crate::{
22 db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind,
23 WhereClause,
24};
19 25
20fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 26fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
21 let resolver = trait_.resolver(db); 27 let resolver = trait_.resolver(db);
@@ -102,25 +108,35 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
102/// `all_super_traits` is that we keep track of type parameters; for example if 108/// `all_super_traits` is that we keep track of type parameters; for example if
103/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get 109/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
104/// `Self: OtherTrait<i32>`. 110/// `Self: OtherTrait<i32>`.
105pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> { 111pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> SuperTraits {
106 // FIXME: replace by Chalk's `super_traits`, maybe make this a query 112 SuperTraits { db, seen: iter::once(trait_ref.trait_id).collect(), stack: vec![trait_ref] }
113}
107 114
108 // we need to take care a bit here to avoid infinite loops in case of cycles 115pub(super) struct SuperTraits<'a> {
109 // (i.e. if we have `trait A: B; trait B: A;`) 116 db: &'a dyn HirDatabase,
110 let mut result = vec![trait_ref]; 117 stack: Vec<TraitRef>,
111 let mut i = 0; 118 seen: FxHashSet<ChalkTraitId>,
112 while i < result.len() { 119}
113 let t = &result[i]; 120
114 // yeah this is quadratic, but trait hierarchies should be flat 121impl<'a> SuperTraits<'a> {
115 // enough that this doesn't matter 122 fn elaborate(&mut self, trait_ref: &TraitRef) {
116 for tt in direct_super_trait_refs(db, t) { 123 let mut trait_refs = direct_super_trait_refs(self.db, trait_ref);
117 if !result.iter().any(|tr| tr.trait_id == tt.trait_id) { 124 trait_refs.retain(|tr| !self.seen.contains(&tr.trait_id));
118 result.push(tt); 125 self.stack.extend(trait_refs);
119 } 126 }
127}
128
129impl<'a> Iterator for SuperTraits<'a> {
130 type Item = TraitRef;
131
132 fn next(&mut self) -> Option<Self::Item> {
133 if let Some(next) = self.stack.pop() {
134 self.elaborate(&next);
135 Some(next)
136 } else {
137 None
120 } 138 }
121 i += 1;
122 } 139 }
123 result
124} 140}
125 141
126pub(super) fn associated_type_by_name_including_super_traits( 142pub(super) fn associated_type_by_name_including_super_traits(
@@ -128,7 +144,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
128 trait_ref: TraitRef, 144 trait_ref: TraitRef,
129 name: &Name, 145 name: &Name,
130) -> Option<(TraitRef, TypeAliasId)> { 146) -> Option<(TraitRef, TypeAliasId)> {
131 all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| { 147 all_super_trait_refs(db, trait_ref).find_map(|t| {
132 let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?; 148 let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?;
133 Some((t, assoc_type)) 149 Some((t, assoc_type))
134 }) 150 })