mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-16 15:14:02 +00:00
Auto merge of #13584 - jonas-schievink:fix-signature-panic, r=jonas-schievink
fix: fix panic when computing signature of generic `FnOnce` callable Fixes https://github.com/rust-lang/rust-analyzer/issues/13579
This commit is contained in:
commit
392784ad17
3 changed files with 54 additions and 28 deletions
|
@ -523,7 +523,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn callable_sig_from_fnonce(
|
pub fn callable_sig_from_fnonce(
|
||||||
self_ty: &Canonical<Ty>,
|
self_ty: &Ty,
|
||||||
env: Arc<TraitEnvironment>,
|
env: Arc<TraitEnvironment>,
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
) -> Option<CallableSig> {
|
) -> Option<CallableSig> {
|
||||||
|
@ -531,27 +531,28 @@ pub fn callable_sig_from_fnonce(
|
||||||
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
|
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
|
||||||
let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
|
let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
|
||||||
|
|
||||||
let mut kinds = self_ty.binders.interned().to_vec();
|
|
||||||
let b = TyBuilder::trait_ref(db, fn_once_trait);
|
let b = TyBuilder::trait_ref(db, fn_once_trait);
|
||||||
if b.remaining() != 2 {
|
if b.remaining() != 2 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let fn_once = b
|
let fn_once = b.push(self_ty.clone()).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
|
||||||
.push(self_ty.value.clone())
|
let kinds = fn_once
|
||||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
|
.substitution
|
||||||
.build();
|
.iter(Interner)
|
||||||
kinds.extend(fn_once.substitution.iter(Interner).skip(1).map(|x| {
|
.skip(1)
|
||||||
let vk = match x.data(Interner) {
|
.map(|x| {
|
||||||
chalk_ir::GenericArgData::Ty(_) => {
|
let vk = match x.data(Interner) {
|
||||||
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
|
chalk_ir::GenericArgData::Ty(_) => {
|
||||||
}
|
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
|
||||||
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
|
}
|
||||||
chalk_ir::GenericArgData::Const(c) => {
|
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
|
||||||
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
|
chalk_ir::GenericArgData::Const(c) => {
|
||||||
}
|
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
|
||||||
};
|
}
|
||||||
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
|
};
|
||||||
}));
|
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
|
// FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
|
||||||
// `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
|
// `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
|
||||||
|
@ -563,21 +564,16 @@ pub fn callable_sig_from_fnonce(
|
||||||
Some(Solution::Unique(vars)) => vars.value.subst,
|
Some(Solution::Unique(vars)) => vars.value.subst,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let args = subst.at(Interner, self_ty.binders.interned().len()).ty(Interner)?;
|
let args = subst.at(Interner, 0).ty(Interner)?;
|
||||||
let params = match args.kind(Interner) {
|
let params = match args.kind(Interner) {
|
||||||
chalk_ir::TyKind::Tuple(_, subst) => {
|
chalk_ir::TyKind::Tuple(_, subst) => {
|
||||||
subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
|
subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
if params.iter().any(|ty| ty.is_unknown()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fn_once = TyBuilder::trait_ref(db, fn_once_trait)
|
let fn_once =
|
||||||
.push(self_ty.value.clone())
|
TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build();
|
||||||
.push(args.clone())
|
|
||||||
.build();
|
|
||||||
let projection =
|
let projection =
|
||||||
TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
|
TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -2997,8 +2997,7 @@ impl Type {
|
||||||
TyKind::Function(_) => Callee::FnPtr,
|
TyKind::Function(_) => Callee::FnPtr,
|
||||||
TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?),
|
TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?),
|
||||||
_ => {
|
_ => {
|
||||||
let ty = hir_ty::replace_errors_with_variables(&self.ty);
|
let sig = hir_ty::callable_sig_from_fnonce(&self.ty, self.env.clone(), db)?;
|
||||||
let sig = hir_ty::callable_sig_from_fnonce(&ty, self.env.clone(), db)?;
|
|
||||||
return Some(Callable {
|
return Some(Callable {
|
||||||
ty: self.clone(),
|
ty: self.clone(),
|
||||||
sig,
|
sig,
|
||||||
|
|
|
@ -1345,5 +1345,36 @@ fn f<F: FnOnce(u8, u16) -> i32>(f: F) {
|
||||||
^^ ---
|
^^ ---
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn f<T, F: FnOnce(&T, u16) -> &T>(f: F) {
|
||||||
|
f($0)
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
(&T, u16) -> &T
|
||||||
|
^^ ---
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regression_13579() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn f() {
|
||||||
|
take(2)($0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take<C, Error>(
|
||||||
|
count: C
|
||||||
|
) -> impl Fn() -> C {
|
||||||
|
move || count
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
() -> i32
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue