mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Show fn traits in signature info for trait implementors
This commit is contained in:
parent
0de904d539
commit
7bd343e085
8 changed files with 195 additions and 67 deletions
|
@ -797,19 +797,22 @@ impl<'a> InferenceTable<'a> {
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let projection = {
|
let b = TyBuilder::trait_ref(self.db, fn_once_trait);
|
||||||
let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
|
if b.remaining() != 2 {
|
||||||
if b.remaining() != 2 {
|
return None;
|
||||||
return None;
|
}
|
||||||
}
|
let mut trait_ref = b.push(ty.clone()).push(arg_ty).build();
|
||||||
let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
|
|
||||||
|
|
||||||
TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
|
let projection = {
|
||||||
.build()
|
TyBuilder::assoc_type_projection(
|
||||||
|
self.db,
|
||||||
|
output_assoc_type,
|
||||||
|
Some(trait_ref.substitution.clone()),
|
||||||
|
)
|
||||||
|
.build()
|
||||||
};
|
};
|
||||||
|
|
||||||
let trait_env = self.trait_env.env.clone();
|
let trait_env = self.trait_env.env.clone();
|
||||||
let mut trait_ref = projection.trait_ref(self.db);
|
|
||||||
let obligation = InEnvironment {
|
let obligation = InEnvironment {
|
||||||
goal: trait_ref.clone().cast(Interner),
|
goal: trait_ref.clone().cast(Interner),
|
||||||
environment: trait_env.clone(),
|
environment: trait_env.clone(),
|
||||||
|
|
|
@ -570,6 +570,10 @@ impl CallableSig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn abi(&self) -> FnAbi {
|
||||||
|
self.abi
|
||||||
|
}
|
||||||
|
|
||||||
pub fn params(&self) -> &[Ty] {
|
pub fn params(&self) -> &[Ty] {
|
||||||
&self.params_and_return[0..self.params_and_return.len() - 1]
|
&self.params_and_return[0..self.params_and_return.len() - 1]
|
||||||
}
|
}
|
||||||
|
@ -892,20 +896,16 @@ where
|
||||||
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(
|
pub fn callable_sig_from_fn_trait(
|
||||||
mut self_ty: &Ty,
|
self_ty: &Ty,
|
||||||
env: Arc<TraitEnvironment>,
|
trait_env: Arc<TraitEnvironment>,
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
) -> Option<CallableSig> {
|
) -> Option<(FnTrait, CallableSig)> {
|
||||||
if let Some((ty, _, _)) = self_ty.as_reference() {
|
let krate = trait_env.krate;
|
||||||
// This will happen when it implements fn or fn mut, since we add a autoborrow adjustment
|
|
||||||
self_ty = ty;
|
|
||||||
}
|
|
||||||
let krate = env.krate;
|
|
||||||
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 table = InferenceTable::new(db, env);
|
let mut table = InferenceTable::new(db, trait_env.clone());
|
||||||
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;
|
||||||
|
@ -915,23 +915,56 @@ pub fn callable_sig_from_fnonce(
|
||||||
// - Self: FnOnce<?args_ty>
|
// - Self: FnOnce<?args_ty>
|
||||||
// - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
|
// - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
|
||||||
let args_ty = table.new_type_var();
|
let args_ty = table.new_type_var();
|
||||||
let trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
|
let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
|
||||||
let projection = TyBuilder::assoc_type_projection(
|
let projection = TyBuilder::assoc_type_projection(
|
||||||
db,
|
db,
|
||||||
output_assoc_type,
|
output_assoc_type,
|
||||||
Some(trait_ref.substitution.clone()),
|
Some(trait_ref.substitution.clone()),
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
table.register_obligation(trait_ref.cast(Interner));
|
|
||||||
let ret_ty = table.normalize_projection_ty(projection);
|
|
||||||
|
|
||||||
let ret_ty = table.resolve_completely(ret_ty);
|
let block = trait_env.block;
|
||||||
let args_ty = table.resolve_completely(args_ty);
|
let trait_env = trait_env.env.clone();
|
||||||
|
let obligation =
|
||||||
|
InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() };
|
||||||
|
let canonical = table.canonicalize(obligation.clone());
|
||||||
|
if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() {
|
||||||
|
table.register_obligation(obligation.goal);
|
||||||
|
let return_ty = table.normalize_projection_ty(projection);
|
||||||
|
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
|
||||||
|
let fn_x_trait = fn_x.get_id(db, krate)?;
|
||||||
|
trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
|
||||||
|
let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment {
|
||||||
|
goal: trait_ref.clone().cast(Interner),
|
||||||
|
environment: trait_env.clone(),
|
||||||
|
};
|
||||||
|
let canonical = table.canonicalize(obligation.clone());
|
||||||
|
if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() {
|
||||||
|
let ret_ty = table.resolve_completely(return_ty);
|
||||||
|
let args_ty = table.resolve_completely(args_ty);
|
||||||
|
let params = args_ty
|
||||||
|
.as_tuple()?
|
||||||
|
.iter(Interner)
|
||||||
|
.map(|it| it.assert_ty_ref(Interner))
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
let params =
|
return Some((
|
||||||
args_ty.as_tuple()?.iter(Interner).map(|it| it.assert_ty_ref(Interner)).cloned().collect();
|
fn_x,
|
||||||
|
CallableSig::from_params_and_return(
|
||||||
Some(CallableSig::from_params_and_return(params, ret_ty, false, Safety::Safe, FnAbi::RustCall))
|
params,
|
||||||
|
ret_ty,
|
||||||
|
false,
|
||||||
|
Safety::Safe,
|
||||||
|
FnAbi::RustCall,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!("It should at least implement FnOnce at this point");
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PlaceholderCollector<'db> {
|
struct PlaceholderCollector<'db> {
|
||||||
|
|
|
@ -221,6 +221,14 @@ impl fmt::Display for FnTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnTrait {
|
impl FnTrait {
|
||||||
|
pub const fn function_name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
FnTrait::FnOnce => "call_once",
|
||||||
|
FnTrait::FnMut => "call_mut",
|
||||||
|
FnTrait::Fn => "call",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fn lang_item(self) -> LangItem {
|
const fn lang_item(self) -> LangItem {
|
||||||
match self {
|
match self {
|
||||||
FnTrait::FnOnce => LangItem::FnOnce,
|
FnTrait::FnOnce => LangItem::FnOnce,
|
||||||
|
|
|
@ -140,7 +140,7 @@ pub use {
|
||||||
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
|
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
|
||||||
layout::LayoutError,
|
layout::LayoutError,
|
||||||
mir::{MirEvalError, MirLowerError},
|
mir::{MirEvalError, MirLowerError},
|
||||||
PointerCast, Safety,
|
FnAbi, PointerCast, Safety,
|
||||||
},
|
},
|
||||||
// FIXME: Properly encapsulate mir
|
// FIXME: Properly encapsulate mir
|
||||||
hir_ty::{mir, Interner as ChalkTyInterner},
|
hir_ty::{mir, Interner as ChalkTyInterner},
|
||||||
|
@ -2227,7 +2227,7 @@ impl Param {
|
||||||
let InFile { file_id, value } = Function { id: func }.source(db)?;
|
let InFile { file_id, value } = Function { id: func }.source(db)?;
|
||||||
let params = value.param_list()?;
|
let params = value.param_list()?;
|
||||||
if let Some(self_param) = params.self_param() {
|
if let Some(self_param) = params.self_param() {
|
||||||
if let Some(idx) = self.idx.checked_sub(1 as usize) {
|
if let Some(idx) = self.idx.checked_sub(1) {
|
||||||
params.params().nth(idx).map(Either::Right)
|
params.params().nth(idx).map(Either::Right)
|
||||||
} else {
|
} else {
|
||||||
Some(Either::Left(self_param))
|
Some(Either::Left(self_param))
|
||||||
|
@ -4321,23 +4321,26 @@ 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)?),
|
||||||
kind => {
|
kind => {
|
||||||
// This branch shouldn't be necessary?
|
// This will happen when it implements fn or fn mut, since we add an autoborrow adjustment
|
||||||
if let TyKind::Ref(_, _, ty) = kind {
|
let (ty, kind) = if let TyKind::Ref(_, _, ty) = kind {
|
||||||
if let TyKind::Closure(closure, subst) = ty.kind(Interner) {
|
(ty, ty.kind(Interner))
|
||||||
let sig = ty.callable_sig(db)?;
|
} else {
|
||||||
return Some(Callable {
|
(&self.ty, kind)
|
||||||
ty: self.clone(),
|
};
|
||||||
sig,
|
if let TyKind::Closure(closure, subst) = kind {
|
||||||
callee: Callee::Closure(*closure, subst.clone()),
|
let sig = ty.callable_sig(db)?;
|
||||||
is_bound_method: false,
|
return Some(Callable {
|
||||||
});
|
ty: self.clone(),
|
||||||
}
|
sig,
|
||||||
|
callee: Callee::Closure(*closure, subst.clone()),
|
||||||
|
is_bound_method: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
let sig = hir_ty::callable_sig_from_fnonce(&self.ty, self.env.clone(), db)?;
|
let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(ty, self.env.clone(), db)?;
|
||||||
return Some(Callable {
|
return Some(Callable {
|
||||||
ty: self.clone(),
|
ty: self.clone(),
|
||||||
sig,
|
sig,
|
||||||
callee: Callee::Other,
|
callee: Callee::FnImpl(fn_trait),
|
||||||
is_bound_method: false,
|
is_bound_method: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4968,7 +4971,7 @@ enum Callee {
|
||||||
Def(CallableDefId),
|
Def(CallableDefId),
|
||||||
Closure(ClosureId, Substitution),
|
Closure(ClosureId, Substitution),
|
||||||
FnPtr,
|
FnPtr,
|
||||||
Other,
|
FnImpl(FnTrait),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum CallableKind {
|
pub enum CallableKind {
|
||||||
|
@ -4977,8 +4980,7 @@ pub enum CallableKind {
|
||||||
TupleEnumVariant(Variant),
|
TupleEnumVariant(Variant),
|
||||||
Closure(Closure),
|
Closure(Closure),
|
||||||
FnPtr,
|
FnPtr,
|
||||||
/// Some other type that implements `FnOnce`.
|
FnImpl(FnTrait),
|
||||||
Other,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Callable {
|
impl Callable {
|
||||||
|
@ -4993,7 +4995,7 @@ impl Callable {
|
||||||
CallableKind::Closure(Closure { id, subst: subst.clone() })
|
CallableKind::Closure(Closure { id, subst: subst.clone() })
|
||||||
}
|
}
|
||||||
Callee::FnPtr => CallableKind::FnPtr,
|
Callee::FnPtr => CallableKind::FnPtr,
|
||||||
Callee::Other => CallableKind::Other,
|
Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(SelfParam, Type)> {
|
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(SelfParam, Type)> {
|
||||||
|
@ -5023,6 +5025,10 @@ impl Callable {
|
||||||
pub fn sig(&self) -> &CallableSig {
|
pub fn sig(&self) -> &CallableSig {
|
||||||
&self.sig
|
&self.sig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ty(&self) -> &Type {
|
||||||
|
&self.ty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
|
|
@ -307,7 +307,8 @@ impl SourceAnalyzer {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
call: &ast::Expr,
|
call: &ast::Expr,
|
||||||
) -> Option<Callable> {
|
) -> Option<Callable> {
|
||||||
self.type_of_expr(db, &call.clone())?.0.as_callable(db)
|
let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
|
||||||
|
adjusted.unwrap_or(orig).as_callable(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_field(
|
pub(crate) fn resolve_field(
|
||||||
|
|
|
@ -60,10 +60,7 @@ pub fn callable_for_node(
|
||||||
token: &SyntaxToken,
|
token: &SyntaxToken,
|
||||||
) -> Option<(hir::Callable, Option<usize>)> {
|
) -> Option<(hir::Callable, Option<usize>)> {
|
||||||
let callable = match calling_node {
|
let callable = match calling_node {
|
||||||
ast::CallableExpr::Call(call) => {
|
ast::CallableExpr::Call(call) => sema.resolve_expr_as_callable(&call.expr()?),
|
||||||
let expr = call.expr()?;
|
|
||||||
sema.type_of_expr(&expr)?.adjusted().as_callable(sema.db)
|
|
||||||
}
|
|
||||||
ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call),
|
ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call),
|
||||||
}?;
|
}?;
|
||||||
let active_param = calling_node.arg_list().map(|arg_list| {
|
let active_param = calling_node.arg_list().map(|arg_list| {
|
||||||
|
|
|
@ -109,12 +109,12 @@ pub(crate) fn outgoing_calls(
|
||||||
let expr = call.expr()?;
|
let expr = call.expr()?;
|
||||||
let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?;
|
let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?;
|
||||||
match callable.kind() {
|
match callable.kind() {
|
||||||
hir::CallableKind::Function(it) => {
|
hir::CallableKind::Function(it) => it.try_to_nav(db),
|
||||||
let range = expr.syntax().text_range();
|
hir::CallableKind::TupleEnumVariant(it) => it.try_to_nav(db),
|
||||||
it.try_to_nav(db).zip(Some(range))
|
hir::CallableKind::TupleStruct(it) => it.try_to_nav(db),
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
.zip(Some(expr.syntax().text_range()))
|
||||||
}
|
}
|
||||||
ast::CallableExpr::MethodCall(expr) => {
|
ast::CallableExpr::MethodCall(expr) => {
|
||||||
let range = expr.name_ref()?.syntax().text_range();
|
let range = expr.name_ref()?.syntax().text_range();
|
||||||
|
|
|
@ -202,9 +202,20 @@ fn signature_help_for_call(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hir::CallableKind::Closure(closure) => {
|
hir::CallableKind::Closure(closure) => {
|
||||||
format_to!(res.signature, "impl {}", closure.fn_trait(db));
|
let fn_trait = closure.fn_trait(db);
|
||||||
|
format_to!(res.signature, "impl {fn_trait}")
|
||||||
}
|
}
|
||||||
hir::CallableKind::FnPtr | hir::CallableKind::Other => (),
|
hir::CallableKind::FnPtr => format_to!(res.signature, "fn"),
|
||||||
|
hir::CallableKind::FnImpl(fn_trait) => match callable.ty().as_adt() {
|
||||||
|
// FIXME: Render docs of the concrete trait impl function
|
||||||
|
Some(adt) => format_to!(
|
||||||
|
res.signature,
|
||||||
|
"<{} as {fn_trait}>::{}",
|
||||||
|
adt.name(db).display(db),
|
||||||
|
fn_trait.function_name()
|
||||||
|
),
|
||||||
|
None => format_to!(res.signature, "impl {fn_trait}"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
res.signature.push('(');
|
res.signature.push('(');
|
||||||
|
@ -250,7 +261,7 @@ fn signature_help_for_call(
|
||||||
hir::CallableKind::Function(_)
|
hir::CallableKind::Function(_)
|
||||||
| hir::CallableKind::Closure(_)
|
| hir::CallableKind::Closure(_)
|
||||||
| hir::CallableKind::FnPtr
|
| hir::CallableKind::FnPtr
|
||||||
| hir::CallableKind::Other => render(callable.return_type()),
|
| hir::CallableKind::FnImpl(_) => render(callable.return_type()),
|
||||||
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
||||||
}
|
}
|
||||||
Some(res)
|
Some(res)
|
||||||
|
@ -1417,12 +1428,81 @@ fn main(f: fn(i32, f64) -> char) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
(i32, f64) -> char
|
fn(i32, f64) -> char
|
||||||
--- ^^^
|
--- ^^^
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_info_for_fn_impl() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl core::ops::FnOnce<(i32, f64)> for S {
|
||||||
|
type Output = char;
|
||||||
|
}
|
||||||
|
impl core::ops::FnMut<(i32, f64)> for S {}
|
||||||
|
impl core::ops::Fn<(i32, f64)> for S {}
|
||||||
|
fn main() {
|
||||||
|
S($0);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
<S as Fn>::call(i32, f64) -> char
|
||||||
|
^^^ ---
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl core::ops::FnOnce<(i32, f64)> for S {
|
||||||
|
type Output = char;
|
||||||
|
}
|
||||||
|
impl core::ops::FnMut<(i32, f64)> for S {}
|
||||||
|
impl core::ops::Fn<(i32, f64)> for S {}
|
||||||
|
fn main() {
|
||||||
|
S(1, $0);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
<S as Fn>::call(i32, f64) -> char
|
||||||
|
--- ^^^
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl core::ops::FnOnce<(i32, f64)> for S {
|
||||||
|
type Output = char;
|
||||||
|
}
|
||||||
|
impl core::ops::FnOnce<(char, char)> for S {
|
||||||
|
type Output = f64;
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
S($0);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![""],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct S;
|
||||||
|
impl core::ops::FnOnce<(i32, f64)> for S {
|
||||||
|
type Output = char;
|
||||||
|
}
|
||||||
|
impl core::ops::FnOnce<(char, char)> for S {
|
||||||
|
type Output = f64;
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
// FIXME: The ide layer loses the calling info here so we get an ambiguous trait solve result
|
||||||
|
S(0i32, $0);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![""],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn call_info_for_unclosed_call() {
|
fn call_info_for_unclosed_call() {
|
||||||
check(
|
check(
|
||||||
|
@ -1828,19 +1908,19 @@ fn f<F: FnOnce(u8, u16) -> i32>(f: F) {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
(u8, u16) -> i32
|
impl FnOnce(u8, u16) -> i32
|
||||||
^^ ---
|
^^ ---
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
fn f<T, F: FnOnce(&T, u16) -> &T>(f: F) {
|
fn f<T, F: FnMut(&T, u16) -> &T>(f: F) {
|
||||||
f($0)
|
f($0)
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
(&T, u16) -> &T
|
impl FnMut(&T, u16) -> &T
|
||||||
^^ ---
|
^^ ---
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1860,7 +1940,7 @@ fn take<C, Error>(
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
() -> i32
|
impl Fn() -> i32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue