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>,
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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