diff --git a/src/librustc_middle/ty/trait_def.rs b/src/librustc_middle/ty/trait_def.rs index 912f8be1d3342..3546e5f429ef5 100644 --- a/src/librustc_middle/ty/trait_def.rs +++ b/src/librustc_middle/ty/trait_def.rs @@ -168,15 +168,13 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns a vector containing all impls - pub fn all_impls(self, def_id: DefId) -> Vec { - let impls = self.trait_impls_of(def_id); + pub fn all_impls(self, def_id: DefId) -> impl Iterator + 'tcx { + let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id); - impls - .blanket_impls - .iter() - .chain(impls.non_blanket_impls.values().flatten()) + blanket_impls + .into_iter() + .chain(non_blanket_impls.into_iter().map(|(_, v)| v).flatten()) .cloned() - .collect() } } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 927f7c294f068..74cf06d54687d 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1208,8 +1208,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { match simp { Some(simp) => all_impls - .iter() - .filter_map(|&def_id| { + .filter_map(|def_id| { let imp = self.tcx.impl_trait_ref(def_id).unwrap(); let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); if let Some(imp_simp) = imp_simp { @@ -1217,13 +1216,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return None; } } - Some(imp) }) .collect(), - None => { - all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect() - } + None => all_impls.map(|def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect(), } } diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 2227477a4635b..c5dbe81629550 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -110,8 +110,8 @@ pub enum TraitQueryMode { pub fn predicates_for_generics<'tcx>( cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> PredicateObligations<'tcx> { + generic_bounds: ty::InstantiatedPredicates<'tcx>, +) -> impl Iterator> { util::predicates_for_generics(cause, 0, param_env, generic_bounds) } diff --git a/src/librustc_trait_selection/traits/specialize/mod.rs b/src/librustc_trait_selection/traits/specialize/mod.rs index fabd8c89b72af..a69c8acef5b16 100644 --- a/src/librustc_trait_selection/traits/specialize/mod.rs +++ b/src/librustc_trait_selection/traits/specialize/mod.rs @@ -189,26 +189,22 @@ fn fulfill_implication<'a, 'tcx>( let selcx = &mut SelectionContext::new(&infcx); let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); - let (target_trait_ref, mut obligations) = + let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, param_env, target_impl, target_substs); - debug!( - "fulfill_implication: target_trait_ref={:?}, obligations={:?}", - target_trait_ref, obligations - ); // do the impls unify? If not, no specialization. - match infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait_ref, target_trait_ref) { - Ok(InferOk { obligations: o, .. }) => { - obligations.extend(o); - } - Err(_) => { - debug!( - "fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, target_trait_ref - ); - return Err(()); - } - } + let more_obligations = + match infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait_ref, target_trait_ref) + { + Ok(InferOk { obligations, .. }) => obligations, + Err(_) => { + debug!( + "fulfill_implication: {:?} does not unify with {:?}", + source_trait_ref, target_trait_ref + ); + return Err(()); + } + }; // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) @@ -226,7 +222,7 @@ fn fulfill_implication<'a, 'tcx>( // we already make a mockery out of the region system, so // why not ignore them a bit earlier? let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); - for oblig in obligations.into_iter() { + for oblig in obligations.chain(more_obligations) { fulfill_cx.register_predicate_obligation(&infcx, oblig); } match fulfill_cx.select_all_or_error(infcx) { @@ -261,7 +257,7 @@ pub(super) fn specialization_graph_provider( ) -> &specialization_graph::Graph { let mut sg = specialization_graph::Graph::new(); - let mut trait_impls = tcx.all_impls(trait_id); + let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect(); // The coherence checking implementation seems to rely on impls being // iterated over (roughly) in definition order, so we are sorting by diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs index ffece42ec306c..4aceccf64ce65 100644 --- a/src/librustc_trait_selection/traits/util.rs +++ b/src/librustc_trait_selection/traits/util.rs @@ -81,12 +81,10 @@ impl<'tcx> TraitAliasExpansionInfo<'tcx> { pub fn expand_trait_aliases<'tcx>( tcx: TyCtxt<'tcx>, - trait_refs: impl IntoIterator, Span)>, + trait_refs: impl Iterator, Span)>, ) -> TraitAliasExpander<'tcx> { - let items: Vec<_> = trait_refs - .into_iter() - .map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)) - .collect(); + let items: Vec<_> = + trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect(); TraitAliasExpander { tcx, stack: items } } @@ -199,7 +197,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, impl_def_id: DefId, impl_substs: SubstsRef<'tcx>, -) -> (ty::TraitRef<'tcx>, Vec>) { +) -> (ty::TraitRef<'tcx>, impl Iterator>) { let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = @@ -210,13 +208,11 @@ pub fn impl_trait_ref_and_oblig<'a, 'tcx>( let Normalized { value: predicates, obligations: normalization_obligations2 } = super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); let impl_obligations = - predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates); + predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates); - let impl_obligations: Vec<_> = impl_obligations - .into_iter() - .chain(normalization_obligations1) - .chain(normalization_obligations2) - .collect(); + let impl_obligations = impl_obligations + .chain(normalization_obligations1.into_iter()) + .chain(normalization_obligations2.into_iter()); (impl_trait_ref, impl_obligations) } @@ -226,20 +222,16 @@ pub fn predicates_for_generics<'tcx>( cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> Vec> { + generic_bounds: ty::InstantiatedPredicates<'tcx>, +) -> impl Iterator> { debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); - generic_bounds - .predicates - .iter() - .map(|&predicate| Obligation { - cause: cause.clone(), - recursion_depth, - param_env, - predicate, - }) - .collect() + generic_bounds.predicates.into_iter().map(move |predicate| Obligation { + cause: cause.clone(), + recursion_depth, + param_env, + predicate, + }) } pub fn predicate_for_trait_ref<'tcx>( diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 5c5f3f89aba42..22c81ece39181 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // a custom error in that case. if illegal_sized_bound.is_none() { let method_ty = self.tcx.mk_fn_ptr(ty::Binder::bind(method_sig)); - self.add_obligations(method_ty, all_substs, &method_predicates); + self.add_obligations(method_ty, all_substs, method_predicates); } // Create the final `MethodCallee`. @@ -395,7 +395,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { &mut self, fty: Ty<'tcx>, all_substs: SubstsRef<'tcx>, - method_predicates: &ty::InstantiatedPredicates<'tcx>, + method_predicates: ty::InstantiatedPredicates<'tcx>, ) { debug!( "add_obligations: fty={:?} all_substs={:?} method_predicates={:?}", diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index c4f53332cb673..65e9abcd14644 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -390,7 +390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(!bounds.has_escaping_bound_vars()); let cause = traits::ObligationCause::misc(span, self.body_id); - obligations.extend(traits::predicates_for_generics(cause.clone(), self.param_env, &bounds)); + obligations.extend(traits::predicates_for_generics(cause.clone(), self.param_env, bounds)); // Also add an obligation for the method type being well-formed. let method_ty = tcx.mk_fn_ptr(ty::Binder::bind(fn_sig)); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3f159fe5e3029..03e32c21a54ac 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1342,7 +1342,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // clauses) that must be considered. Make sure that those // match as well (or at least may match, sometimes we // don't have enough information to fully evaluate). - let candidate_obligations: Vec<_> = match probe.kind { + match probe.kind { InherentImplCandidate(ref substs, ref ref_obligations) => { // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container.id(); @@ -1353,19 +1353,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Convert the bounds into obligations. let impl_obligations = - traits::predicates_for_generics(cause, self.param_env, &impl_bounds); + traits::predicates_for_generics(cause, self.param_env, impl_bounds); - debug!("impl_obligations={:?}", impl_obligations); - impl_obligations - .into_iter() + let candidate_obligations = impl_obligations .chain(norm_obligations.into_iter()) - .chain(ref_obligations.iter().cloned()) - .collect() + .chain(ref_obligations.iter().cloned()); + // Evaluate those obligations to see if they might possibly hold. + for o in candidate_obligations { + let o = self.resolve_vars_if_possible(&o); + if !self.predicate_may_hold(&o) { + result = ProbeResult::NoMatch; + possibly_unsatisfied_predicates.push((o.predicate, None)); + } + } } ObjectCandidate | WhereClauseCandidate(..) => { // These have no additional conditions to check. - vec![] } TraitCandidate(trait_ref) => { @@ -1412,17 +1416,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return ProbeResult::NoMatch; } } - vec![] } - }; - - debug!( - "consider_probe - candidate_obligations={:?} sub_obligations={:?}", - candidate_obligations, sub_obligations - ); + } // Evaluate those obligations to see if they might possibly hold. - for o in candidate_obligations.into_iter().chain(sub_obligations) { + for o in sub_obligations { let o = self.resolve_vars_if_possible(&o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1be8d258dcb18..ec5d3331956e5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3434,7 +3434,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn add_obligations_for_parameters( &self, cause: traits::ObligationCause<'tcx>, - predicates: &ty::InstantiatedPredicates<'tcx>, + predicates: ty::InstantiatedPredicates<'tcx>, ) { assert!(!predicates.has_escaping_bound_vars()); @@ -4385,7 +4385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (bounds, _) = self.instantiate_bounds(path_span, did, substs); let cause = traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); - self.add_obligations_for_parameters(cause, &bounds); + self.add_obligations_for_parameters(cause, bounds); Some((variant, ty)) } else { @@ -5654,9 +5654,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (i, mut obligation) in traits::predicates_for_generics( traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), self.param_env, - &bounds, + bounds, ) - .into_iter() .enumerate() { // This makes the error point at the bound, but we want to point at the argument