diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index f69bf31626f62..bddbb7c02baa7 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -63,7 +63,7 @@ mod util; /// either identifying an `impl` (e.g., `impl Eq for int`) that /// provides the required vtable, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Obligation<'tcx, T> { pub cause: ObligationCause<'tcx>, pub recursion_depth: uint, @@ -74,7 +74,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; /// Why did we incur this obligation? Used for error reporting. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -89,7 +89,7 @@ pub struct ObligationCause<'tcx> { pub code: ObligationCauseCode<'tcx> } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, @@ -129,7 +129,7 @@ pub enum ObligationCauseCode<'tcx> { CompareImplMethodObligation, } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct DerivedObligationCause<'tcx> { /// The trait reference of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to @@ -251,7 +251,7 @@ pub enum Vtable<'tcx, N> { /// is `Obligation`, as one might expect. During trans, however, this /// is `()`, because trans only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct VtableImplData<'tcx, N> { pub impl_def_id: ast::DefId, pub substs: subst::Substs<'tcx>, diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 9d3ad28e6138b..7d02adea1fa5c 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -54,6 +54,7 @@ pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::type_err<'tcx> } +#[derive(PartialEq, Eq)] enum ProjectionTyCandidate<'tcx> { ParamEnv(ty::PolyProjectionPredicate<'tcx>), Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), @@ -481,6 +482,25 @@ fn project_type<'cx,'tcx>( // We probably need some winnowing logic similar to select here. + // Drop duplicates. + // + // Note: `candidates.vec` seems to be on the critical path of the + // compiler. Replacing it with an hash set was also tried, which would + // render the following dedup unnecessary. It led to cleaner code but + // prolonged compiling time of `librustc` from 5m30s to 6m in one test, or + // ~9% performance lost. + if candidates.vec.len() > 1 { + let mut i = 0; + while i < candidates.vec.len() { + let has_dup = (0..i).any(|j| candidates.vec[i] == candidates.vec[j]); + if has_dup { + candidates.vec.swap_remove(i); + } else { + i += 1; + } + } + } + if candidates.ambiguous || candidates.vec.len() > 1 { return Err(ProjectionTyError::TooManyCandidates); } diff --git a/src/test/run-pass/issue-22036.rs b/src/test/run-pass/issue-22036.rs new file mode 100644 index 0000000000000..c06a29c09f78e --- /dev/null +++ b/src/test/run-pass/issue-22036.rs @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +trait DigitCollection: Sized { + type Iter: Iterator; + fn digit_iter(self) -> Self::Iter; + + fn digit_sum(self) -> u32 { + self.digit_iter() + .map(|digit: u8| digit as u32) + .fold(0, |sum, digit| sum + digit) + } +} + +impl DigitCollection for I where I: Iterator { + type Iter = I; + + fn digit_iter(self) -> I { + self + } +} + +fn main() { + let xs = vec![1u8, 2, 3, 4, 5]; + assert_eq!(xs.into_iter().digit_sum(), 15); +}