fix: Cycle handlers for `HirDatabase::infer, const_param_ty_with_diagnostics

This commit is contained in:
Shoyu Vanilla 2025-05-30 23:53:30 +09:00
parent 25808c1ba1
commit fefe86732d
5 changed files with 72 additions and 7 deletions

View File

@ -31,6 +31,7 @@ use crate::{
#[query_group::query_group]
pub trait HirDatabase: DefDatabase + std::fmt::Debug {
#[salsa::invoke(crate::infer::infer_query)]
#[salsa::cycle(cycle_result = crate::infer::infer_cycle_result)]
fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
// region:mir
@ -132,6 +133,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
// FIXME: Make this a non-interned query.
#[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)]
#[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)]
fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics);
#[salsa::invoke(crate::lower::const_param_ty_query)]

View File

@ -135,6 +135,10 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
Arc::new(ctx.resolve_all())
}
pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc<InferenceResult> {
Arc::new(InferenceResult { has_errors: true, ..Default::default() })
}
/// Fully normalize all the types found within `ty` in context of `owner` body definition.
///
/// This is appropriate to use only after type-check: it assumes
@ -558,6 +562,9 @@ impl InferenceResult {
ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
}
}
pub fn is_erroneous(&self) -> bool {
self.has_errors && self.type_of_expr.iter().count() == 0
}
}
impl Index<ExprId> for InferenceResult {

View File

@ -1604,6 +1604,14 @@ pub(crate) fn impl_self_ty_with_diagnostics_query(
)
}
pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
db: &dyn HirDatabase,
impl_id: ImplId,
) -> (Binders<Ty>, Diagnostics) {
let generics = generics(db, impl_id.into());
(make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
}
pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
db.const_param_ty_with_diagnostics(def).0
}
@ -1633,12 +1641,12 @@ pub(crate) fn const_param_ty_with_diagnostics_query(
(ty, create_diagnostics(ctx.diagnostics))
}
pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
db: &dyn HirDatabase,
impl_id: ImplId,
) -> (Binders<Ty>, Diagnostics) {
let generics = generics(db, impl_id.into());
(make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
pub(crate) fn const_param_ty_with_diagnostics_cycle_result(
_: &dyn HirDatabase,
_: crate::db::HirDatabaseData,
_: ConstParamId,
) -> (Ty, Diagnostics) {
(TyKind::Error.intern(Interner), None)
}
pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {

View File

@ -2182,7 +2182,7 @@ pub fn lower_to_mir(
// need to take this input explicitly.
root_expr: ExprId,
) -> Result<MirBody> {
if infer.type_mismatches().next().is_some() {
if infer.type_mismatches().next().is_some() || infer.is_erroneous() {
return Err(MirLowerError::HasErrors);
}
let mut ctx = MirLowerCtx::new(db, owner, body, infer);

View File

@ -2301,3 +2301,51 @@ trait Foo {
"#]],
);
}
#[test]
fn no_panic_on_recursive_const() {
check_infer(
r#"
struct Foo<const N: usize> {}
impl<const N: Foo<N>> Foo<N> {
fn foo(self) {}
}
fn test() {
let _ = N;
}
"#,
expect![[r#"
72..76 'self': Foo<N>
78..80 '{}': ()
94..112 '{ ...= N; }': ()
104..105 '_': {unknown}
108..109 'N': {unknown}
"#]],
);
check_infer(
r#"
struct Foo<const N: usize>;
const N: Foo<N> = Foo;
impl<const N: usize> Foo<N> {
fn foo(self) -> usize {
N
}
}
fn test() {
let _ = N;
}
"#,
expect![[r#"
93..97 'self': Foo<N>
108..125 '{ ... }': usize
118..119 'N': usize
139..157 '{ ...= N; }': ()
149..150 '_': Foo<_>
153..154 'N': Foo<_>
"#]],
);
}