diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4d772de7835..4f6c1305f76 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -108,7 +108,6 @@ pub mod middle { pub mod free_region; pub mod intrinsicck; pub mod infer; - pub mod implicator; pub mod lang_items; pub mod liveness; pub mod mem_categorization; diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs deleted file mode 100644 index d25084bbdff..00000000000 --- a/src/librustc/middle/implicator.rs +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright 2012 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. - -// #![warn(deprecated_mode)] - -use middle::def_id::DefId; -use middle::infer::{InferCtxt, GenericKind}; -use middle::subst::Substs; -use middle::traits; -use middle::ty::{self, ToPredicate, Ty}; -use middle::ty::fold::{TypeFoldable, TypeFolder}; - -use syntax::ast; -use syntax::codemap::Span; - -use util::common::ErrorReported; -use util::nodemap::FnvHashSet; - -// Helper functions related to manipulating region types. - -#[derive(Debug)] -pub enum Implication<'tcx> { - RegionSubRegion(Option>, ty::Region, ty::Region), - RegionSubGeneric(Option>, ty::Region, GenericKind<'tcx>), - Predicate(DefId, ty::Predicate<'tcx>), -} - -struct Implicator<'a, 'tcx: 'a> { - infcx: &'a InferCtxt<'a,'tcx>, - body_id: ast::NodeId, - stack: Vec<(ty::Region, Option>)>, - span: Span, - out: Vec>, - visited: FnvHashSet>, -} - -/// This routine computes the well-formedness constraints that must hold for the type `ty` to -/// appear in a context with lifetime `outer_region` -pub fn implications<'a,'tcx>( - infcx: &'a InferCtxt<'a,'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - outer_region: ty::Region, - span: Span) - -> Vec> -{ - debug!("implications(body_id={}, ty={:?}, outer_region={:?})", - body_id, - ty, - outer_region); - - let mut stack = Vec::new(); - stack.push((outer_region, None)); - let mut wf = Implicator { infcx: infcx, - body_id: body_id, - span: span, - stack: stack, - out: Vec::new(), - visited: FnvHashSet() }; - wf.accumulate_from_ty(ty); - debug!("implications: out={:?}", wf.out); - wf.out -} - -impl<'a, 'tcx> Implicator<'a, 'tcx> { - fn tcx(&self) -> &'a ty::ctxt<'tcx> { - self.infcx.tcx - } - - fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) { - debug!("accumulate_from_ty(ty={:?})", - ty); - - // When expanding out associated types, we can visit a cyclic - // set of types. Issue #23003. - if !self.visited.insert(ty) { - return; - } - - match ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(..) | - ty::TyUint(..) | - ty::TyFloat(..) | - ty::TyBareFn(..) | - ty::TyError | - ty::TyStr => { - // No borrowed content reachable here. - } - - ty::TyClosure(_, ref substs) => { - // FIXME(#27086). We do not accumulate from substs, since they - // don't represent reachable data. This means that, in - // practice, some of the lifetime parameters might not - // be in scope when the body runs, so long as there is - // no reachable data with that lifetime. For better or - // worse, this is consistent with fn types, however, - // which can also encapsulate data in this fashion - // (though it's somewhat harder, and typically - // requires virtual dispatch). - // - // Note that changing this (in a naive way, at least) - // causes regressions for what appears to be perfectly - // reasonable code like this: - // - // ``` - // fn foo<'a>(p: &Data<'a>) { - // bar(|q: &mut Parser| q.read_addr()) - // } - // fn bar(p: Box) { - // } - // ``` - // - // Note that `p` (and `'a`) are not used in the - // closure at all, but to meet the requirement that - // the closure type `C: 'static` (so it can be coerced - // to the object type), we get the requirement that - // `'a: 'static` since `'a` appears in the closure - // type `C`. - // - // A smarter fix might "prune" unused `func_substs` -- - // this would avoid breaking simple examples like - // this, but would still break others (which might - // indeed be invalid, depending on your POV). Pruning - // would be a subtle process, since we have to see - // what func/type parameters are used and unused, - // taking into consideration UFCS and so forth. - - for &upvar_ty in &substs.upvar_tys { - self.accumulate_from_ty(upvar_ty); - } - } - - ty::TyTrait(ref t) => { - let required_region_bounds = - object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds); - self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds) - } - - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) => { - let item_scheme = def.type_scheme(self.tcx()); - self.accumulate_from_adt(ty, def.did, &item_scheme.generics, substs) - } - - ty::TyArray(t, _) | - ty::TySlice(t) | - ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) | - ty::TyBox(t) => { - self.accumulate_from_ty(t) - } - - ty::TyRef(r_b, mt) => { - self.accumulate_from_rptr(ty, *r_b, mt.ty); - } - - ty::TyParam(p) => { - self.push_param_constraint_from_top(p); - } - - ty::TyProjection(ref data) => { - // `>::Name` - - self.push_projection_constraint_from_top(data); - } - - ty::TyTuple(ref tuptys) => { - for &tupty in tuptys { - self.accumulate_from_ty(tupty); - } - } - - ty::TyInfer(_) => { - // This should not happen, BUT: - // - // Currently we uncover region relationships on - // entering the fn check. We should do this after - // the fn check, then we can call this case a bug(). - } - } - } - - fn accumulate_from_rptr(&mut self, - ty: Ty<'tcx>, - r_b: ty::Region, - ty_b: Ty<'tcx>) { - // We are walking down a type like this, and current - // position is indicated by caret: - // - // &'a &'b ty_b - // ^ - // - // At this point, top of stack will be `'a`. We must - // require that `'a <= 'b`. - - self.push_region_constraint_from_top(r_b); - - // Now we push `'b` onto the stack, because it must - // constrain any borrowed content we find within `T`. - - self.stack.push((r_b, Some(ty))); - self.accumulate_from_ty(ty_b); - self.stack.pop().unwrap(); - } - - /// Pushes a constraint that `r_b` must outlive the top region on the stack. - fn push_region_constraint_from_top(&mut self, - r_b: ty::Region) { - - // Indicates that we have found borrowed content with a lifetime - // of at least `r_b`. This adds a constraint that `r_b` must - // outlive the region `r_a` on top of the stack. - // - // As an example, imagine walking a type like: - // - // &'a &'b T - // ^ - // - // when we hit the inner pointer (indicated by caret), `'a` will - // be on top of stack and `'b` will be the lifetime of the content - // we just found. So we add constraint that `'a <= 'b`. - - let &(r_a, opt_ty) = self.stack.last().unwrap(); - self.push_sub_region_constraint(opt_ty, r_a, r_b); - } - - /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty` - fn push_sub_region_constraint(&mut self, - opt_ty: Option>, - r_a: ty::Region, - r_b: ty::Region) { - self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b)); - } - - /// Pushes a constraint that `param_ty` must outlive the top region on the stack. - fn push_param_constraint_from_top(&mut self, - param_ty: ty::ParamTy) { - let &(region, opt_ty) = self.stack.last().unwrap(); - self.push_param_constraint(region, opt_ty, param_ty); - } - - /// Pushes a constraint that `projection_ty` must outlive the top region on the stack. - fn push_projection_constraint_from_top(&mut self, - projection_ty: &ty::ProjectionTy<'tcx>) { - let &(region, opt_ty) = self.stack.last().unwrap(); - self.out.push(Implication::RegionSubGeneric( - opt_ty, region, GenericKind::Projection(projection_ty.clone()))); - } - - /// Pushes a constraint that `region <= param_ty`, due to `opt_ty` - fn push_param_constraint(&mut self, - region: ty::Region, - opt_ty: Option>, - param_ty: ty::ParamTy) { - self.out.push(Implication::RegionSubGeneric( - opt_ty, region, GenericKind::Param(param_ty))); - } - - fn accumulate_from_adt(&mut self, - ty: Ty<'tcx>, - def_id: DefId, - _generics: &ty::Generics<'tcx>, - substs: &Substs<'tcx>) - { - let predicates = - self.tcx().lookup_predicates(def_id).instantiate(self.tcx(), substs); - let predicates = match self.fully_normalize(&predicates) { - Ok(predicates) => predicates, - Err(ErrorReported) => { return; } - }; - - for predicate in predicates.predicates.as_slice() { - match *predicate { - ty::Predicate::Trait(..) => { } - ty::Predicate::Equate(..) => { } - ty::Predicate::Projection(..) => { } - ty::Predicate::RegionOutlives(ref data) => { - match self.tcx().no_late_bound_regions(data) { - None => { } - Some(ty::OutlivesPredicate(r_a, r_b)) => { - self.push_sub_region_constraint(Some(ty), r_b, r_a); - } - } - } - ty::Predicate::TypeOutlives(ref data) => { - match self.tcx().no_late_bound_regions(data) { - None => { } - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - self.stack.push((r_b, Some(ty))); - self.accumulate_from_ty(ty_a); - self.stack.pop().unwrap(); - } - } - } - ty::Predicate::ObjectSafe(_) | - ty::Predicate::WellFormed(_) => { - } - } - } - - let obligations = predicates.predicates - .into_iter() - .map(|pred| Implication::Predicate(def_id, pred)); - self.out.extend(obligations); - - let variances = self.tcx().item_variances(def_id); - self.accumulate_from_substs(substs, Some(&variances)); - } - - fn accumulate_from_substs(&mut self, - substs: &Substs<'tcx>, - variances: Option<&ty::ItemVariances>) - { - let mut tmp_variances = None; - let variances = variances.unwrap_or_else(|| { - tmp_variances = Some(ty::ItemVariances { - types: substs.types.map(|_| ty::Variance::Invariant), - regions: substs.regions().map(|_| ty::Variance::Invariant), - }); - tmp_variances.as_ref().unwrap() - }); - - for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) { - match variance { - ty::Contravariant | ty::Invariant => { - // If any data with this lifetime is reachable - // within, it must be at least contravariant. - self.push_region_constraint_from_top(region) - } - ty::Covariant | ty::Bivariant => { } - } - } - - for (&ty, &variance) in substs.types.iter().zip(&variances.types) { - match variance { - ty::Covariant | ty::Invariant => { - // If any data of this type is reachable within, - // it must be at least covariant. - self.accumulate_from_ty(ty); - } - ty::Contravariant | ty::Bivariant => { } - } - } - } - - fn accumulate_from_object_ty(&mut self, - ty: Ty<'tcx>, - region_bound: ty::Region, - required_region_bounds: Vec) - { - // Imagine a type like this: - // - // trait Foo { } - // trait Bar<'c> : 'c { } - // - // &'b (Foo+'c+Bar<'d>) - // ^ - // - // In this case, the following relationships must hold: - // - // 'b <= 'c - // 'd <= 'c - // - // The first conditions is due to the normal region pointer - // rules, which say that a reference cannot outlive its - // referent. - // - // The final condition may be a bit surprising. In particular, - // you may expect that it would have been `'c <= 'd`, since - // usually lifetimes of outer things are conservative - // approximations for inner things. However, it works somewhat - // differently with trait objects: here the idea is that if the - // user specifies a region bound (`'c`, in this case) it is the - // "master bound" that *implies* that bounds from other traits are - // all met. (Remember that *all bounds* in a type like - // `Foo+Bar+Zed` must be met, not just one, hence if we write - // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and - // 'y.) - // - // Note: in fact we only permit builtin traits, not `Bar<'d>`, I - // am looking forward to the future here. - - // The content of this object type must outlive - // `bounds.region_bound`: - let r_c = region_bound; - self.push_region_constraint_from_top(r_c); - - // And then, in turn, to be well-formed, the - // `region_bound` that user specified must imply the - // region bounds required from all of the trait types: - for &r_d in &required_region_bounds { - // Each of these is an instance of the `'c <= 'b` - // constraint above - self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c)); - } - } - - fn fully_normalize(&self, value: &T) -> Result - where T : TypeFoldable<'tcx> - { - let value = - traits::fully_normalize(self.infcx, - traits::ObligationCause::misc(self.span, self.body_id), - value); - match value { - Ok(value) => Ok(value), - Err(errors) => { - // I don't like reporting these errors here, but I - // don't know where else to report them just now. And - // I don't really expect errors to arise here - // frequently. I guess the best option would be to - // propagate them out. - traits::report_fulfillment_errors(self.infcx, &errors); - Err(ErrorReported) - } - } - } -} - -/// Given an object type like `SomeTrait+Send`, computes the lifetime -/// bounds that must hold on the elided self type. These are derived -/// from the declarations of `SomeTrait`, `Send`, and friends -- if -/// they declare `trait SomeTrait : 'static`, for example, then -/// `'static` would appear in the list. The hard work is done by -/// `ty::required_region_bounds`, see that for more information. -pub fn object_region_bounds<'tcx>( - tcx: &ty::ctxt<'tcx>, - principal: &ty::PolyTraitRef<'tcx>, - others: ty::BuiltinBounds) - -> Vec -{ - // Since we don't actually *know* the self type for an object, - // this "open(err)" serves as a kind of dummy standin -- basically - // a skolemized type. - let open_ty = tcx.mk_infer(ty::FreshTy(0)); - - // Note that we preserve the overall binding levels here. - assert!(!open_ty.has_escaping_regions()); - let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); - let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs))); - - let mut predicates = others.to_predicates(tcx, open_ty); - predicates.extend(trait_refs.iter().map(|t| t.to_predicate())); - - tcx.required_region_bounds(open_ty, predicates) -} diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 47cd31d9898..56b02412c31 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -86,7 +86,6 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; use middle::free_region::FreeRegionMap; -use middle::implicator::{self, Implication}; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use middle::region::{self, CodeExtent}; @@ -365,12 +364,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { r_o, r_o.cause); let sup_type = self.resolve_type(r_o.sup_type); let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code); - - if r_o.sub_region != ty::ReEmpty { - type_must_outlive(self, origin, sup_type, r_o.sub_region); - } else { - self.visit_old_school_wf(node_id, sup_type, origin); - } + type_must_outlive(self, origin, sup_type, r_o.sub_region); } // Processing the region obligations should not cause the list to grow further: @@ -378,47 +372,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { self.fcx.inh.infcx.fulfillment_cx.borrow().region_obligations(node_id).len()); } - fn visit_old_school_wf(&mut self, - body_id: ast::NodeId, - ty: Ty<'tcx>, - origin: infer::SubregionOrigin<'tcx>) { - // As a weird kind of hack, we use a region of empty as a signal - // to mean "old-school WF rules". The only reason the old-school - // WF rules are not encoded using WF is that this leads to errors, - // and we want to phase those in gradually. - - // FIXME(#27579) remove this weird special case once we phase in new WF rules completely - let implications = implicator::implications(self.infcx(), - body_id, - ty, - ty::ReEmpty, - origin.span()); - let origin_for_ty = |ty: Option>| match ty { - None => origin.clone(), - Some(ty) => infer::ReferenceOutlivesReferent(ty, origin.span()), - }; - for implication in implications { - match implication { - Implication::RegionSubRegion(ty, r1, r2) => { - self.fcx.mk_subr(origin_for_ty(ty), r1, r2); - } - Implication::RegionSubGeneric(ty, r1, GenericKind::Param(param_ty)) => { - param_ty_must_outlive(self, origin_for_ty(ty), r1, param_ty); - } - Implication::RegionSubGeneric(ty, r1, GenericKind::Projection(proj_ty)) => { - projection_must_outlive(self, origin_for_ty(ty), r1, proj_ty); - } - Implication::Predicate(def_id, predicate) => { - let cause = traits::ObligationCause::new(origin.span(), - body_id, - traits::ItemObligation(def_id)); - let obligation = traits::Obligation::new(cause, predicate); - self.fcx.register_predicate(obligation); - } - } - } - } - fn code_to_origin(&self, span: Span, sup_type: Ty<'tcx>,