diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index dcbd48d6498..ec495506a42 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -44,7 +44,6 @@ impl AutoTraitResult { pub struct AutoTraitInfo<'cx> { pub full_user_env: ty::ParamEnv<'cx>, pub region_data: RegionConstraintData<'cx>, - pub names_map: FxHashSet, pub vid_to_region: FxHashMap>, } @@ -78,15 +77,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { pub fn find_auto_trait_generics( &self, ty: Ty<'tcx>, - param_env_def_id: DefId, + orig_env: ty::ParamEnv<'tcx>, trait_did: DefId, - generics: &ty::Generics, auto_trait_callback: impl for<'i> Fn(&InferCtxt<'_, 'tcx, 'i>, AutoTraitInfo<'i>) -> A, ) -> AutoTraitResult { let tcx = self.tcx; - let orig_params = tcx.param_env(param_env_def_id); - let trait_ref = ty::TraitRef { def_id: trait_did, substs: tcx.mk_substs_trait(ty, &[]), @@ -98,16 +94,16 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let mut selcx = SelectionContext::with_negative(&infcx, true); let result = selcx.select(&Obligation::new( ObligationCause::dummy(), - orig_params, + orig_env, trait_pred.to_poly_trait_predicate(), )); match result { Ok(Some(Vtable::VtableImpl(_))) => { debug!( - "find_auto_trait_generics(ty={:?}, trait_did={:?}, generics={:?}): \ + "find_auto_trait_generics({:?}): \ manual impl found, bailing out", - ty, trait_did, generics + trait_ref ); true } @@ -160,8 +156,8 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { &mut infcx, trait_did, ty, - orig_params.clone(), - orig_params, + orig_env, + orig_env, &mut fresh_preds, false, ) { @@ -173,21 +169,21 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { &mut infcx, trait_did, ty, - new_env.clone(), + new_env, user_env, &mut fresh_preds, true, ).unwrap_or_else(|| { panic!( "Failed to fully process: {:?} {:?} {:?}", - ty, trait_did, orig_params + ty, trait_did, orig_env ) }); debug!( - "find_auto_trait_generics(ty={:?}, trait_did={:?}, generics={:?}): fulfilling \ + "find_auto_trait_generics({:?}): fulfilling \ with {:?}", - ty, trait_did, generics, full_env + trait_ref, full_env ); infcx.clear_caches(); @@ -209,15 +205,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { ) }); - let names_map: FxHashSet = generics - .params - .iter() - .filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()), - _ => None, - }) - .collect(); - let body_id_map: FxHashMap<_, _> = infcx .region_obligations .borrow() @@ -225,7 +212,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .map(|&(id, _)| (id, vec![])) .collect(); - infcx.process_registered_region_obligations(&body_id_map, None, full_env.clone()); + infcx.process_registered_region_obligations(&body_id_map, None, full_env); let region_data = infcx .borrow_region_constraints() @@ -237,7 +224,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let info = AutoTraitInfo { full_user_env, region_data, - names_map, vid_to_region, }; @@ -284,7 +270,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // the final synthesized generics: we don't want our generated docs page to contain something // like 'T: Copy + Clone', as that's redundant. Therefore, we keep track of a separate // 'user_env', which only holds the predicates that will actually be displayed to the user. - pub fn evaluate_predicates<'b, 'gcx, 'c>( + fn evaluate_predicates<'b, 'gcx, 'c>( &self, infcx: &InferCtxt<'b, 'tcx, 'c>, trait_did: DefId, @@ -311,13 +297,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds.iter().cloned().collect(); - let mut new_env = param_env.clone(); + let mut new_env = param_env; let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID); while let Some(pred) = predicates.pop_front() { infcx.clear_caches(); - if !already_visited.insert(pred.clone()) { + if !already_visited.insert(pred) { continue; } @@ -365,7 +351,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { already_visited.remove(&pred); self.add_user_pred( &mut user_computed_preds, - ty::Predicate::Trait(pred.clone()), + ty::Predicate::Trait(pred), ); predicates.push_back(pred); } else { @@ -384,7 +370,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { computed_preds.extend(user_computed_preds.iter().cloned()); let normalized_preds = - elaborate_predicates(tcx, computed_preds.clone().into_iter().collect()); + elaborate_predicates(tcx, computed_preds.iter().cloned().collect()); new_env = ty::ParamEnv::new( tcx.mk_predicates(normalized_preds), param_env.reveal, @@ -519,28 +505,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } } - pub fn region_name(&self, region: Region<'_>) -> Option { - match region { - &ty::ReEarlyBound(r) => Some(r.name.to_string()), - _ => None, - } - } - - pub fn get_lifetime(&self, region: Region<'_>, - names_map: &FxHashMap) -> String { - self.region_name(region) - .map(|name| - names_map.get(&name).unwrap_or_else(|| - panic!("Missing lifetime with name {:?} for {:?}", name, region) - ) - ) - .cloned() - .unwrap_or_else(|| "'static".to_owned()) - } - // This is very similar to handle_lifetimes. However, instead of matching ty::Region's // to each other, we match ty::RegionVid's to ty::Region's - pub fn map_vid_to_region<'cx>( + fn map_vid_to_region<'cx>( &self, regions: &RegionConstraintData<'cx>, ) -> FxHashMap> { @@ -650,7 +617,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } } - pub fn evaluate_nested_obligations< + fn evaluate_nested_obligations< 'b, 'c, 'd, @@ -669,10 +636,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID); for (obligation, mut predicate) in nested - .map(|o| (o.clone(), o.predicate.clone())) + .map(|o| (o.clone(), o.predicate)) { let is_new_pred = - fresh_preds.insert(self.clean_pred(select.infcx(), predicate.clone())); + fresh_preds.insert(self.clean_pred(select.infcx(), predicate)); // Resolve any inference variables that we can, to help selection succeed predicate = select.infcx().resolve_type_vars_if_possible(&predicate); @@ -690,14 +657,14 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // We check this by calling is_of_param on the relevant types // from the various possible predicates match &predicate { - &ty::Predicate::Trait(ref p) => { + &ty::Predicate::Trait(p) => { if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred { self.add_user_pred(computed_preds, predicate); } - predicates.push_back(p.clone()); + predicates.push_back(p); } &ty::Predicate::Projection(p) => { debug!("evaluate_nested_obligations: examining projection predicate {:?}", @@ -739,7 +706,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { if p.ty().skip_binder().has_infer_types() { debug!("Projecting and unifying projection predicate {:?}", predicate); - match poly_project_and_unify_type(select, &obligation.with(p.clone())) { + match poly_project_and_unify_type(select, &obligation.with(p)) { Err(e) => { debug!( "evaluate_nested_obligations: Unable to unify predicate \ diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 46af92baa93..11e8192521d 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -1,5 +1,5 @@ use rustc::hir; -use rustc::traits::auto_trait as auto; +use rustc::traits::auto_trait::{self, AutoTraitResult}; use rustc::ty::{self, TypeFoldable}; use std::fmt::Debug; @@ -7,12 +7,12 @@ use super::*; pub struct AutoTraitFinder<'a, 'tcx> { pub cx: &'a core::DocContext<'tcx>, - pub f: auto::AutoTraitFinder<'a, 'tcx>, + pub f: auto_trait::AutoTraitFinder<'a, 'tcx>, } impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { pub fn new(cx: &'a core::DocContext<'tcx>) -> Self { - let f = auto::AutoTraitFinder::new(cx.tcx); + let f = auto_trait::AutoTraitFinder::new(cx.tcx); AutoTraitFinder { cx, f } } @@ -24,68 +24,66 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { ty: Ty<'tcx>, param_env_def_id: DefId, ) -> Vec { - let generics = self.cx.tcx.generics_of(param_env_def_id); + let param_env = self.cx.tcx.param_env(param_env_def_id); - debug!( - "get_auto_trait_impls(param_env_def_id={:?}, generics={:?}", - param_env_def_id, generics + debug!("get_auto_trait_impls({:?})", ty); + let auto_traits = self.cx.send_trait.into_iter().chain( + Some(self.cx.tcx.require_lang_item(lang_items::SyncTraitLangItem)) ); - let auto_traits: Vec<_> = self.cx - .send_trait - .and_then(|send_trait| { - self.get_auto_trait_impl_for( - ty, - param_env_def_id, - generics, - send_trait, - ) - }) - .into_iter() - .chain(self.get_auto_trait_impl_for( - ty, - param_env_def_id, - generics, - self.cx.tcx.require_lang_item(lang_items::SyncTraitLangItem), - ).into_iter()) - .collect(); - - debug!( - "get_auto_traits: type {:?} auto_traits {:?}", - param_env_def_id, auto_traits - ); - auto_traits - } - - fn get_auto_trait_impl_for( - &self, - ty: Ty<'tcx>, - param_env_def_id: DefId, - generics: &ty::Generics, - trait_def_id: DefId, - ) -> Option { - if !self.cx - .generated_synthetics - .borrow_mut() - .insert((param_env_def_id, trait_def_id)) - { - debug!( - "get_auto_trait_impl_for(param_env_def_id={:?}, generics={:?}, \ - trait_def_id={:?}): already generated, aborting", - param_env_def_id, generics, trait_def_id - ); - return None; - } - - let result = self.find_auto_trait_generics(ty, param_env_def_id, trait_def_id, &generics); - - if result.is_auto() { + auto_traits.filter_map(|trait_def_id| { let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: self.cx.tcx.mk_substs_trait(ty, &[]), }; + if !self.cx + .generated_synthetics + .borrow_mut() + .insert((ty, trait_def_id)) + { + debug!( + "get_auto_trait_impl_for({:?}): already generated, aborting", + trait_ref + ); + return None; + } + + let result = self.f.find_auto_trait_generics( + ty, + param_env, + trait_def_id, + |infcx, info| { + let region_data = info.region_data; + + let names_map = self.cx.tcx.generics_of(param_env_def_id) + .params + .iter() + .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()), + _ => None, + }) + .map(|name| (name.clone(), Lifetime(name))) + .collect(); + let lifetime_predicates = + self.handle_lifetimes(®ion_data, &names_map); + let new_generics = self.param_env_to_generics( + infcx.tcx, + param_env_def_id, + info.full_user_env, + lifetime_predicates, + info.vid_to_region, + ); + + debug!( + "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \ + finished with {:?}", + param_env_def_id, trait_def_id, new_generics + ); + + new_generics + }, + ); let polarity; - let new_generics = match result { AutoTraitResult::PositiveImpl(new_generics) => { polarity = None; @@ -106,21 +104,18 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // Instead, we generate `impl !Send for Foo`, which better // expresses the fact that `Foo` never implements `Send`, // regardless of the choice of `T`. - let real_generics = (generics, &Default::default()); - - // Clean the generics, but ignore the '?Sized' bounds generated - // by the `Clean` impl - let clean_generics = real_generics.clean(self.cx); + let params = (self.cx.tcx.generics_of(param_env_def_id), &Default::default()) + .clean(self.cx).params; Generics { - params: clean_generics.params, + params, where_predicates: Vec::new(), } } - _ => unreachable!(), + AutoTraitResult::ExplicitImpl => return None, }; - return Some(Item { + Some(Item { source: Span::empty(), name: None, attrs: Default::default(), @@ -139,49 +134,8 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { synthetic: true, blanket_impl: None, }), - }); - } - None - } - - fn find_auto_trait_generics( - &self, - ty: Ty<'tcx>, - param_env_def_id: DefId, - trait_did: DefId, - generics: &ty::Generics, - ) -> AutoTraitResult { - match self.f.find_auto_trait_generics(ty, param_env_def_id, trait_did, generics, - |infcx, mut info| { - let region_data = info.region_data; - let names_map = - info.names_map - .drain() - .map(|name| (name.clone(), Lifetime(name))) - .collect(); - let lifetime_predicates = - self.handle_lifetimes(®ion_data, &names_map); - let new_generics = self.param_env_to_generics( - infcx.tcx, - param_env_def_id, - info.full_user_env, - generics, - lifetime_predicates, - info.vid_to_region, - ); - - debug!( - "find_auto_trait_generics(ty={:?}, trait_did={:?}, generics={:?}): \ - finished with {:?}", - ty, trait_did, generics, new_generics - ); - - new_generics - }) { - auto::AutoTraitResult::ExplicitImpl => AutoTraitResult::ExplicitImpl, - auto::AutoTraitResult::NegativeImpl => AutoTraitResult::NegativeImpl, - auto::AutoTraitResult::PositiveImpl(res) => AutoTraitResult::PositiveImpl(res), - } + }) + }).collect() } fn get_lifetime( @@ -497,14 +451,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { tcx: TyCtxt<'b, 'c, 'cx>, param_env_def_id: DefId, param_env: ty::ParamEnv<'cx>, - type_generics: &ty::Generics, mut existing_predicates: Vec, vid_to_region: FxHashMap>, ) -> Generics { debug!( - "param_env_to_generics(param_env_def_id={:?}, param_env={:?}, type_generics={:?}, \ + "param_env_to_generics(param_env_def_id={:?}, param_env={:?}, \ existing_predicates={:?})", - param_env_def_id, param_env, type_generics, existing_predicates + param_env_def_id, param_env, existing_predicates ); // The `Sized` trait must be handled specially, since we only display it when @@ -534,11 +487,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { (replaced.clone(), replaced.clean(self.cx)) }); - let full_generics = (type_generics, &tcx.explicit_predicates_of(param_env_def_id)); - let Generics { - params: mut generic_params, - .. - } = full_generics.clean(self.cx); + let mut generic_params = ( + tcx.generics_of(param_env_def_id), + &tcx.explicit_predicates_of(param_env_def_id), + ).clean(self.cx).params; let mut has_sized = FxHashSet::default(); let mut ty_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 423cbc66e1c..5c42d705bd5 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -25,23 +25,23 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { ty: Ty<'tcx>, param_env_def_id: DefId, ) -> Vec { - debug!("get_blanket_impls(param_env_def_id={:?}, ...)", param_env_def_id); - let mut impls = Vec::new(); let param_env = self.cx.tcx.param_env(param_env_def_id); + + debug!("get_blanket_impls({:?})", ty); + let mut impls = Vec::new(); for &trait_def_id in self.cx.all_traits.iter() { if !self.cx.renderinfo.borrow().access_levels.is_doc_reachable(trait_def_id) || self.cx.generated_synthetics .borrow_mut() - .get(&(param_env_def_id, trait_def_id)) + .get(&(ty, trait_def_id)) .is_some() { continue } self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| { + debug!("get_blanket_impls: Considering impl for trait '{:?}' {:?}", + trait_def_id, impl_def_id); let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); let may_apply = self.cx.tcx.infer_ctxt().enter(|infcx| { - debug!("get_blanket_impls: Considering impl for trait '{:?}' {:?}", - trait_def_id, impl_def_id); - match trait_ref.self_ty().sty { ty::Param(_) => {}, _ => return false, @@ -84,12 +84,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { debug!("get_blanket_impls: found applicable impl: {}\ for trait_ref={:?}, ty={:?}", may_apply, trait_ref, ty); - if !may_apply { - return + return; } + self.cx.generated_synthetics.borrow_mut() - .insert((param_env_def_id, trait_def_id)); + .insert((ty, trait_def_id)); let provided_trait_methods = self.cx.tcx.provided_trait_methods(trait_def_id) .into_iter() @@ -111,6 +111,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { &self.cx.tcx.explicit_predicates_of(impl_def_id), ).clean(self.cx), provided_trait_methods, + // FIXME(eddyb) compute both `trait_` and `for_` from + // the post-inference `trait_ref`, as it's more accurate. trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), for_: ty.clean(self.cx), items: self.cx.tcx.associated_items(impl_def_id) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8067bdf8796..dd4900cfaee 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -4452,21 +4452,6 @@ enum SimpleBound { Outlives(Lifetime), } -enum AutoTraitResult { - ExplicitImpl, - PositiveImpl(Generics), - NegativeImpl, -} - -impl AutoTraitResult { - fn is_auto(&self) -> bool { - match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, - _ => false, - } - } -} - impl From for SimpleBound { fn from(bound: GenericBound) -> Self { match bound.clone() { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 99550a3db65..831adb301ef 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -5,7 +5,7 @@ use rustc::hir::def::Def; use rustc::hir::HirId; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; -use rustc::ty::TyCtxt; +use rustc::ty::{Ty, TyCtxt}; use rustc::lint::{self, LintPass}; use rustc::session::config::ErrorOutputType; use rustc::session::DiagnosticOutput; @@ -70,8 +70,9 @@ pub struct DocContext<'tcx> { pub send_trait: Option, pub fake_def_ids: RefCell>, pub all_fake_def_ids: RefCell>, - /// Maps (type_id, trait_id) -> auto trait impl - pub generated_synthetics: RefCell>, + /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. + // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set. + pub generated_synthetics: RefCell, DefId)>>, pub all_traits: Vec, }