diff options
| -rw-r--r-- | src/librustc/traits/auto_trait.rs | 397 |
1 files changed, 199 insertions, 198 deletions
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 2ee22d494e1..7e4d4505022 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -25,13 +25,13 @@ use ty::fold::TypeFolder; #[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] pub enum RegionTarget<'tcx> { Region(Region<'tcx>), - RegionVid(RegionVid) + RegionVid(RegionVid), } #[derive(Default, Debug, Clone)] pub struct RegionDeps<'tcx> { larger: FxHashSet<RegionTarget<'tcx>>, - smaller: FxHashSet<RegionTarget<'tcx>> + smaller: FxHashSet<RegionTarget<'tcx>>, } pub enum AutoTraitResult<A> { @@ -43,7 +43,8 @@ pub enum AutoTraitResult<A> { impl<A> AutoTraitResult<A> { fn is_auto(&self) -> bool { match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, + AutoTraitResult::PositiveImpl(_) | + AutoTraitResult::NegativeImpl => true, _ => false, } } @@ -65,14 +66,17 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { AutoTraitFinder { tcx } } - pub fn find_auto_trait_generics<A>( - &self, - did: DefId, - trait_did: DefId, - generics: &ty::Generics, - auto_trait_callback: impl for<'i> Fn(&InferCtxt<'_, 'tcx, 'i>, AutoTraitInfo<'i>) -> A) - -> AutoTraitResult<A> - { + /// Determine whether an auto trait is implemented for a type, and if this is the case if + /// non-trivial bounds need to be fulfilled, invoke a callback to compute a value representing + /// these in a fashion suitable for the caller. + pub fn find_auto_trait_generics<A>(&self, + did: DefId, + trait_did: DefId, + generics: &ty::Generics, + auto_trait_callback: + impl for<'i> Fn(&InferCtxt<'_, 'tcx, 'i>, + AutoTraitInfo<'i>) -> A) + -> AutoTraitResult<A> { let tcx = self.tcx; let ty = self.tcx.type_of(did); @@ -85,32 +89,33 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let trait_pred = ty::Binder::bind(trait_ref); - let bail_out = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::with_negative(&infcx, true); - let result = selcx.select(&Obligation::new( - ObligationCause::dummy(), - orig_params, - trait_pred.to_poly_trait_predicate(), - )); - match result { - Ok(Some(Vtable::VtableImpl(_))) => { - debug!( - "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): \ + let bail_out = tcx.infer_ctxt() + .enter(|infcx| { + let mut selcx = SelectionContext::with_negative(&infcx, true); + let result = + selcx.select(&Obligation::new(ObligationCause::dummy(), + orig_params, + trait_pred.to_poly_trait_predicate())); + match result { + Ok(Some(Vtable::VtableImpl(_))) => { + debug!("find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): \ manual impl found, bailing out", - did, trait_did, generics - ); - return true; - } - _ => return false, - }; - }); + did, + trait_did, + generics); + return true; + } + _ => return false, + }; + }); // If an explicit impl exists, it always takes priority over an auto impl if bail_out { return AutoTraitResult::ExplicitImpl; } - return tcx.infer_ctxt().enter(|mut infcx| { + return tcx.infer_ctxt() + .enter(|mut infcx| { let mut fresh_preds = FxHashSet(); // Due to the way projections are handled by SelectionContext, we need to run @@ -146,60 +151,59 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing // SelectionContext to return it back to us. - let (new_env, user_env) = match self.evaluate_predicates( - &mut infcx, - did, - trait_did, - ty, - orig_params.clone(), - orig_params, - &mut fresh_preds, - false, - ) { - Some(e) => e, - None => return AutoTraitResult::NegativeImpl, - }; - - let (full_env, full_user_env) = self.evaluate_predicates( - &mut infcx, - did, - trait_did, - ty, - new_env.clone(), - user_env, - &mut fresh_preds, - true, - ).unwrap_or_else(|| { - panic!( - "Failed to fully process: {:?} {:?} {:?}", - ty, trait_did, orig_params - ) - }); - - debug!( - "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): fulfilling \ + let (new_env, user_env) = + match self.evaluate_predicates(&mut infcx, + did, + trait_did, + ty, + orig_params.clone(), + orig_params, + &mut fresh_preds, + false) { + Some(e) => e, + None => return AutoTraitResult::NegativeImpl, + }; + + let (full_env, full_user_env) = self.evaluate_predicates(&mut infcx, + did, + trait_did, + ty, + new_env.clone(), + user_env, + &mut fresh_preds, + true) + .unwrap_or_else(|| { + panic!("Failed to fully process: {:?} {:?} {:?}", + ty, + trait_did, + orig_params) + }); + + debug!("find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): fulfilling \ with {:?}", - did, trait_did, generics, full_env - ); + did, + trait_did, + generics, + full_env); infcx.clear_caches(); // At this point, we already have all of the bounds we need. FulfillmentContext is used // to store all of the necessary region/lifetime bounds in the InferContext, as well as // an additional sanity check. let mut fulfill = FulfillmentContext::new(); - fulfill.register_bound( - &infcx, - full_env, - ty, - trait_did, - ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID), - ); - fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { - panic!( - "Unable to fulfill trait {:?} for '{:?}': {:?}", - trait_did, ty, e - ) - }); + fulfill.register_bound(&infcx, + full_env, + ty, + trait_did, + ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID)); + fulfill + .select_all_or_error(&infcx) + .unwrap_or_else(|e| { + panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", + trait_did, + ty, + e) + }); let names_map: FxHashMap<String, String> = generics .regions @@ -227,7 +231,12 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let vid_to_region = self.map_vid_to_region(®ion_data); - let info = AutoTraitInfo { full_user_env, region_data, names_map, vid_to_region }; + let info = AutoTraitInfo { + full_user_env, + region_data, + names_map, + vid_to_region, + }; return AutoTraitResult::PositiveImpl(auto_trait_callback(&infcx, info)); }); @@ -272,17 +281,16 @@ 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>( - &self, - infcx: & InferCtxt<'b, 'tcx, 'c>, - ty_did: DefId, - trait_did: DefId, - ty: ty::Ty<'c>, - param_env: ty::ParamEnv<'c>, - user_env: ty::ParamEnv<'c>, - fresh_preds: &mut FxHashSet<ty::Predicate<'c>>, - only_projections: bool, - ) -> Option<(ty::ParamEnv<'c>, ty::ParamEnv<'c>)> { + pub fn evaluate_predicates<'b, 'gcx, 'c>(&self, + infcx: &InferCtxt<'b, 'tcx, 'c>, + ty_did: DefId, + trait_did: DefId, + ty: ty::Ty<'c>, + param_env: ty::ParamEnv<'c>, + user_env: ty::ParamEnv<'c>, + fresh_preds: &mut FxHashSet<ty::Predicate<'c>>, + only_projections: bool) + -> Option<(ty::ParamEnv<'c>, ty::ParamEnv<'c>)> { let tcx = infcx.tcx; let mut select = SelectionContext::new(&infcx); @@ -290,11 +298,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let mut already_visited = FxHashSet(); let mut predicates = VecDeque::new(); predicates.push_back(ty::Binder::bind(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: trait_did, - substs: infcx.tcx.mk_substs_trait(ty, &[]), - }, - })); + trait_ref: ty::TraitRef { + def_id: trait_did, + substs: infcx.tcx.mk_substs_trait(ty, &[]), + }, + })); let mut computed_preds: FxHashSet<_> = param_env.caller_bounds.iter().cloned().collect(); let mut user_computed_preds: FxHashSet<_> = @@ -316,15 +324,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { &Ok(Some(ref vtable)) => { let obligations = vtable.clone().nested_obligations().into_iter(); - if !self.evaluate_nested_obligations( - ty, - obligations, - &mut user_computed_preds, - fresh_preds, - &mut predicates, - &mut select, - only_projections, - ) { + if !self.evaluate_nested_obligations(ty, + obligations, + &mut user_computed_preds, + fresh_preds, + &mut predicates, + &mut select, + only_projections) { return None; } } @@ -335,13 +341,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { user_computed_preds.insert(ty::Predicate::Trait(pred.clone())); predicates.push_back(pred); } else { - debug!( - "evaluate_nested_obligations: Unimplemented found, bailing: {:?} {:?} \ - {:?}", - ty, - pred, - pred.skip_binder().trait_ref.substs - ); + debug!("evaluate_nested_obligations: Unimplemented found, bailing: \ + {:?} {:?} {:?}", + ty, + pred, + pred.skip_binder().trait_ref.substs); return None; } } @@ -351,21 +355,17 @@ 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()); - new_env = ty::ParamEnv::new( - tcx.mk_predicates(normalized_preds), - param_env.reveal, - ); + new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal); } - let final_user_env = ty::ParamEnv::new( - tcx.mk_predicates(user_computed_preds.into_iter()), - user_env.reveal, - ); - debug!( - "evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \ + let final_user_env = ty::ParamEnv::new(tcx.mk_predicates(user_computed_preds.into_iter()), + user_env.reveal); + debug!("evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \ '{:?}'", - ty_did, trait_did, new_env, final_user_env - ); + ty_did, + trait_did, + new_env, + final_user_env); return Some((new_env, final_user_env)); } @@ -380,9 +380,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { pub fn get_lifetime(&self, region: Region, names_map: &FxHashMap<String, String>) -> String { self.region_name(region) .map(|name| { - names_map.get(&name).unwrap_or_else(|| { - panic!("Missing lifetime with name {:?} for {:?}", name, region) - }) + names_map + .get(&name) + .unwrap_or_else(|| { + panic!("Missing lifetime with name {:?} for {:?}", + name, + region) + }) }) .unwrap_or(&"'static".to_string()) .clone() @@ -390,10 +394,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // 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>( - &self, - regions: &RegionConstraintData<'cx>, - ) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> { + pub fn map_vid_to_region<'cx>(&self, + regions: &RegionConstraintData<'cx>) + -> FxHashMap<ty::RegionVid, ty::Region<'cx>> { let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap(); let mut finished_map = FxHashMap(); @@ -496,31 +499,34 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } return match substs.type_at(0).sty { - ty::TyParam(_) => true, - ty::TyProjection(p) => self.is_of_param(p.substs), - _ => false, - }; + ty::TyParam(_) => true, + ty::TyProjection(p) => self.is_of_param(p.substs), + _ => false, + }; } - pub fn evaluate_nested_obligations<'b, 'c, 'd, 'cx, - T: Iterator<Item = Obligation<'cx, ty::Predicate<'cx>>>>( - &self, - ty: ty::Ty, - nested: T, - computed_preds: &'b mut FxHashSet<ty::Predicate<'cx>>, - fresh_preds: &'b mut FxHashSet<ty::Predicate<'cx>>, - predicates: &'b mut VecDeque<ty::PolyTraitPredicate<'cx>>, - select: &mut SelectionContext<'c, 'd, 'cx>, - only_projections: bool, - ) -> bool { + pub fn evaluate_nested_obligations<'b, + 'c, + 'd, + 'cx, + T: Iterator<Item = Obligation<'cx, ty::Predicate<'cx>>>> + (&self, + ty: ty::Ty, + nested: T, + computed_preds: &'b mut FxHashSet<ty::Predicate<'cx>>, + fresh_preds: &'b mut FxHashSet<ty::Predicate<'cx>>, + predicates: &'b mut VecDeque<ty::PolyTraitPredicate<'cx>>, + select: &mut SelectionContext<'c, 'd, 'cx>, + only_projections: bool) + -> bool { let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID); - for (obligation, predicate) in nested - .filter(|o| o.recursion_depth == 1) - .map(|o| (o.clone(), o.predicate.clone())) - { - let is_new_pred = - fresh_preds.insert(self.clean_pred(select.infcx(), predicate.clone())); + for (obligation, predicate) in + nested + .filter(|o| o.recursion_depth == 1) + .map(|o| (o.clone(), o.predicate.clone())) { + let is_new_pred = fresh_preds + .insert(self.clean_pred(select.infcx(), predicate.clone())); match &predicate { &ty::Predicate::Trait(ref p) => { @@ -537,28 +543,22 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { if self.is_of_param(p.skip_binder().projection_ty.substs) && is_new_pred { computed_preds.insert(predicate); } else { - match poly_project_and_unify_type( - select, - &obligation.with(p.clone()), - ) { + match poly_project_and_unify_type(select, &obligation.with(p.clone())) { Err(e) => { - debug!( - "evaluate_nested_obligations: Unable to unify predicate \ + debug!("evaluate_nested_obligations: Unable to unify predicate \ '{:?}' '{:?}', bailing out", - ty, e - ); + ty, + e); return false; } Ok(Some(v)) => { - if !self.evaluate_nested_obligations( - ty, - v.clone().iter().cloned(), - computed_preds, - fresh_preds, - predicates, - select, - only_projections, - ) { + if !self.evaluate_nested_obligations(ty, + v.clone().iter().cloned(), + computed_preds, + fresh_preds, + predicates, + select, + only_projections) { return false; } } @@ -570,36 +570,37 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } &ty::Predicate::RegionOutlives(ref binder) => { if let Err(_) = select - .infcx() - .region_outlives_predicate(&dummy_cause, binder) - { + .infcx() + .region_outlives_predicate(&dummy_cause, binder) { return false; } } &ty::Predicate::TypeOutlives(ref binder) => { - match ( - binder.no_late_bound_regions(), - binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(), - ) { + match (binder.no_late_bound_regions(), + binder.map_bound_ref(|pred| pred.0).no_late_bound_regions()) { (None, Some(t_a)) => { - select.infcx().register_region_obligation( - ast::DUMMY_NODE_ID, - RegionObligation { - sup_type: t_a, - sub_region: select.infcx().tcx.types.re_static, - cause: dummy_cause.clone(), - }, - ); + select + .infcx() + .register_region_obligation(ast::DUMMY_NODE_ID, + RegionObligation { + sup_type: t_a, + sub_region: select + .infcx() + .tcx + .types + .re_static, + cause: dummy_cause.clone(), + }); } (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - select.infcx().register_region_obligation( - ast::DUMMY_NODE_ID, - RegionObligation { - sup_type: t_a, - sub_region: r_b, - cause: dummy_cause.clone(), - }, - ); + select + .infcx() + .register_region_obligation(ast::DUMMY_NODE_ID, + RegionObligation { + sup_type: t_a, + sub_region: r_b, + cause: dummy_cause.clone(), + }); } _ => {} }; @@ -610,11 +611,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { return true; } - pub fn clean_pred<'c, 'd, 'cx>( - &self, - infcx: &InferCtxt<'c, 'd, 'cx>, - p: ty::Predicate<'cx>, - ) -> ty::Predicate<'cx> { + pub fn clean_pred<'c, 'd, 'cx>(&self, + infcx: &InferCtxt<'c, 'd, 'cx>, + p: ty::Predicate<'cx>) + -> ty::Predicate<'cx> { infcx.freshen(p) } } @@ -632,8 +632,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { (match r { - &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), - _ => None, - }).unwrap_or_else(|| r.super_fold_with(self)) + &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), + _ => None, + }) + .unwrap_or_else(|| r.super_fold_with(self)) } } |
