From 590a61f788e058d7ae95806f55258bce3ae45567 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 13 Oct 2014 19:54:01 -0400 Subject: [PATCH 1/2] Only consider impliciy unboxed closure impl if the obligation is actually for `Fn`, `FnMut`, or `FnOnce`. Fixes #18019 --- src/librustc/middle/traits/select.rs | 49 ++++++++----------- .../multidispatch-infer-from-single-impl.rs | 32 ++++++++++++ 2 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 src/test/run-pass/multidispatch-infer-from-single-impl.rs diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 4040b452e9988..2a45d536066ef 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -608,6 +608,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { * unified during the confirmation step. */ + let tcx = self.tcx(); + let kind = if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_trait() { + ty::FnUnboxedClosureKind + } else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_mut_trait() { + ty::FnMutUnboxedClosureKind + } else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_once_trait() { + ty::FnOnceUnboxedClosureKind + } else { + return Ok(()); // not a fn trait, ignore + }; + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let closure_def_id = match ty::get(self_ty).sty { ty::ty_unboxed_closure(id, _) => id, @@ -622,37 +633,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self_ty.repr(self.tcx()), obligation.repr(self.tcx())); - let tcx = self.tcx(); - let fn_traits = [ - (ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()), - (ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()), - (ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()), - ]; - for tuple in fn_traits.iter() { - let kind = match tuple { - &(kind, Some(ref fn_trait)) - if *fn_trait == obligation.trait_ref.def_id => - { - kind - } - _ => continue, - }; - - // Check to see whether the argument and return types match. - let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) { - Some(closure) => closure.kind, - None => { - self.tcx().sess.span_bug( - obligation.cause.span, - format!("No entry for unboxed closure: {}", - closure_def_id.repr(self.tcx())).as_slice()); - } - }; - - if closure_kind != kind { - continue; + let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) { + Some(closure) => closure.kind, + None => { + self.tcx().sess.span_bug( + obligation.cause.span, + format!("No entry for unboxed closure: {}", + closure_def_id.repr(self.tcx())).as_slice()); } + }; + if closure_kind == kind { candidates.vec.push(UnboxedClosureCandidate(closure_def_id)); } diff --git a/src/test/run-pass/multidispatch-infer-from-single-impl.rs b/src/test/run-pass/multidispatch-infer-from-single-impl.rs new file mode 100644 index 0000000000000..f4ca67548fd53 --- /dev/null +++ b/src/test/run-pass/multidispatch-infer-from-single-impl.rs @@ -0,0 +1,32 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we correctly infer that `E` must be `()` here. This is +// known because there is just one impl that could apply where +// `Self=()`. + +pub trait FromError { + fn from_error(err: E) -> Self; +} + +impl FromError for E { + fn from_error(err: E) -> E { + err + } +} + +fn test() -> Result<(), ()> { + Err(FromError::from_error(())) +} + +fn main() { + let result = (|| Err(FromError::from_error(())))(); + let foo: () = result.unwrap_or(()); +} From f4a7d32c8b53649d20735c8a90469b08fe7cc3dc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Oct 2014 08:04:34 -0400 Subject: [PATCH 2/2] Correct a test. The error message changed because, with this fix, we detected (correctly) that there was only one impl and hence ignored the `Self` bound completely. I (semi-arbitrarily) elected to delect the impl, forcing the trait matcher to be more conservative and lean on the where clauses in scope, yielding the original error message. --- .../compile-fail/type-params-in-different-spaces-2.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/test/compile-fail/type-params-in-different-spaces-2.rs b/src/test/compile-fail/type-params-in-different-spaces-2.rs index d1bbda932cb73..9be64bf534679 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-2.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-2.rs @@ -8,28 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test static calls to make sure that we align the Self and input +// type parameters on a trait correctly. + trait Tr { fn op(T) -> Self; } -// these compile as if Self: Tr, even tho only Self: Tr trait A: Tr { fn test(u: U) -> Self { Tr::op(u) //~ ERROR not implemented } } + trait B: Tr { fn test(u: U) -> Self { Tr::op(u) //~ ERROR not implemented } } -impl Tr for T { - fn op(t: T) -> T { t } -} -impl A for T {} - fn main() { - std::io::println(A::test((&7306634593706211700, 8))); }