Skip to content

Cherry-picking PR 24553 into [beta] #24941

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,11 @@ pub mod middle {
pub mod entry;
pub mod expr_use_visitor;
pub mod fast_reject;
pub mod free_region;
pub mod graph;
pub mod intrinsicck;
pub mod infer;
pub mod implicator;
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;
Expand Down
127 changes: 127 additions & 0 deletions src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2012-2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This file defines

use middle::implicator::Implication;
use middle::ty::{self, FreeRegion};
use util::common::can_reach;
use util::nodemap::FnvHashMap;
use util::ppaux::Repr;

#[derive(Clone)]
pub struct FreeRegionMap {
/// `free_region_map` maps from a free region `a` to a list of
/// free regions `bs` such that `a <= b for all b in bs`
map: FnvHashMap<FreeRegion, Vec<FreeRegion>>,
}

impl FreeRegionMap {
pub fn new() -> FreeRegionMap {
FreeRegionMap { map: FnvHashMap() }
}

pub fn relate_free_regions_from_implications<'tcx>(&mut self,
tcx: &ty::ctxt<'tcx>,
implications: &[Implication<'tcx>])
{
for implication in implications {
debug!("implication: {}", implication.repr(tcx));
match *implication {
Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
self.relate_free_regions(free_a, free_b);
}
Implication::RegionSubRegion(..) |
Implication::RegionSubClosure(..) |
Implication::RegionSubGeneric(..) |
Implication::Predicate(..) => {
}
}
}
}

pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
tcx: &ty::ctxt<'tcx>,
predicates: &[ty::Predicate<'tcx>]) {
debug!("relate_free_regions_from_predicates(predicates={})", predicates.repr(tcx));
for predicate in predicates {
match *predicate {
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Equate(..) |
ty::Predicate::TypeOutlives(..) => {
// No region bounds here
}
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
match (r_a, r_b) {
(ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
// Record that `'a:'b`. Or, put another way, `'b <= 'a`.
self.relate_free_regions(fr_b, fr_a);
}
_ => {
// All named regions are instantiated with free regions.
tcx.sess.bug(
&format!("record_region_bounds: non free region: {} / {}",
r_a.repr(tcx),
r_b.repr(tcx)));
}
}
}
}
}
}

pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
let mut sups = self.map.entry(sub).or_insert(Vec::new());
if !sups.contains(&sup) {
sups.push(sup);
}
}

/// Determines whether two free regions have a subregion relationship
/// by walking the graph encoded in `map`. Note that
/// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
/// (that is, the user can give two different names to the same lifetime).
pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
can_reach(&self.map, sub, sup)
}

/// Determines whether one region is a subregion of another. This is intended to run *after
/// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
pub fn is_subregion_of(&self,
tcx: &ty::ctxt,
sub_region: ty::Region,
super_region: ty::Region)
-> bool {
debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
sub_region, super_region);

sub_region == super_region || {
match (sub_region, super_region) {
(ty::ReEmpty, _) |
(_, ty::ReStatic) =>
true,

(ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
tcx.region_maps.is_subscope_of(sub_scope, super_scope),

(ty::ReScope(sub_scope), ty::ReFree(ref fr)) =>
tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()),

(ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
self.sub_free_region(sub_fr, super_fr),

_ =>
false,
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@

// #![warn(deprecated_mode)]

use astconv::object_region_bounds;
use middle::infer::{InferCtxt, GenericKind};
use middle::subst::Substs;
use middle::traits;
use middle::ty::{self, ToPolyTraitRef, Ty};
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty_fold::{TypeFoldable, TypeFolder};

use std::rc::Rc;
Expand Down Expand Up @@ -423,6 +422,39 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
}
}

/// 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<ty::Region>
{
// 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 = ty::mk_infer(tcx, 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(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));

let param_bounds = ty::ParamBounds {
region_bounds: Vec::new(),
builtin_bounds: others,
trait_bounds: trait_refs,
projection_bounds: Vec::new(), // not relevant to computing region bounds
};

let predicates = ty::predicates(tcx, open_ty, &param_bounds);
ty::required_region_bounds(tcx, open_ty, predicates)
}

impl<'tcx> Repr<'tcx> for Implication<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub use middle::ty::IntVarValue;
pub use self::freshen::TypeFreshener;
pub use self::region_inference::GenericKind;

use middle::free_region::FreeRegionMap;
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
Expand Down Expand Up @@ -854,8 +855,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.region_vars.new_bound(debruijn)
}

pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) {
let errors = self.region_vars.resolve_regions(subject_node_id);
pub fn resolve_regions_and_report_errors(&self,
free_regions: &FreeRegionMap,
subject_node_id: ast::NodeId) {
let errors = self.region_vars.resolve_regions(free_regions, subject_node_id);
self.report_region_errors(&errors); // see error_reporting.rs
}

Expand Down
Loading