Add test for #8931 and better checking

This commit is contained in:
Florian Diebold 2021-05-23 12:52:41 +02:00
parent bc1ba1549d
commit a5d85a6356
3 changed files with 114 additions and 13 deletions

View file

@ -2053,7 +2053,7 @@ impl Type {
name: Option<&Name>, name: Option<&Name>,
mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
) -> Option<T> { ) -> Option<T> {
let canonical = hir_ty::replace_errors_with_variables(self.ty.clone()); let canonical = hir_ty::replace_errors_with_variables(&self.ty);
let env = self.env.clone(); let env = self.env.clone();
let krate = krate.id; let krate = krate.id;
@ -2222,7 +2222,7 @@ impl Type {
} }
pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool { pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone())); let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
could_unify(db, self.env.clone(), &tys) could_unify(db, self.env.clone(), &tys)
} }
} }

View file

@ -43,7 +43,6 @@ use hir_def::{
type_ref::{ConstScalar, Rawness}, type_ref::{ConstScalar, Rawness},
TypeParamId, TypeParamId,
}; };
use stdx::always;
use crate::{db::HirDatabase, utils::generics}; use crate::{db::HirDatabase, utils::generics};
@ -329,14 +328,17 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly") t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
} }
pub fn replace_errors_with_variables<T>(t: T) -> Canonical<T::Result> /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
/// ensures there are no unbound variables or inference variables anywhere in
/// the `t`.
pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T::Result>
where where
T: HasInterner<Interner = Interner> + Fold<Interner>, T: HasInterner<Interner = Interner> + Fold<Interner> + Clone,
T::Result: HasInterner<Interner = Interner>, T::Result: HasInterner<Interner = Interner>,
{ {
use chalk_ir::{ use chalk_ir::{
fold::{Folder, SuperFold}, fold::{Folder, SuperFold},
Fallible, Fallible, NoSolution,
}; };
struct ErrorReplacer { struct ErrorReplacer {
vars: usize, vars: usize,
@ -363,18 +365,88 @@ where
fn fold_inference_ty( fn fold_inference_ty(
&mut self, &mut self,
var: InferenceVar, _var: InferenceVar,
kind: TyVariableKind, _kind: TyVariableKind,
_outer_binder: DebruijnIndex, _outer_binder: DebruijnIndex,
) -> Fallible<Ty> { ) -> Fallible<Ty> {
always!(false); if cfg!(debug_assertions) {
Ok(TyKind::InferenceVar(var, kind).intern(&Interner)) // we don't want to just panic here, because then the error message
// won't contain the whole thing, which would not be very helpful
Err(NoSolution)
} else {
Ok(TyKind::Error.intern(&Interner))
}
}
fn fold_free_var_ty(
&mut self,
_bound_var: BoundVar,
_outer_binder: DebruijnIndex,
) -> Fallible<Ty> {
if cfg!(debug_assertions) {
// we don't want to just panic here, because then the error message
// won't contain the whole thing, which would not be very helpful
Err(NoSolution)
} else {
Ok(TyKind::Error.intern(&Interner))
}
}
fn fold_inference_const(
&mut self,
_ty: Ty,
_var: InferenceVar,
_outer_binder: DebruijnIndex,
) -> Fallible<Const> {
if cfg!(debug_assertions) {
Err(NoSolution)
} else {
Ok(dummy_usize_const())
}
}
fn fold_free_var_const(
&mut self,
_ty: Ty,
_bound_var: BoundVar,
_outer_binder: DebruijnIndex,
) -> Fallible<Const> {
if cfg!(debug_assertions) {
Err(NoSolution)
} else {
Ok(dummy_usize_const())
}
}
fn fold_inference_lifetime(
&mut self,
_var: InferenceVar,
_outer_binder: DebruijnIndex,
) -> Fallible<Lifetime> {
if cfg!(debug_assertions) {
Err(NoSolution)
} else {
Ok(static_lifetime())
}
}
fn fold_free_var_lifetime(
&mut self,
_bound_var: BoundVar,
_outer_binder: DebruijnIndex,
) -> Fallible<Lifetime> {
if cfg!(debug_assertions) {
Err(NoSolution)
} else {
Ok(static_lifetime())
}
} }
} }
let mut error_replacer = ErrorReplacer { vars: 0 }; let mut error_replacer = ErrorReplacer { vars: 0 };
let value = t let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
.fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) Ok(t) => t,
.expect("fold failed unexpectedly"); Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
};
let kinds = (0..error_replacer.vars).map(|_| { let kinds = (0..error_replacer.vars).map(|_| {
chalk_ir::CanonicalVarKind::new( chalk_ir::CanonicalVarKind::new(
chalk_ir::VariableKind::Ty(TyVariableKind::General), chalk_ir::VariableKind::Ty(TyVariableKind::General),

View file

@ -454,4 +454,33 @@ mod foo {
"#]], "#]],
); );
} }
#[test]
fn issue_8931() {
check(
r#"
#[lang = "fn_once"]
trait FnOnce<Args> {
type Output;
}
struct S;
struct Foo;
impl Foo {
fn foo(&self) -> &[u8] { loop {} }
}
impl S {
fn indented(&mut self, f: impl FnOnce(&mut Self)) {
}
fn f(&mut self, v: Foo) {
self.indented(|this| v.$0)
}
}
"#,
expect![[r#"
"#]],
);
}
} }