Skip to content

Commit a8d89ae

Browse files
Handle cycles in RPITIT computation
Cycles can occur in malformed code (this is only a conjecture) or from Chalk bugs (for this I have a test).
1 parent 29ea2f0 commit a8d89ae

File tree

4 files changed

+55
-5
lines changed

4 files changed

+55
-5
lines changed

crates/hir-ty/src/chalk_db.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use chalk_ir::{
1313
cast::{Cast, Caster},
1414
fold::shift::Shift,
1515
};
16-
use chalk_solve::rust_ir::{self, AssociatedTyDatumBound, OpaqueTyDatumBound, WellKnownTrait};
16+
use chalk_solve::rust_ir::{
17+
self, AssociatedTyDatumBound, AssociatedTyValueBound, OpaqueTyDatumBound, WellKnownTrait,
18+
};
1719

1820
use base_db::Crate;
1921
use hir_def::{
@@ -1008,6 +1010,31 @@ pub(crate) fn associated_ty_value_query(
10081010
}
10091011
}
10101012

1013+
/// We need cycle recovery because RPITITs can cause cycles.
1014+
pub(crate) fn associated_ty_value_cycle(
1015+
db: &dyn HirDatabase,
1016+
krate: Crate,
1017+
id: AssociatedTyValueId,
1018+
) -> Arc<AssociatedTyValue> {
1019+
match from_assoc_type_value_id(db, id) {
1020+
AnyImplAssocType::Normal(type_alias) => {
1021+
type_alias_associated_ty_value(db, krate, type_alias)
1022+
}
1023+
AnyImplAssocType::Rpitit(assoc_type_id) => {
1024+
let assoc = assoc_type_id.loc(db);
1025+
let trait_assoc = assoc.trait_assoc.loc(db);
1026+
Arc::new(AssociatedTyValue {
1027+
associated_ty_id: to_assoc_type_id_rpitit(assoc.trait_assoc),
1028+
impl_id: assoc.impl_id.to_chalk(db),
1029+
value: trait_assoc
1030+
.bounds
1031+
.as_ref()
1032+
.map(|_| AssociatedTyValueBound { ty: TyKind::Error.intern(Interner) }),
1033+
})
1034+
}
1035+
}
1036+
}
1037+
10111038
fn rpitit_associated_ty_value(
10121039
db: &dyn HirDatabase,
10131040
assoc_type_id: RpititImplAssocTyId,

crates/hir-ty/src/db.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
290290
fn variances_of(&self, def: GenericDefId) -> Option<Arc<[crate::variance::Variance]>>;
291291

292292
#[salsa::invoke(chalk_db::associated_ty_value_query)]
293+
#[salsa::cycle(cycle_result = chalk_db::associated_ty_value_cycle)]
293294
fn associated_ty_value(
294295
&self,
295296
krate: Crate,

crates/hir-ty/src/rpitit.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,16 @@ pub struct RpititImplAssocTy {
5858

5959
impl_intern_key_ref!(RpititImplAssocTyId, RpititImplAssocTy);
6060

61+
fn impl_method_rpitit_values_cycle(
62+
_db: &dyn HirDatabase,
63+
_impl_id: ImplId,
64+
_trait_method_id: FunctionId,
65+
) -> ThinVec<Arc<AssociatedTyValue>> {
66+
ThinVec::new()
67+
}
68+
6169
// We return a list and not a hasmap because the number of RPITITs in a function should be small.
62-
#[salsa_macros::tracked(return_ref)]
70+
#[salsa_macros::tracked(return_ref, cycle_result = impl_method_rpitit_values_cycle)]
6371
pub(crate) fn impl_method_rpitit_values(
6472
db: &dyn HirDatabase,
6573
impl_id: ImplId,
@@ -249,11 +257,18 @@ fn defaulted_impl_method_rpitit_values(
249257
.collect()
250258
}
251259

260+
fn defaulted_trait_method_rpitit_values_cycle(
261+
_db: &dyn HirDatabase,
262+
_method_id: FunctionId,
263+
) -> ThinVec<(RpititTraitAssocTyId, Binders<Ty>)> {
264+
ThinVec::new()
265+
}
266+
252267
/// This is called only for defaulted trait methods, as there the value of the RPITIT associated
253268
/// items on an impl (if the method body is left defaulted) is the same as with the trait method.
254269
// This returns an `ThinVec` and not `Box<[]>` because this is called from inference,
255270
// and most methods don't have RPITITs.
256-
#[salsa_macros::tracked(return_ref)]
271+
#[salsa_macros::tracked(return_ref, cycle_result = defaulted_trait_method_rpitit_values_cycle)]
257272
pub(crate) fn defaulted_trait_method_rpitit_values(
258273
db: &dyn HirDatabase,
259274
method_id: FunctionId,

crates/hir-ty/src/tests/traits.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5141,7 +5141,10 @@ impl<T, U> Trait<(Foo<()>, U)> for Foo<T> {}
51415141
}
51425142

51435143
#[test]
5144-
fn check_foo() {
5144+
fn rpitit_cycle() {
5145+
// This shouldn't cause a cycle, but it does due to Chalk shortcomings. It should be
5146+
// fixed when we switch to the new trait solver. However, I believe it will still possible
5147+
// to cause cycles with malformed code, so we still need the cycle handlers.
51455148
check_rpitit(
51465149
r#"
51475150
//- minicore: future, send, sized
@@ -5153,6 +5156,10 @@ trait DesugaredAsyncTrait {
51535156
51545157
impl DesugaredAsyncTrait for () {}
51555158
"#,
5156-
expect![[r#""#]],
5159+
expect![[r#"
5160+
type __foo_rpitit: Future<Output = usize> + Send;
5161+
5162+
type __foo_rpitit = {unknown};
5163+
"#]],
51575164
);
51585165
}

0 commit comments

Comments
 (0)