mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-04 02:54:00 +00:00
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 <flodiebold@gmail.com>
This commit is contained in:
commit
9e3517f8f3
@ -986,20 +986,21 @@ impl<'a> InferenceContext<'a> {
|
||||
inputs: Vec<Ty>,
|
||||
) -> Vec<Ty> {
|
||||
if let Some(expected_ty) = expected_output.to_option(&mut self.table) {
|
||||
let snapshot = self.table.snapshot();
|
||||
let result = if self.table.try_unify(&expected_ty, &output).is_ok() {
|
||||
// FIXME: the unification could introduce lifetime variables, which we'd need to handle here
|
||||
self.table.resolve_with_fallback(inputs, |var, kind, _, _| match kind {
|
||||
chalk_ir::VariableKind::Ty(tk) => var.to_ty(&Interner, tk).cast(&Interner),
|
||||
chalk_ir::VariableKind::Lifetime => var.to_lifetime(&Interner).cast(&Interner),
|
||||
chalk_ir::VariableKind::Const(ty) => {
|
||||
var.to_const(&Interner, ty).cast(&Interner)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
self.table.rollback_to(snapshot);
|
||||
let result = self.table.fudge_inference(|table| {
|
||||
if table.try_unify(&expected_ty, &output).is_ok() {
|
||||
table.resolve_with_fallback(inputs, |var, kind, _, _| match kind {
|
||||
chalk_ir::VariableKind::Ty(tk) => var.to_ty(&Interner, tk).cast(&Interner),
|
||||
chalk_ir::VariableKind::Lifetime => {
|
||||
var.to_lifetime(&Interner).cast(&Interner)
|
||||
}
|
||||
chalk_ir::VariableKind::Const(ty) => {
|
||||
var.to_const(&Interner, ty).cast(&Interner)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
});
|
||||
result
|
||||
} else {
|
||||
Vec::new()
|
||||
|
@ -11,9 +11,9 @@ use ena::unify::UnifyKey;
|
||||
|
||||
use super::{InferOk, InferResult, InferenceContext, TypeError};
|
||||
use crate::{
|
||||
db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical,
|
||||
DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, ProjectionTy,
|
||||
Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
|
||||
db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, Const,
|
||||
DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime,
|
||||
ProjectionTy, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
|
||||
};
|
||||
|
||||
impl<'a> InferenceContext<'a> {
|
||||
@ -273,6 +273,16 @@ impl<'a> InferenceTable<'a> {
|
||||
self.new_var(TyVariableKind::General, true)
|
||||
}
|
||||
|
||||
pub(crate) fn new_const_var(&mut self, ty: Ty) -> Const {
|
||||
let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
|
||||
var.to_const(&Interner, ty)
|
||||
}
|
||||
|
||||
pub(crate) fn new_lifetime_var(&mut self) -> Lifetime {
|
||||
let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
|
||||
var.to_lifetime(&Interner)
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_with_fallback<T>(
|
||||
&mut self,
|
||||
t: T,
|
||||
@ -388,6 +398,76 @@ impl<'a> InferenceTable<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fudge_inference<T: Fold<Interner>>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T::Result {
|
||||
use chalk_ir::fold::Folder;
|
||||
struct VarFudger<'a, 'b> {
|
||||
table: &'a mut InferenceTable<'b>,
|
||||
highest_known_var: InferenceVar,
|
||||
}
|
||||
impl<'a, 'b> Folder<'static, Interner> for VarFudger<'a, 'b> {
|
||||
fn as_dyn(&mut self) -> &mut dyn Folder<'static, Interner> {
|
||||
self
|
||||
}
|
||||
|
||||
fn interner(&self) -> &'static Interner {
|
||||
&Interner
|
||||
}
|
||||
|
||||
fn fold_inference_ty(
|
||||
&mut self,
|
||||
var: chalk_ir::InferenceVar,
|
||||
kind: TyVariableKind,
|
||||
_outer_binder: chalk_ir::DebruijnIndex,
|
||||
) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
|
||||
Ok(if var < self.highest_known_var {
|
||||
var.to_ty(&Interner, kind)
|
||||
} else {
|
||||
self.table.new_type_var()
|
||||
})
|
||||
}
|
||||
|
||||
fn fold_inference_lifetime(
|
||||
&mut self,
|
||||
var: chalk_ir::InferenceVar,
|
||||
_outer_binder: chalk_ir::DebruijnIndex,
|
||||
) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
|
||||
Ok(if var < self.highest_known_var {
|
||||
var.to_lifetime(&Interner)
|
||||
} else {
|
||||
self.table.new_lifetime_var()
|
||||
})
|
||||
}
|
||||
|
||||
fn fold_inference_const(
|
||||
&mut self,
|
||||
ty: chalk_ir::Ty<Interner>,
|
||||
var: chalk_ir::InferenceVar,
|
||||
_outer_binder: chalk_ir::DebruijnIndex,
|
||||
) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
|
||||
Ok(if var < self.highest_known_var {
|
||||
var.to_const(&Interner, ty)
|
||||
} else {
|
||||
self.table.new_const_var(ty)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let snapshot = self.snapshot();
|
||||
let highest_known_var =
|
||||
self.new_type_var().inference_var(&Interner).expect("inference_var");
|
||||
let result = f(self);
|
||||
self.rollback_to(snapshot);
|
||||
|
||||
let result = result
|
||||
.fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
|
||||
.expect("fold_with with VarFudger");
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// This checks whether any of the free variables in the `canonicalized`
|
||||
/// have changed (either been unified with another variable, or with a
|
||||
/// value). If this is not the case, we don't need to try to solve the goal
|
||||
|
@ -1114,3 +1114,34 @@ fn test() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn coerce_diesel_panic() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: option
|
||||
|
||||
trait TypeMetadata {
|
||||
type MetadataLookup;
|
||||
}
|
||||
|
||||
pub struct Output<'a, T, DB>
|
||||
where
|
||||
DB: TypeMetadata,
|
||||
DB::MetadataLookup: 'a,
|
||||
{
|
||||
out: T,
|
||||
metadata_lookup: Option<&'a DB::MetadataLookup>,
|
||||
}
|
||||
|
||||
impl<'a, T, DB: TypeMetadata> Output<'a, T, DB> {
|
||||
pub fn new(out: T, metadata_lookup: &'a DB::MetadataLookup) -> Self {
|
||||
Output {
|
||||
out,
|
||||
metadata_lookup: Some(metadata_lookup),
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user