Skip to content

Commit 9e3517f

Browse files
Merge #9975
9975: minor: Fix panic caused by #9966 r=flodiebold a=flodiebold Chalk can introduce new type variables when doing lazy normalization, so we have to do the proper 'fudging' after all. Co-authored-by: Florian Diebold <[email protected]>
2 parents 337ccc7 + df77e24 commit 9e3517f

File tree

3 files changed

+129
-17
lines changed

3 files changed

+129
-17
lines changed

crates/hir_ty/src/infer/expr.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -986,20 +986,21 @@ impl<'a> InferenceContext<'a> {
986986
inputs: Vec<Ty>,
987987
) -> Vec<Ty> {
988988
if let Some(expected_ty) = expected_output.to_option(&mut self.table) {
989-
let snapshot = self.table.snapshot();
990-
let result = if self.table.try_unify(&expected_ty, &output).is_ok() {
991-
// FIXME: the unification could introduce lifetime variables, which we'd need to handle here
992-
self.table.resolve_with_fallback(inputs, |var, kind, _, _| match kind {
993-
chalk_ir::VariableKind::Ty(tk) => var.to_ty(&Interner, tk).cast(&Interner),
994-
chalk_ir::VariableKind::Lifetime => var.to_lifetime(&Interner).cast(&Interner),
995-
chalk_ir::VariableKind::Const(ty) => {
996-
var.to_const(&Interner, ty).cast(&Interner)
997-
}
998-
})
999-
} else {
1000-
Vec::new()
1001-
};
1002-
self.table.rollback_to(snapshot);
989+
let result = self.table.fudge_inference(|table| {
990+
if table.try_unify(&expected_ty, &output).is_ok() {
991+
table.resolve_with_fallback(inputs, |var, kind, _, _| match kind {
992+
chalk_ir::VariableKind::Ty(tk) => var.to_ty(&Interner, tk).cast(&Interner),
993+
chalk_ir::VariableKind::Lifetime => {
994+
var.to_lifetime(&Interner).cast(&Interner)
995+
}
996+
chalk_ir::VariableKind::Const(ty) => {
997+
var.to_const(&Interner, ty).cast(&Interner)
998+
}
999+
})
1000+
} else {
1001+
Vec::new()
1002+
}
1003+
});
10031004
result
10041005
} else {
10051006
Vec::new()

crates/hir_ty/src/infer/unify.rs

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ use ena::unify::UnifyKey;
1111

1212
use super::{InferOk, InferResult, InferenceContext, TypeError};
1313
use crate::{
14-
db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical,
15-
DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, ProjectionTy,
16-
Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
14+
db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, Const,
15+
DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime,
16+
ProjectionTy, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
1717
};
1818

1919
impl<'a> InferenceContext<'a> {
@@ -273,6 +273,16 @@ impl<'a> InferenceTable<'a> {
273273
self.new_var(TyVariableKind::General, true)
274274
}
275275

276+
pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const {
277+
let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
278+
var.to_const(&Interner, ty)
279+
}
280+
281+
pub(crate) fn new_lifetime_var(&mut self) -> Lifetime {
282+
let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
283+
var.to_lifetime(&Interner)
284+
}
285+
276286
pub(crate) fn resolve_with_fallback<T>(
277287
&mut self,
278288
t: T,
@@ -388,6 +398,76 @@ impl<'a> InferenceTable<'a> {
388398
}
389399
}
390400

401+
pub(crate) fn fudge_inference<T: Fold<Interner>>(
402+
&mut self,
403+
f: impl FnOnce(&mut Self) -> T,
404+
) -> T::Result {
405+
use chalk_ir::fold::Folder;
406+
struct VarFudger<'a, 'b> {
407+
table: &'a mut InferenceTable<'b>,
408+
highest_known_var: InferenceVar,
409+
}
410+
impl<'a, 'b> Folder<'static, Interner> for VarFudger<'a, 'b> {
411+
fn as_dyn(&mut self) -> &mut dyn Folder<'static, Interner> {
412+
self
413+
}
414+
415+
fn interner(&self) -> &'static Interner {
416+
&Interner
417+
}
418+
419+
fn fold_inference_ty(
420+
&mut self,
421+
var: chalk_ir::InferenceVar,
422+
kind: TyVariableKind,
423+
_outer_binder: chalk_ir::DebruijnIndex,
424+
) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
425+
Ok(if var < self.highest_known_var {
426+
var.to_ty(&Interner, kind)
427+
} else {
428+
self.table.new_type_var()
429+
})
430+
}
431+
432+
fn fold_inference_lifetime(
433+
&mut self,
434+
var: chalk_ir::InferenceVar,
435+
_outer_binder: chalk_ir::DebruijnIndex,
436+
) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
437+
Ok(if var < self.highest_known_var {
438+
var.to_lifetime(&Interner)
439+
} else {
440+
self.table.new_lifetime_var()
441+
})
442+
}
443+
444+
fn fold_inference_const(
445+
&mut self,
446+
ty: chalk_ir::Ty<Interner>,
447+
var: chalk_ir::InferenceVar,
448+
_outer_binder: chalk_ir::DebruijnIndex,
449+
) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
450+
Ok(if var < self.highest_known_var {
451+
var.to_const(&Interner, ty)
452+
} else {
453+
self.table.new_const_var(ty)
454+
})
455+
}
456+
}
457+
458+
let snapshot = self.snapshot();
459+
let highest_known_var =
460+
self.new_type_var().inference_var(&Interner).expect("inference_var");
461+
let result = f(self);
462+
self.rollback_to(snapshot);
463+
464+
let result = result
465+
.fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
466+
.expect("fold_with with VarFudger");
467+
468+
result
469+
}
470+
391471
/// This checks whether any of the free variables in the `canonicalized`
392472
/// have changed (either been unified with another variable, or with a
393473
/// value). If this is not the case, we don't need to try to solve the goal

crates/hir_ty/src/tests/regression.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,3 +1114,34 @@ fn test() {
11141114
"#,
11151115
);
11161116
}
1117+
1118+
#[test]
1119+
fn coerce_diesel_panic() {
1120+
check_no_mismatches(
1121+
r#"
1122+
//- minicore: option
1123+
1124+
trait TypeMetadata {
1125+
type MetadataLookup;
1126+
}
1127+
1128+
pub struct Output<'a, T, DB>
1129+
where
1130+
DB: TypeMetadata,
1131+
DB::MetadataLookup: 'a,
1132+
{
1133+
out: T,
1134+
metadata_lookup: Option<&'a DB::MetadataLookup>,
1135+
}
1136+
1137+
impl<'a, T, DB: TypeMetadata> Output<'a, T, DB> {
1138+
pub fn new(out: T, metadata_lookup: &'a DB::MetadataLookup) -> Self {
1139+
Output {
1140+
out,
1141+
metadata_lookup: Some(metadata_lookup),
1142+
}
1143+
}
1144+
}
1145+
"#,
1146+
);
1147+
}

0 commit comments

Comments
 (0)