Skip to content

Commit a602f13

Browse files
committedJan 4, 2019
Auto merge of #55986 - cjgillot:issue-45510, r=nikomatsakis
Allow to dispatch fn traits depending on number of parameters Hello, By following @eddyb's advise on issue #45510, I managed to have the snippets of code in #45510 and #18952 passing without breaking older diagnostics. EDIT: the codegen tests breakage I experienced is due to the poor quality of my laptop. If any kind reviewer has any advice, you are very welcome.
2 parents ae38bae + 91c155b commit a602f13

File tree

3 files changed

+309
-145
lines changed

3 files changed

+309
-145
lines changed
 

‎src/librustc_typeck/check/callee.rs

Lines changed: 221 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
21
use super::autoderef::Autoderef;
32
use super::method::MethodCallee;
3+
use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
44

5+
use errors::Applicability;
56
use hir::def::Def;
67
use hir::def_id::{DefId, LOCAL_CRATE};
8+
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
9+
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
710
use rustc::{infer, traits};
8-
use rustc::ty::{self, TyCtxt, TypeFoldable, Ty};
9-
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
11+
use rustc::infer::type_variable::TypeVariableOrigin;
1012
use rustc_target::spec::abi;
1113
use syntax::ast::Ident;
1214
use syntax_pos::Span;
13-
use errors::Applicability;
1415

1516
use rustc::hir;
1617

@@ -33,19 +34,20 @@ enum CallStep<'tcx> {
3334
}
3435

3536
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
36-
pub fn check_call(&self,
37-
call_expr: &'gcx hir::Expr,
38-
callee_expr: &'gcx hir::Expr,
39-
arg_exprs: &'gcx [hir::Expr],
40-
expected: Expectation<'tcx>)
41-
-> Ty<'tcx> {
37+
pub fn check_call(
38+
&self,
39+
call_expr: &'gcx hir::Expr,
40+
callee_expr: &'gcx hir::Expr,
41+
arg_exprs: &'gcx [hir::Expr],
42+
expected: Expectation<'tcx>,
43+
) -> Ty<'tcx> {
4244
let original_callee_ty = self.check_expr(callee_expr);
4345
let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
4446

4547
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
4648
let mut result = None;
4749
while result.is_none() && autoderef.next().is_some() {
48-
result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef);
50+
result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
4951
}
5052
autoderef.finalize(self);
5153

@@ -74,15 +76,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
7476
output
7577
}
7678

77-
fn try_overloaded_call_step(&self,
78-
call_expr: &'gcx hir::Expr,
79-
callee_expr: &'gcx hir::Expr,
80-
autoderef: &Autoderef<'a, 'gcx, 'tcx>)
81-
-> Option<CallStep<'tcx>> {
79+
fn try_overloaded_call_step(
80+
&self,
81+
call_expr: &'gcx hir::Expr,
82+
callee_expr: &'gcx hir::Expr,
83+
arg_exprs: &'gcx [hir::Expr],
84+
autoderef: &Autoderef<'a, 'gcx, 'tcx>,
85+
) -> Option<CallStep<'tcx>> {
8286
let adjusted_ty = autoderef.unambiguous_final_ty(self);
83-
debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
84-
call_expr,
85-
adjusted_ty);
87+
debug!(
88+
"try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
89+
call_expr, adjusted_ty
90+
);
8691

8792
// If the callee is a bare function or a closure, then we're all set.
8893
match adjusted_ty.sty {
@@ -100,21 +105,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
100105
// fnmut vs fnonce. If so, we have to defer further processing.
101106
if self.closure_kind(def_id, substs).is_none() {
102107
let closure_ty = self.closure_sig(def_id, substs);
103-
let fn_sig = self.replace_bound_vars_with_fresh_vars(
104-
call_expr.span,
105-
infer::FnCall,
106-
&closure_ty
107-
).0;
108+
let fn_sig = self
109+
.replace_bound_vars_with_fresh_vars(
110+
call_expr.span,
111+
infer::FnCall,
112+
&closure_ty,
113+
)
114+
.0;
108115
let adjustments = autoderef.adjust_steps(self, Needs::None);
109-
self.record_deferred_call_resolution(def_id, DeferredCallResolution {
110-
call_expr,
111-
callee_expr,
112-
adjusted_ty,
113-
adjustments,
114-
fn_sig,
115-
closure_def_id: def_id,
116-
closure_substs: substs,
117-
});
116+
self.record_deferred_call_resolution(
117+
def_id,
118+
DeferredCallResolution {
119+
call_expr,
120+
callee_expr,
121+
adjusted_ty,
122+
adjustments,
123+
fn_sig,
124+
closure_def_id: def_id,
125+
closure_substs: substs,
126+
},
127+
);
118128
return Some(CallStep::DeferredClosure(fn_sig));
119129
}
120130
}
@@ -134,34 +144,68 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
134144
_ => {}
135145
}
136146

137-
self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
138-
let mut adjustments = autoderef.adjust_steps(self, Needs::None);
139-
adjustments.extend(autoref);
140-
self.apply_adjustments(callee_expr, adjustments);
141-
CallStep::Overloaded(method)
142-
})
147+
// Now, we look for the implementation of a Fn trait on the object's type.
148+
// We first do it with the explicit instruction to look for an impl of
149+
// `Fn<Tuple>`, with the tuple `Tuple` having an arity corresponding
150+
// to the number of call parameters.
151+
// If that fails (or_else branch), we try again without specifying the
152+
// shape of the tuple (hence the None). This allows to detect an Fn trait
153+
// is implemented, and use this information for diagnostic.
154+
self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs))
155+
.or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None))
156+
.map(|(autoref, method)| {
157+
let mut adjustments = autoderef.adjust_steps(self, Needs::None);
158+
adjustments.extend(autoref);
159+
self.apply_adjustments(callee_expr, adjustments);
160+
CallStep::Overloaded(method)
161+
})
143162
}
144163

145-
fn try_overloaded_call_traits(&self,
146-
call_expr: &hir::Expr,
147-
adjusted_ty: Ty<'tcx>)
148-
-> Option<(Option<Adjustment<'tcx>>,
149-
MethodCallee<'tcx>)> {
164+
fn try_overloaded_call_traits(
165+
&self,
166+
call_expr: &hir::Expr,
167+
adjusted_ty: Ty<'tcx>,
168+
opt_arg_exprs: Option<&'gcx [hir::Expr]>,
169+
) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
150170
// Try the options that are least restrictive on the caller first.
151-
for &(opt_trait_def_id, method_name, borrow) in
152-
&[(self.tcx.lang_items().fn_trait(), Ident::from_str("call"), true),
153-
(self.tcx.lang_items().fn_mut_trait(), Ident::from_str("call_mut"), true),
154-
(self.tcx.lang_items().fn_once_trait(), Ident::from_str("call_once"), false)] {
171+
for &(opt_trait_def_id, method_name, borrow) in &[
172+
(
173+
self.tcx.lang_items().fn_trait(),
174+
Ident::from_str("call"),
175+
true,
176+
),
177+
(
178+
self.tcx.lang_items().fn_mut_trait(),
179+
Ident::from_str("call_mut"),
180+
true,
181+
),
182+
(
183+
self.tcx.lang_items().fn_once_trait(),
184+
Ident::from_str("call_once"),
185+
false,
186+
),
187+
] {
155188
let trait_def_id = match opt_trait_def_id {
156189
Some(def_id) => def_id,
157190
None => continue,
158191
};
159192

160-
if let Some(ok) = self.lookup_method_in_trait(call_expr.span,
161-
method_name,
162-
trait_def_id,
163-
adjusted_ty,
164-
None) {
193+
let opt_input_types = opt_arg_exprs.map(|arg_exprs| [self.tcx.mk_tup(
194+
arg_exprs
195+
.iter()
196+
.map(|e| self.next_ty_var(
197+
TypeVariableOrigin::TypeInference(e.span)
198+
))
199+
)]);
200+
let opt_input_types = opt_input_types.as_ref().map(AsRef::as_ref);
201+
202+
if let Some(ok) = self.lookup_method_in_trait(
203+
call_expr.span,
204+
method_name,
205+
trait_def_id,
206+
adjusted_ty,
207+
opt_input_types,
208+
) {
165209
let method = self.register_infer_ok_obligations(ok);
166210
let mut autoref = None;
167211
if borrow {
@@ -173,11 +217,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
173217
// deployment, conservatively omit
174218
// overloaded function call ops.
175219
allow_two_phase_borrow: AllowTwoPhase::No,
176-
}
220+
},
177221
};
178222
autoref = Some(Adjustment {
179223
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
180-
target: method.sig.inputs()[0]
224+
target: method.sig.inputs()[0],
181225
});
182226
}
183227
}
@@ -188,16 +232,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
188232
None
189233
}
190234

191-
fn confirm_builtin_call(&self,
192-
call_expr: &hir::Expr,
193-
callee_ty: Ty<'tcx>,
194-
arg_exprs: &'gcx [hir::Expr],
195-
expected: Expectation<'tcx>)
196-
-> Ty<'tcx> {
235+
fn confirm_builtin_call(
236+
&self,
237+
call_expr: &hir::Expr,
238+
callee_ty: Ty<'tcx>,
239+
arg_exprs: &'gcx [hir::Expr],
240+
expected: Expectation<'tcx>,
241+
) -> Ty<'tcx> {
197242
let (fn_sig, def_span) = match callee_ty.sty {
198-
ty::FnDef(def_id, _) => {
199-
(callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id))
200-
}
243+
ty::FnDef(def_id, _) => (
244+
callee_ty.fn_sig(self.tcx),
245+
self.tcx.hir().span_if_local(def_id),
246+
),
201247
ty::FnPtr(sig) => (sig, None),
202248
ref t => {
203249
let mut unit_variant = None;
@@ -219,84 +265,96 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
219265
match unit_variant {
220266
Some(ref path) => format!("enum variant `{}`", path),
221267
None => format!("`{}`", callee_ty),
222-
});
268+
}
269+
);
223270

224271
if let Some(ref path) = unit_variant {
225272
err.span_suggestion_with_applicability(
226273
call_expr.span,
227-
&format!("`{}` is a unit variant, you need to write it \
228-
without the parenthesis", path),
274+
&format!(
275+
"`{}` is a unit variant, you need to write it \
276+
without the parenthesis",
277+
path
278+
),
229279
path.to_string(),
230-
Applicability::MachineApplicable
280+
Applicability::MachineApplicable,
231281
);
232282
}
233283

234284
let mut inner_callee_path = None;
235285
let def = match callee.node {
236286
hir::ExprKind::Path(ref qpath) => {
237287
self.tables.borrow().qpath_def(qpath, callee.hir_id)
238-
},
288+
}
239289
hir::ExprKind::Call(ref inner_callee, _) => {
240290
// If the call spans more than one line and the callee kind is
241291
// itself another `ExprCall`, that's a clue that we might just be
242292
// missing a semicolon (Issue #51055)
243-
let call_is_multiline = self.tcx.sess.source_map()
244-
.is_multiline(call_expr.span);
293+
let call_is_multiline =
294+
self.tcx.sess.source_map().is_multiline(call_expr.span);
245295
if call_is_multiline {
246296
let span = self.tcx.sess.source_map().next_point(callee.span);
247297
err.span_suggestion_with_applicability(
248298
span,
249299
"try adding a semicolon",
250300
";".to_owned(),
251-
Applicability::MaybeIncorrect
301+
Applicability::MaybeIncorrect,
252302
);
253303
}
254304
if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.node {
255305
inner_callee_path = Some(inner_qpath);
256-
self.tables.borrow().qpath_def(inner_qpath, inner_callee.hir_id)
306+
self.tables
307+
.borrow()
308+
.qpath_def(inner_qpath, inner_callee.hir_id)
257309
} else {
258310
Def::Err
259311
}
260-
},
261-
_ => {
262-
Def::Err
263312
}
313+
_ => Def::Err,
264314
};
265315

266316
err.span_label(call_expr.span, "call expression requires function");
267317

268318
let def_span = match def {
269319
Def::Err => None,
270-
Def::Local(id) | Def::Upvar(id, ..) => {
271-
Some(self.tcx.hir().span(id))
272-
}
273-
_ => def.opt_def_id().and_then(|did| self.tcx.hir().span_if_local(did)),
320+
Def::Local(id) | Def::Upvar(id, ..) => Some(self.tcx.hir().span(id)),
321+
_ => def
322+
.opt_def_id()
323+
.and_then(|did| self.tcx.hir().span_if_local(did)),
274324
};
275325
if let Some(span) = def_span {
276326
let label = match (unit_variant, inner_callee_path) {
277327
(Some(path), _) => format!("`{}` defined here", path),
278328
(_, Some(hir::QPath::Resolved(_, path))) => format!(
279-
"`{}` defined here returns `{}`", path, callee_ty.to_string()
329+
"`{}` defined here returns `{}`",
330+
path,
331+
callee_ty.to_string()
280332
),
281333
_ => format!("`{}` defined here", callee_ty.to_string()),
282334
};
283335
err.span_label(span, label);
284336
}
285337
err.emit();
286338
} else {
287-
bug!("call_expr.node should be an ExprKind::Call, got {:?}", call_expr.node);
339+
bug!(
340+
"call_expr.node should be an ExprKind::Call, got {:?}",
341+
call_expr.node
342+
);
288343
}
289344

290345
// This is the "default" function signature, used in case of error.
291346
// In that case, we check each argument against "error" in order to
292347
// set up all the node type bindings.
293-
(ty::Binder::bind(self.tcx.mk_fn_sig(
294-
self.err_args(arg_exprs.len()).into_iter(),
295-
self.tcx.types.err,
296-
false,
297-
hir::Unsafety::Normal,
298-
abi::Abi::Rust
299-
)), None)
348+
(
349+
ty::Binder::bind(self.tcx.mk_fn_sig(
350+
self.err_args(arg_exprs.len()).into_iter(),
351+
self.tcx.types.err,
352+
false,
353+
hir::Unsafety::Normal,
354+
abi::Abi::Rust,
355+
)),
356+
None,
357+
)
300358
}
301359
};
302360

@@ -305,69 +363,80 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
305363
// renormalize the associated types at this point, since they
306364
// previously appeared within a `Binder<>` and hence would not
307365
// have been normalized before.
308-
let fn_sig =
309-
self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, &fn_sig)
310-
.0;
366+
let fn_sig = self
367+
.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, &fn_sig)
368+
.0;
311369
let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
312370

313371
// Call the generic checker.
314-
let expected_arg_tys =
315-
self.expected_inputs_for_expected_output(call_expr.span,
316-
expected,
317-
fn_sig.output(),
318-
fn_sig.inputs());
319-
self.check_argument_types(call_expr.span,
320-
call_expr.span,
321-
fn_sig.inputs(),
322-
&expected_arg_tys[..],
323-
arg_exprs,
324-
fn_sig.variadic,
325-
TupleArgumentsFlag::DontTupleArguments,
326-
def_span);
372+
let expected_arg_tys = self.expected_inputs_for_expected_output(
373+
call_expr.span,
374+
expected,
375+
fn_sig.output(),
376+
fn_sig.inputs(),
377+
);
378+
self.check_argument_types(
379+
call_expr.span,
380+
call_expr.span,
381+
fn_sig.inputs(),
382+
&expected_arg_tys[..],
383+
arg_exprs,
384+
fn_sig.variadic,
385+
TupleArgumentsFlag::DontTupleArguments,
386+
def_span,
387+
);
327388

328389
fn_sig.output()
329390
}
330391

331-
fn confirm_deferred_closure_call(&self,
332-
call_expr: &hir::Expr,
333-
arg_exprs: &'gcx [hir::Expr],
334-
expected: Expectation<'tcx>,
335-
fn_sig: ty::FnSig<'tcx>)
336-
-> Ty<'tcx> {
392+
fn confirm_deferred_closure_call(
393+
&self,
394+
call_expr: &hir::Expr,
395+
arg_exprs: &'gcx [hir::Expr],
396+
expected: Expectation<'tcx>,
397+
fn_sig: ty::FnSig<'tcx>,
398+
) -> Ty<'tcx> {
337399
// `fn_sig` is the *signature* of the cosure being called. We
338400
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
339401
// do know the types expected for each argument and the return
340402
// type.
341403

342-
let expected_arg_tys = self.expected_inputs_for_expected_output(call_expr.span,
343-
expected,
344-
fn_sig.output().clone(),
345-
fn_sig.inputs());
346-
347-
self.check_argument_types(call_expr.span,
348-
call_expr.span,
349-
fn_sig.inputs(),
350-
&expected_arg_tys,
351-
arg_exprs,
352-
fn_sig.variadic,
353-
TupleArgumentsFlag::TupleArguments,
354-
None);
404+
let expected_arg_tys = self.expected_inputs_for_expected_output(
405+
call_expr.span,
406+
expected,
407+
fn_sig.output().clone(),
408+
fn_sig.inputs(),
409+
);
410+
411+
self.check_argument_types(
412+
call_expr.span,
413+
call_expr.span,
414+
fn_sig.inputs(),
415+
&expected_arg_tys,
416+
arg_exprs,
417+
fn_sig.variadic,
418+
TupleArgumentsFlag::TupleArguments,
419+
None,
420+
);
355421

356422
fn_sig.output()
357423
}
358424

359-
fn confirm_overloaded_call(&self,
360-
call_expr: &hir::Expr,
361-
arg_exprs: &'gcx [hir::Expr],
362-
expected: Expectation<'tcx>,
363-
method_callee: MethodCallee<'tcx>)
364-
-> Ty<'tcx> {
365-
let output_type = self.check_method_argument_types(call_expr.span,
366-
call_expr.span,
367-
Ok(method_callee),
368-
arg_exprs,
369-
TupleArgumentsFlag::TupleArguments,
370-
expected);
425+
fn confirm_overloaded_call(
426+
&self,
427+
call_expr: &hir::Expr,
428+
arg_exprs: &'gcx [hir::Expr],
429+
expected: Expectation<'tcx>,
430+
method_callee: MethodCallee<'tcx>,
431+
) -> Ty<'tcx> {
432+
let output_type = self.check_method_argument_types(
433+
call_expr.span,
434+
call_expr.span,
435+
Ok(method_callee),
436+
arg_exprs,
437+
TupleArgumentsFlag::TupleArguments,
438+
expected,
439+
);
371440

372441
self.write_method_call(call_expr.hir_id, method_callee);
373442
output_type
@@ -391,11 +460,12 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
391460

392461
// we should not be invoked until the closure kind has been
393462
// determined by upvar inference
394-
assert!(fcx.closure_kind(self.closure_def_id, self.closure_substs).is_some());
463+
assert!(fcx
464+
.closure_kind(self.closure_def_id, self.closure_substs)
465+
.is_some());
395466

396467
// We may now know enough to figure out fn vs fnmut etc.
397-
match fcx.try_overloaded_call_traits(self.call_expr,
398-
self.adjusted_ty) {
468+
match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) {
399469
Some((autoref, method_callee)) => {
400470
// One problem is that when we get here, we are going
401471
// to have a newly instantiated function signature
@@ -410,22 +480,28 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> {
410480
debug!("attempt_resolution: method_callee={:?}", method_callee);
411481

412482
for (method_arg_ty, self_arg_ty) in
413-
method_sig.inputs().iter().skip(1).zip(self.fn_sig.inputs()) {
483+
method_sig.inputs().iter().skip(1).zip(self.fn_sig.inputs())
484+
{
414485
fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty);
415486
}
416487

417-
fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
488+
fcx.demand_eqtype(
489+
self.call_expr.span,
490+
method_sig.output(),
491+
self.fn_sig.output(),
492+
);
418493

419494
let mut adjustments = self.adjustments;
420495
adjustments.extend(autoref);
421496
fcx.apply_adjustments(self.callee_expr, adjustments);
422497

423-
fcx.write_method_call(self.call_expr.hir_id,
424-
method_callee);
498+
fcx.write_method_call(self.call_expr.hir_id, method_callee);
425499
}
426500
None => {
427-
span_bug!(self.call_expr.span,
428-
"failed to find an overloaded call trait for closure call");
501+
span_bug!(
502+
self.call_expr.span,
503+
"failed to find an overloaded call trait for closure call"
504+
);
429505
}
430506
}
431507
}

‎src/test/run-pass/issue-18952.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// This issue tests fn_traits overloading on arity.
2+
// run-pass
3+
4+
#![feature(fn_traits)]
5+
#![feature(unboxed_closures)]
6+
7+
struct Foo;
8+
9+
impl Fn<(isize, isize)> for Foo {
10+
extern "rust-call" fn call(&self, args: (isize, isize)) -> Self::Output {
11+
println!("{:?}", args);
12+
(args.0 + 1, args.1 + 1)
13+
}
14+
}
15+
16+
impl FnMut<(isize, isize)> for Foo {
17+
extern "rust-call" fn call_mut(&mut self, args: (isize, isize)) -> Self::Output {
18+
println!("{:?}", args);
19+
(args.0 + 1, args.1 + 1)
20+
}
21+
}
22+
23+
impl FnOnce<(isize, isize)> for Foo {
24+
type Output = (isize, isize);
25+
extern "rust-call" fn call_once(self, args: (isize, isize)) -> Self::Output {
26+
println!("{:?}", args);
27+
(args.0 + 1, args.1 + 1)
28+
}
29+
}
30+
31+
impl Fn<(isize, isize, isize)> for Foo {
32+
extern "rust-call" fn call(&self, args: (isize, isize, isize)) -> Self::Output {
33+
println!("{:?}", args);
34+
(args.0 + 3, args.1 + 3, args.2 + 3)
35+
}
36+
}
37+
38+
impl FnMut<(isize, isize, isize)> for Foo {
39+
extern "rust-call" fn call_mut(&mut self, args: (isize, isize, isize)) -> Self::Output {
40+
println!("{:?}", args);
41+
(args.0 + 3, args.1 + 3, args.2 + 3)
42+
}
43+
}
44+
impl FnOnce<(isize, isize, isize)> for Foo {
45+
type Output = (isize, isize, isize);
46+
extern "rust-call" fn call_once(self, args: (isize, isize, isize)) -> Self::Output {
47+
println!("{:?}", args);
48+
(args.0 + 3, args.1 + 3, args.2 + 3)
49+
}
50+
}
51+
52+
fn main() {
53+
let foo = Foo;
54+
assert_eq!(foo(1, 1), (2, 2));
55+
assert_eq!(foo(1, 1, 1), (4, 4, 4));
56+
}

‎src/test/run-pass/issue-45510.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Test overloaded resolution of fn_traits.
2+
// run-pass
3+
4+
#![feature(fn_traits)]
5+
#![feature(unboxed_closures)]
6+
7+
#[derive(Debug, PartialEq, Eq)]
8+
struct Ishmael;
9+
#[derive(Debug, PartialEq, Eq)]
10+
struct Maybe;
11+
struct CallMe;
12+
13+
impl FnOnce<(Ishmael,)> for CallMe {
14+
type Output = Ishmael;
15+
extern "rust-call" fn call_once(self, _args: (Ishmael,)) -> Ishmael {
16+
println!("Split your lungs with blood and thunder!");
17+
Ishmael
18+
}
19+
}
20+
21+
impl FnOnce<(Maybe,)> for CallMe {
22+
type Output = Maybe;
23+
extern "rust-call" fn call_once(self, _args: (Maybe,)) -> Maybe {
24+
println!("So we just met, and this is crazy");
25+
Maybe
26+
}
27+
}
28+
29+
fn main() {
30+
assert_eq!(CallMe(Ishmael), Ishmael);
31+
assert_eq!(CallMe(Maybe), Maybe);
32+
}

0 commit comments

Comments
 (0)
Please sign in to comment.