Skip to content

Commit 590a61f

Browse files
committed
Only consider impliciy unboxed closure impl if the obligation is
actually for `Fn`, `FnMut`, or `FnOnce`. Fixes #18019
1 parent 4a382d7 commit 590a61f

File tree

2 files changed

+52
-29
lines changed

2 files changed

+52
-29
lines changed

src/librustc/middle/traits/select.rs

+20-29
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
608608
* unified during the confirmation step.
609609
*/
610610

611+
let tcx = self.tcx();
612+
let kind = if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_trait() {
613+
ty::FnUnboxedClosureKind
614+
} else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_mut_trait() {
615+
ty::FnMutUnboxedClosureKind
616+
} else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_once_trait() {
617+
ty::FnOnceUnboxedClosureKind
618+
} else {
619+
return Ok(()); // not a fn trait, ignore
620+
};
621+
611622
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
612623
let closure_def_id = match ty::get(self_ty).sty {
613624
ty::ty_unboxed_closure(id, _) => id,
@@ -622,37 +633,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
622633
self_ty.repr(self.tcx()),
623634
obligation.repr(self.tcx()));
624635

625-
let tcx = self.tcx();
626-
let fn_traits = [
627-
(ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()),
628-
(ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()),
629-
(ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()),
630-
];
631-
for tuple in fn_traits.iter() {
632-
let kind = match tuple {
633-
&(kind, Some(ref fn_trait))
634-
if *fn_trait == obligation.trait_ref.def_id =>
635-
{
636-
kind
637-
}
638-
_ => continue,
639-
};
640-
641-
// Check to see whether the argument and return types match.
642-
let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) {
643-
Some(closure) => closure.kind,
644-
None => {
645-
self.tcx().sess.span_bug(
646-
obligation.cause.span,
647-
format!("No entry for unboxed closure: {}",
648-
closure_def_id.repr(self.tcx())).as_slice());
649-
}
650-
};
651-
652-
if closure_kind != kind {
653-
continue;
636+
let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) {
637+
Some(closure) => closure.kind,
638+
None => {
639+
self.tcx().sess.span_bug(
640+
obligation.cause.span,
641+
format!("No entry for unboxed closure: {}",
642+
closure_def_id.repr(self.tcx())).as_slice());
654643
}
644+
};
655645

646+
if closure_kind == kind {
656647
candidates.vec.push(UnboxedClosureCandidate(closure_def_id));
657648
}
658649

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we correctly infer that `E` must be `()` here. This is
12+
// known because there is just one impl that could apply where
13+
// `Self=()`.
14+
15+
pub trait FromError<E> {
16+
fn from_error(err: E) -> Self;
17+
}
18+
19+
impl<E> FromError<E> for E {
20+
fn from_error(err: E) -> E {
21+
err
22+
}
23+
}
24+
25+
fn test() -> Result<(), ()> {
26+
Err(FromError::from_error(()))
27+
}
28+
29+
fn main() {
30+
let result = (|| Err(FromError::from_error(())))();
31+
let foo: () = result.unwrap_or(());
32+
}

0 commit comments

Comments
 (0)