mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Add test for #8931 and better checking
This commit is contained in:
parent
bc1ba1549d
commit
a5d85a6356
3 changed files with 114 additions and 13 deletions
|
@ -2053,7 +2053,7 @@ impl Type {
|
|||
name: Option<&Name>,
|
||||
mut callback: impl FnMut(&Ty, AssocItem) -> 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 krate = krate.id;
|
||||
|
@ -2222,7 +2222,7 @@ impl Type {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ use hir_def::{
|
|||
type_ref::{ConstScalar, Rawness},
|
||||
TypeParamId,
|
||||
};
|
||||
use stdx::always;
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
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
|
||||
T: HasInterner<Interner = Interner> + Fold<Interner>,
|
||||
T: HasInterner<Interner = Interner> + Fold<Interner> + Clone,
|
||||
T::Result: HasInterner<Interner = Interner>,
|
||||
{
|
||||
use chalk_ir::{
|
||||
fold::{Folder, SuperFold},
|
||||
Fallible,
|
||||
Fallible, NoSolution,
|
||||
};
|
||||
struct ErrorReplacer {
|
||||
vars: usize,
|
||||
|
@ -363,18 +365,88 @@ where
|
|||
|
||||
fn fold_inference_ty(
|
||||
&mut self,
|
||||
var: InferenceVar,
|
||||
kind: TyVariableKind,
|
||||
_var: InferenceVar,
|
||||
_kind: TyVariableKind,
|
||||
_outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Ty> {
|
||||
always!(false);
|
||||
Ok(TyKind::InferenceVar(var, kind).intern(&Interner))
|
||||
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_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 value = t
|
||||
.fold_with(&mut error_replacer, DebruijnIndex::INNERMOST)
|
||||
.expect("fold failed unexpectedly");
|
||||
let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
|
||||
Ok(t) => t,
|
||||
Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
|
||||
};
|
||||
let kinds = (0..error_replacer.vars).map(|_| {
|
||||
chalk_ir::CanonicalVarKind::new(
|
||||
chalk_ir::VariableKind::Ty(TyVariableKind::General),
|
||||
|
|
|
@ -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#"
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue