Skip to content
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

Reason about nested free variables that appear in a function signature #5795

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
21 changes: 21 additions & 0 deletions src/libcore/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ totalord_impl!(i64)
totalord_impl!(int)
totalord_impl!(uint)

pub fn cmp2<A:TotalOrd,B:TotalOrd>(
a1: &A, b1: &B,
a2: &A, b2: &B) -> Ordering
{
//! Compares (a1, b1) against (a2, b2), where the a values are more significant.

match a1.cmp(a2) {
Less => Less,
Greater => Greater,
Equal => b1.cmp(b2)
}
}

/**
* Trait for values that can be compared for a sort-order.
*
Expand Down Expand Up @@ -175,6 +188,14 @@ mod test {
assert_eq!(12.cmp(-5), Greater);
}

#[test]
fn test_cmp2() {
assert_eq!(cmp2(1, 2, 3, 4), Less);
assert_eq!(cmp2(3, 2, 3, 4), Less);
assert_eq!(cmp2(5, 2, 3, 4), Greater);
assert_eq!(cmp2(5, 5, 5, 4), Greater);
}

#[test]
fn test_int_totaleq() {
assert!(5.equals(&5));
Expand Down
6 changes: 5 additions & 1 deletion src/libcore/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,11 @@ pub fn slice_shift_char<'a>(s: &'a str) -> (char, &'a str) {

/// Prepend a char to a string
pub fn unshift_char(s: &mut ~str, ch: char) {
*s = from_char(ch) + *s;
// This could be more efficient.
let mut new_str = ~"";
new_str.push_char(ch);
new_str.push_str(*s);
*s = new_str;
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/libcore/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ impl<A:Ord> Ord for (A,) {
fn gt(&self, other: &(A,)) -> bool { other.lt(&(*self)) }
}


#[cfg(notest)]
impl<A:Eq,B:Eq> Eq for (A, B) {
#[inline(always)]
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ fn parse_region(st: @mut PState) -> ty::Region {
assert!(next(st) == '|');
let br = parse_bound_region(st);
assert!(next(st) == ']');
ty::re_free(id, br)
ty::re_free(ty::FreeRegion {scope_id: id,
bound_region: br})
}
's' => {
let id = parse_int(st);
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,12 @@ fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) {
w.write_char('b');
enc_bound_region(w, cx, br);
}
ty::re_free(id, br) => {
ty::re_free(ref fr) => {
w.write_char('f');
w.write_char('[');
w.write_int(id);
w.write_int(fr.scope_id);
w.write_char('|');
enc_bound_region(w, cx, br);
enc_bound_region(w, cx, fr.bound_region);
w.write_char(']');
}
ty::re_scope(nid) => {
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,12 @@ impl tr for ty::Region {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region {
match *self {
ty::re_bound(br) => ty::re_bound(br.tr(xcx)),
ty::re_free(id, br) => ty::re_free(xcx.tr_id(id), br.tr(xcx)),
ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)),
ty::re_static | ty::re_infer(*) => *self,
ty::re_free(ref fr) => {
ty::re_free(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id),
bound_region: fr.bound_region.tr(xcx)})
}
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/librustc/middle/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ pub impl CheckLoanCtxt {
Some(e) => return Some(pc_cmt(*e))
}

match self.tcx().region_map.find(&scope_id) {
match self.tcx().region_maps.opt_encl_scope(scope_id) {
None => return default_purity,
Some(&next_scope_id) => scope_id = next_scope_id
Some(next_scope_id) => scope_id = next_scope_id
}
}
}
Expand All @@ -146,9 +146,9 @@ pub impl CheckLoanCtxt {
}
}

match self.tcx().region_map.find(&scope_id) {
match self.tcx().region_maps.opt_encl_scope(scope_id) {
None => return,
Some(&next_scope_id) => scope_id = next_scope_id,
Some(next_scope_id) => scope_id = next_scope_id,
}
}
}
Expand Down Expand Up @@ -270,7 +270,7 @@ pub impl CheckLoanCtxt {

debug!("new_loans has length %?", new_loans.len());

let par_scope_id = *self.tcx().region_map.get(&scope_id);
let par_scope_id = self.tcx().region_maps.encl_scope(scope_id);
for self.walk_loans(par_scope_id) |old_loan| {
debug!("old_loan=%?", self.bccx.loan_to_repr(old_loan));

Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/borrowck/gather_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ fn req_loans_in_expr(ex: @ast::expr,
// (if used like `a.b(...)`), the call where it's an argument
// (if used like `x(a.b)`), or the block (if used like `let x
// = a.b`).
let scope_r = ty::re_scope(*self.tcx().region_map.get(&ex.id));
let scope_r = self.tcx().region_maps.encl_region(ex.id);
let rcvr_cmt = self.bccx.cat_expr(rcvr);
self.guarantee_valid(rcvr_cmt, m_imm, scope_r);
visit::visit_expr(ex, self, vt);
Expand Down Expand Up @@ -524,7 +524,10 @@ pub impl GatherLoanCtxt {
// immutable structures, this is just the converse I suppose)

let scope_id = match scope_r {
ty::re_scope(scope_id) | ty::re_free(scope_id, _) => scope_id,
ty::re_scope(scope_id) |
ty::re_free(ty::FreeRegion {scope_id, _}) => {
scope_id
}
_ => {
self.bccx.tcx.sess.span_bug(
cmt.span,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/borrowck/loan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ pub impl LoanContext {
}
cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => {
// FIXME(#4903)
let local_scope_id = *self.bccx.tcx.region_map.get(&local_id);
self.issue_loan(cmt, ty::re_scope(local_scope_id), loan_kind,
let local_region = self.bccx.tcx.region_maps.encl_region(local_id);
self.issue_loan(cmt, local_region, loan_kind,
owns_lent_data)
}
cat_stack_upvar(cmt) => {
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ Borrowck results in two maps.
use core::prelude::*;

use middle::mem_categorization::*;
use middle::region;
use middle::ty;
use middle::typeck;
use middle::moves;
Expand Down Expand Up @@ -458,7 +457,7 @@ pub fn root_map() -> root_map {

pub impl BorrowckCtxt {
fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region) -> bool {
region::is_subregion_of(self.tcx.region_map, r_sub, r_sup)
self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
}

fn cat_expr(&self, expr: @ast::expr) -> cmt {
Expand Down
18 changes: 9 additions & 9 deletions src/librustc/middle/borrowck/preserve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub impl<'self> PreserveCtxt<'self> {
// Maybe if we pass in the parent instead here,
// we can prevent the "scope not found" error
debug!("scope_region thing: %? ", cmt.id);
ty::re_scope(*self.tcx().region_map.get(&cmt.id))
self.tcx().region_maps.encl_region(cmt.id)
};

self.compare_scope(cmt, scope_region)
Expand All @@ -128,27 +128,27 @@ pub impl<'self> PreserveCtxt<'self> {
cmt.span,
~"preserve() called with local and !root_managed_data");
}
let local_scope_id = *self.tcx().region_map.get(&local_id);
self.compare_scope(cmt, ty::re_scope(local_scope_id))
let local_region = self.tcx().region_maps.encl_region(local_id);
self.compare_scope(cmt, local_region)
}
cat_binding(local_id) => {
// Bindings are these kind of weird implicit pointers (cc
// #2329). We require (in gather_loans) that they be
// rooted in an immutable location.
let local_scope_id = *self.tcx().region_map.get(&local_id);
self.compare_scope(cmt, ty::re_scope(local_scope_id))
let local_region = self.tcx().region_maps.encl_region(local_id);
self.compare_scope(cmt, local_region)
}
cat_arg(local_id) => {
// This can happen as not all args are lendable (e.g., &&
// modes). In that case, the caller guarantees stability
// for at least the scope of the fn. This is basically a
// deref of a region ptr.
let local_scope_id = *self.tcx().region_map.get(&local_id);
self.compare_scope(cmt, ty::re_scope(local_scope_id))
let local_region = self.tcx().region_maps.encl_region(local_id);
self.compare_scope(cmt, local_region)
}
cat_self(local_id) => {
let local_scope_id = *self.tcx().region_map.get(&local_id);
self.compare_scope(cmt, ty::re_scope(local_scope_id))
let local_region = self.tcx().region_maps.encl_region(local_id);
self.compare_scope(cmt, local_region)
}
cat_comp(cmt_base, comp_field(*)) |
cat_comp(cmt_base, comp_index(*)) |
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,11 @@ pub fn specialize(cx: @MatchCheckCtxt,
class_id);
}
_ => {
cx.tcx.sess.span_bug(pat_span,
~"struct pattern didn't resolve to a struct");
cx.tcx.sess.span_bug(
pat_span,
fmt!("struct pattern resolved to %s, \
not a struct",
ty_to_str(cx.tcx, left_ty)));
}
}
let args = vec::map(class_fields, |class_field| {
Expand Down
102 changes: 71 additions & 31 deletions src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use middle::liveness;
use middle::pat_util;
use middle::ty;
use middle::typeck;
use util::ppaux::{ty_to_str, tys_to_str};
use util::ppaux::{ty_to_str, tys_to_str, note_and_explain_region};

use syntax::ast::*;
use syntax::attr::attrs_contains_name;
Expand Down Expand Up @@ -477,13 +477,13 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
}
}

/// This is rather subtle. When we are casting a value to a
/// instantiated trait like `a as trait<'r>`, regionck already ensures
/// that any borrowed pointers that appear in the type of `a` are
/// bounded by `&r`. However, it is possible that there are *type
/// parameters* in the type of `a`, and those *type parameters* may
/// have borrowed pointers within them. We have to guarantee that the
/// regions which appear in those type parameters are not obscured.
/// This is rather subtle. When we are casting a value to a instantiated
/// trait like `a as trait<'r>`, regionck already ensures that any borrowed
/// pointers that appear in the type of `a` are bounded by `'r` (ed.: modulo
/// FIXME(#5723)). However, it is possible that there are *type parameters*
/// in the type of `a`, and those *type parameters* may have borrowed pointers
/// within them. We have to guarantee that the regions which appear in those
/// type parameters are not obscured.
///
/// Therefore, we ensure that one of three conditions holds:
///
Expand All @@ -500,6 +500,8 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool {
///
/// (3) The type parameter is owned (and therefore does not contain
/// borrowed ptrs).
///
/// FIXME(#5723)---This code should probably move into regionck.
pub fn check_cast_for_escaping_regions(
cx: Context,
source: @expr,
Expand All @@ -508,40 +510,78 @@ pub fn check_cast_for_escaping_regions(
// Determine what type we are casting to; if it is not an trait, then no
// worries.
let target_ty = ty::expr_ty(cx.tcx, target);
let target_substs = match ty::get(target_ty).sty {
ty::ty_trait(_, ref substs, _) => {(/*bad*/copy *substs)}
_ => { return; /* not a cast to a trait */ }
};
match ty::get(target_ty).sty {
ty::ty_trait(*) => {}
_ => { return; }
}

// Collect up the regions that appear in the target type. We want to
// ensure that these lifetimes are shorter than all lifetimes that are in
// the source type. See test `src/test/compile-fail/regions-trait-2.rs`
let mut target_regions = ~[];
ty::walk_regions_and_ty(
cx.tcx,
target_ty,
|r| {
if !r.is_bound() {
target_regions.push(r);
}
},
|_| true);

// Check, based on the region associated with the trait, whether it can
// possibly escape the enclosing fn item (note that all type parameters
// must have been declared on the enclosing fn item):
match target_substs.self_r {
Some(ty::re_scope(*)) => { return; /* case (1) */ }
None | Some(ty::re_static) | Some(ty::re_free(*)) => {}
Some(ty::re_bound(*)) | Some(ty::re_infer(*)) => {
cx.tcx.sess.span_bug(
source.span,
fmt!("bad region found in kind: %?", target_substs.self_r));
}
// must have been declared on the enclosing fn item).
if target_regions.any(|r| is_re_scope(*r)) {
return; /* case (1) */
}

// Assuming the trait instance can escape, then ensure that each parameter
// either appears in the trait type or is owned:
// either appears in the trait type or is owned.
let target_params = ty::param_tys_in_type(target_ty);
let source_ty = ty::expr_ty(cx.tcx, source);
do ty::walk_ty(source_ty) |ty| {
match ty::get(ty).sty {
ty::ty_param(source_param) => {
if target_params.contains(&source_param) {
/* case (2) */
} else {
check_durable(cx.tcx, ty, source.span); /* case (3) */
ty::walk_regions_and_ty(
cx.tcx,
source_ty,

|_r| {
// FIXME(#5723) --- turn this check on once &Objects are usable
//
// if !target_regions.any(|t_r| is_subregion_of(cx, *t_r, r)) {
// cx.tcx.sess.span_err(
// source.span,
// fmt!("source contains borrowed pointer with lifetime \
// not found in the target type `%s`",
// ty_to_str(cx.tcx, target_ty)));
// note_and_explain_region(
// cx.tcx, "source data is only valid for ", r, "");
// }
},

|ty| {
match ty::get(ty).sty {
ty::ty_param(source_param) => {
if target_params.contains(&source_param) {
/* case (2) */
} else {
check_durable(cx.tcx, ty, source.span); /* case (3) */
}
}
_ => {}
}
}
_ => {}
true
});

fn is_re_scope(+r: ty::Region) -> bool {
match r {
ty::re_scope(*) => true,
_ => false
}
}

fn is_subregion_of(cx: Context, r_sub: ty::Region, r_sup: ty::Region) -> bool {
cx.tcx.region_maps.is_subregion_of(r_sub, r_sup)
}
}

/// Ensures that values placed into a ~Trait are copyable and sendable.
Expand Down
Loading