Create Callable
s for generic types implementing FnOnce
This commit is contained in:
parent
07f6efc4e7
commit
ecad1a9a6e
@ -38,10 +38,12 @@ macro_rules! eprintln {
|
|||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
fold::{Shift, TypeFoldable},
|
fold::{Shift, TypeFoldable},
|
||||||
interner::HasInterner,
|
interner::HasInterner,
|
||||||
NoSolution,
|
NoSolution, UniverseIndex,
|
||||||
};
|
};
|
||||||
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
|
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
|
||||||
|
use hir_expand::name;
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
|
use traits::FnTrait;
|
||||||
use utils::Generics;
|
use utils::Generics;
|
||||||
|
|
||||||
use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
|
use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
|
||||||
@ -508,3 +510,68 @@ fn try_fold_free_var_lifetime(
|
|||||||
});
|
});
|
||||||
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
|
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn callable_sig_from_fnonce(
|
||||||
|
self_ty: &Canonical<Ty>,
|
||||||
|
env: Arc<TraitEnvironment>,
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
) -> Option<CallableSig> {
|
||||||
|
let krate = env.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 mut kinds = self_ty.binders.interned().to_vec();
|
||||||
|
let b = TyBuilder::trait_ref(db, fn_once_trait);
|
||||||
|
if b.remaining() != 2 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let fn_once = b
|
||||||
|
.push(self_ty.value.clone())
|
||||||
|
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
|
||||||
|
.build();
|
||||||
|
kinds.extend(fn_once.substitution.iter(Interner).skip(1).map(|x| {
|
||||||
|
let vk = match x.data(Interner) {
|
||||||
|
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::VariableKind::Const(c.data(Interner).ty.clone())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
let trait_env = env.env.clone();
|
||||||
|
let obligation = InEnvironment { goal: fn_once.cast(Interner), environment: trait_env };
|
||||||
|
let canonical =
|
||||||
|
Canonical { binders: CanonicalVarKinds::from_iter(Interner, kinds), value: obligation };
|
||||||
|
let subst = match db.trait_solve(krate, canonical) {
|
||||||
|
Some(Solution::Unique(vars)) => vars.value.subst,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let args = subst.at(Interner, self_ty.binders.interned().len()).ty(Interner)?;
|
||||||
|
let params = match args.kind(Interner) {
|
||||||
|
chalk_ir::TyKind::Tuple(_, subst) => {
|
||||||
|
subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
if params.iter().any(|ty| ty.is_unknown()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fn_once = TyBuilder::trait_ref(db, fn_once_trait)
|
||||||
|
.push(self_ty.value.clone())
|
||||||
|
.push(args.clone())
|
||||||
|
.build();
|
||||||
|
let projection =
|
||||||
|
TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let ret_ty = db.normalize_projection(projection, env);
|
||||||
|
|
||||||
|
Some(CallableSig::from_params_and_return(params, ret_ty.clone(), false))
|
||||||
|
}
|
||||||
|
@ -2995,7 +2995,17 @@ pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
|
|||||||
let callee = match self.ty.kind(Interner) {
|
let callee = match self.ty.kind(Interner) {
|
||||||
TyKind::Closure(id, _) => Callee::Closure(*id),
|
TyKind::Closure(id, _) => Callee::Closure(*id),
|
||||||
TyKind::Function(_) => Callee::FnPtr,
|
TyKind::Function(_) => Callee::FnPtr,
|
||||||
_ => 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(&ty, self.env.clone(), db)?;
|
||||||
|
return Some(Callable {
|
||||||
|
ty: self.clone(),
|
||||||
|
sig,
|
||||||
|
callee: Callee::Other,
|
||||||
|
is_bound_method: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let sig = self.ty.callable_sig(db)?;
|
let sig = self.ty.callable_sig(db)?;
|
||||||
@ -3464,6 +3474,7 @@ enum Callee {
|
|||||||
Def(CallableDefId),
|
Def(CallableDefId),
|
||||||
Closure(ClosureId),
|
Closure(ClosureId),
|
||||||
FnPtr,
|
FnPtr,
|
||||||
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum CallableKind {
|
pub enum CallableKind {
|
||||||
@ -3472,6 +3483,8 @@ pub enum CallableKind {
|
|||||||
TupleEnumVariant(Variant),
|
TupleEnumVariant(Variant),
|
||||||
Closure,
|
Closure,
|
||||||
FnPtr,
|
FnPtr,
|
||||||
|
/// Some other type that implements `FnOnce`.
|
||||||
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Callable {
|
impl Callable {
|
||||||
@ -3483,6 +3496,7 @@ pub fn kind(&self) -> CallableKind {
|
|||||||
Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
|
Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
|
||||||
Closure(_) => CallableKind::Closure,
|
Closure(_) => CallableKind::Closure,
|
||||||
FnPtr => CallableKind::FnPtr,
|
FnPtr => CallableKind::FnPtr,
|
||||||
|
Other => CallableKind::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
|
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
|
||||||
|
@ -149,7 +149,7 @@ fn signature_help_for_call(
|
|||||||
variant.name(db)
|
variant.name(db)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hir::CallableKind::Closure | hir::CallableKind::FnPtr => (),
|
hir::CallableKind::Closure | hir::CallableKind::FnPtr | hir::CallableKind::Other => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
res.signature.push('(');
|
res.signature.push('(');
|
||||||
@ -189,9 +189,10 @@ fn signature_help_for_call(
|
|||||||
hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
|
hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
|
||||||
render(func.ret_type(db))
|
render(func.ret_type(db))
|
||||||
}
|
}
|
||||||
hir::CallableKind::Function(_) | hir::CallableKind::Closure | hir::CallableKind::FnPtr => {
|
hir::CallableKind::Function(_)
|
||||||
render(callable.return_type())
|
| hir::CallableKind::Closure
|
||||||
}
|
| hir::CallableKind::FnPtr
|
||||||
|
| hir::CallableKind::Other => render(callable.return_type()),
|
||||||
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
||||||
}
|
}
|
||||||
Some(res)
|
Some(res)
|
||||||
@ -387,10 +388,9 @@ pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check(ra_fixture: &str, expect: Expect) {
|
fn check(ra_fixture: &str, expect: Expect) {
|
||||||
// Implicitly add `Sized` to avoid noisy `T: ?Sized` in the results.
|
|
||||||
let fixture = format!(
|
let fixture = format!(
|
||||||
r#"
|
r#"
|
||||||
#[lang = "sized"] trait Sized {{}}
|
//- minicore: sized, fn
|
||||||
{ra_fixture}
|
{ra_fixture}
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
@ -1331,4 +1331,19 @@ fn foo(self: &Self, other: Self)
|
|||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn help_for_generic_call() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn f<F: FnOnce(u8, u16) -> i32>(f: F) {
|
||||||
|
f($0)
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
(u8, u16) -> i32
|
||||||
|
^^ ---
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user