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:
bors 2022-11-08 17:27:13 +00:00
commit 392784ad17
3 changed files with 54 additions and 28 deletions

View file

@ -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();

View file

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

View file

@ -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
"#]],
);
} }
} }