Skip to content

Commit

Permalink
auto merge of #19858 : nick29581/rust/ranges, r=aturon
Browse files Browse the repository at this point in the history
Closes #19794

r? @aturon for the first patch
r? @nikomatsakis for the rest
  • Loading branch information
bors committed Dec 24, 2014
2 parents 96a3c7c + e82215d commit e64a819
Show file tree
Hide file tree
Showing 24 changed files with 452 additions and 15 deletions.
58 changes: 58 additions & 0 deletions src/libcore/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2542,6 +2542,64 @@ impl<A: Int> Iterator<A> for RangeStepInclusive<A> {
}
}


/// The `Step` trait identifies objects which can be stepped over in both
/// directions. The `steps_between` function provides a way to
/// compare two Step objects (it could be provided using `step()` and `Ord`,
/// but the implementation would be so inefficient as to be useless).
#[unstable = "Trait is unstable."]
pub trait Step: Ord {
/// Change self to the next object.
fn step(&mut self);
/// Change self to the previous object.
fn step_back(&mut self);
/// The steps_between two step objects.
/// a should always be less than b, so the result should never be negative.
/// Return None if it is not possible to calculate steps_between without
/// overflow.
fn steps_between(a: &Self, b: &Self) -> Option<uint>;
}

macro_rules! step_impl {
($($t:ty)*) => ($(
#[unstable = "Trait is unstable."]
impl Step for $t {
#[inline]
fn step(&mut self) { *self += 1; }
#[inline]
fn step_back(&mut self) { *self -= 1; }
#[inline]
fn steps_between(a: &$t, b: &$t) -> Option<uint> {
debug_assert!(a < b);
Some((*a - *b) as uint)
}
}
)*)
}

macro_rules! step_impl_no_between {
($($t:ty)*) => ($(
#[unstable = "Trait is unstable."]
impl Step for $t {
#[inline]
fn step(&mut self) { *self += 1; }
#[inline]
fn step_back(&mut self) { *self -= 1; }
#[inline]
fn steps_between(_a: &$t, _b: &$t) -> Option<uint> {
None
}
}
)*)
}

step_impl!(uint u8 u16 u32 int i8 i16 i32);
#[cfg(target_word_size = "64")]
step_impl!(u64 i64);
#[cfg(target_word_size = "32")]
step_impl_no_between!(u64 i64);


/// An iterator that repeats an element endlessly
#[deriving(Clone)]
#[stable]
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
#![allow(unknown_features, raw_pointer_deriving)]
#![feature(globs, intrinsics, lang_items, macro_rules, phase)]
#![feature(simd, unsafe_destructor, slicing_syntax)]
#![feature(default_type_params, unboxed_closures)]
#![feature(default_type_params, unboxed_closures, associated_types)]
#![deny(missing_docs)]

mod macros;
Expand Down
76 changes: 76 additions & 0 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@
//! See the documentation for each trait for a minimum implementation that prints
//! something to the screen.
use clone::Clone;
use iter::{Step, Iterator,DoubleEndedIterator,ExactSizeIterator};
use kinds::Sized;
use option::Option::{mod, Some, None};

/// The `Drop` trait is used to run some code when a value goes out of scope. This
/// is sometimes called a 'destructor'.
Expand Down Expand Up @@ -833,6 +836,79 @@ pub trait SliceMut<Sized? Idx, Sized? Result> for Sized? {
fn slice_or_fail_mut<'a>(&'a mut self, from: &Idx, to: &Idx) -> &'a mut Result;
}


/// An unbounded range.
#[deriving(Copy)]
#[lang="full_range"]
pub struct FullRange;

/// A (half-open) range which is bounded at both ends.
#[deriving(Copy)]
#[lang="range"]
pub struct Range<Idx> {
/// The lower bound of the range (inclusive).
pub start: Idx,
/// The upper bound of the range (exclusive).
pub end: Idx,
}

// FIXME(#19391) needs a snapshot
//impl<Idx: Clone + Step<T=uint>> Iterator<Idx> for Range<Idx> {
impl<Idx: Clone + Step> Iterator<Idx> for Range<Idx> {
#[inline]
fn next(&mut self) -> Option<Idx> {
if self.start < self.end {
let result = self.start.clone();
self.start.step();
return Some(result);
}

return None;
}

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
if let Some(hint) = Step::steps_between(&self.end, &self.start) {
(hint, Some(hint))
} else {
(0, None)
}
}
}

impl<Idx: Clone + Step> DoubleEndedIterator<Idx> for Range<Idx> {
#[inline]
fn next_back(&mut self) -> Option<Idx> {
if self.start < self.end {
self.end.step_back();
return Some(self.end.clone());
}

return None;
}
}

impl<Idx: Clone + Step> ExactSizeIterator<Idx> for Range<Idx> {}

/// A range which is only bounded below.
#[deriving(Copy)]
#[lang="range_from"]
pub struct RangeFrom<Idx> {
/// The lower bound of the range (inclusive).
pub start: Idx,
}

impl<Idx: Clone + Step> Iterator<Idx> for RangeFrom<Idx> {
#[inline]
fn next(&mut self) -> Option<Idx> {
// Deliberately overflow so we loop forever.
let result = self.start.clone();
self.start.step();
return Some(result);
}
}


/// The `Deref` trait is used to specify the functionality of dereferencing
/// operations like `*v`.
///
Expand Down
33 changes: 33 additions & 0 deletions src/libcoretest/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

use test::Bencher;
use core::ops::{Range, FullRange, RangeFrom};

// Overhead of dtors

Expand All @@ -27,3 +28,35 @@ fn alloc_obj_with_dtor(b: &mut Bencher) {
HasDtor { _x : 10 };
})
}

// Test the Range structs without the syntactic sugar.

#[test]
fn test_range() {
let r = Range { start: 2u, end: 10 };
let mut count = 0u;
for (i, ri) in r.enumerate() {
assert!(ri == i + 2);
assert!(ri >= 2u && ri < 10u);
count += 1;
}
assert!(count == 8);
}

#[test]
fn test_range_from() {
let r = RangeFrom { start: 2u };
let mut count = 0u;
for (i, ri) in r.take(10).enumerate() {
assert!(ri == i + 2);
assert!(ri >= 2u && ri < 12u);
count += 1;
}
assert!(count == 10);
}

#[test]
fn test_full_range() {
// Not much to test.
let _ = FullRange;
}
6 changes: 6 additions & 0 deletions src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
start.iter().chain(end.iter()).map(|x| &**x))
}

ast::ExprRange(ref start, ref end) => {
let fields = Some(&**start).into_iter()
.chain(end.as_ref().map(|e| &**e).into_iter());
self.straightline(expr, pred, fields)
}

ast::ExprUnary(_, ref e) if self.is_method_call(expr) => {
self.call(expr, pred, &**e, None::<ast::Expr>.iter())
}
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,11 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
assert!(overloaded);
}

ast::ExprRange(ref start, ref end) => {
self.consume_expr(&**start);
end.as_ref().map(|e| self.consume_expr(&**e));
}

ast::ExprCall(ref callee, ref args) => { // callee(args)
self.walk_callee(expr, &**callee);
self.consume_exprs(args);
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
infer::MatchExpressionArm(_, _) => "match arms have incompatible types",
infer::IfExpression(_) => "if and else have incompatible types",
infer::IfExpressionWithNoElse(_) => "if may be missing an else clause",
infer::RangeExpression(_) => "start and end of range have incompatible types",
infer::EquatePredicate(_) => "equality predicate not satisfied",
};

Expand Down Expand Up @@ -1490,6 +1491,9 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
infer::IfExpressionWithNoElse(_) => {
format!("if may be missing an else clause")
}
infer::RangeExpression(_) => {
format!("start and end of range have compatible types")
}
infer::EquatePredicate(_) => {
format!("equality where clause is satisfied")
}
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ pub enum TypeOrigin {
// Computing common supertype of an if expression with no else counter-part
IfExpressionWithNoElse(Span),

// Computing common supertype in a range expression
RangeExpression(Span),

// `where a == b`
EquatePredicate(Span),
}
Expand Down Expand Up @@ -1084,6 +1087,7 @@ impl TypeOrigin {
MatchExpressionArm(match_span, _) => match_span,
IfExpression(span) => span,
IfExpressionWithNoElse(span) => span,
RangeExpression(span) => span,
EquatePredicate(span) => span,
}
}
Expand Down Expand Up @@ -1117,6 +1121,9 @@ impl<'tcx> Repr<'tcx> for TypeOrigin {
IfExpressionWithNoElse(a) => {
format!("IfExpressionWithNoElse({})", a.repr(tcx))
}
RangeExpression(a) => {
format!("RangeExpression({})", a.repr(tcx))
}
EquatePredicate(a) => {
format!("EquatePredicate({})", a.repr(tcx))
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ lets_do_this! {
IndexMutTraitLangItem, "index_mut", index_mut_trait;
SliceTraitLangItem, "slice", slice_trait;
SliceMutTraitLangItem, "slice_mut", slice_mut_trait;
RangeStructLangItem, "range", range_struct;
RangeFromStructLangItem, "range_from", range_from_struct;
FullRangeStructLangItem, "full_range", full_range_struct;

UnsafeTypeLangItem, "unsafe", unsafe_type;

Expand Down
10 changes: 8 additions & 2 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
ast::ExprBlock(..) | ast::ExprAssign(..) | ast::ExprAssignOp(..) |
ast::ExprMac(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
ast::ExprParen(..) | ast::ExprInlineAsm(..) | ast::ExprBox(..) |
ast::ExprSlice(..) => {
ast::ExprSlice(..) | ast::ExprRange(..) => {
visit::walk_expr(ir, expr);
}
}
Expand Down Expand Up @@ -1197,6 +1197,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_expr(&**e1, succ)
}

ast::ExprRange(ref e1, ref e2) => {
let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ));
self.propagate_through_expr(&**e1, succ)
}

ast::ExprBox(None, ref e) |
ast::ExprAddrOf(_, ref e) |
ast::ExprCast(ref e, _) |
Expand Down Expand Up @@ -1489,7 +1494,8 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
ast::ExprBreak(..) | ast::ExprAgain(..) | ast::ExprLit(_) |
ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) |
ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) |
ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) | ast::ExprSlice(..) => {
ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) |
ast::ExprSlice(..) | ast::ExprRange(..) => {
visit::walk_expr(this, expr);
}
ast::ExprIfLet(..) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
ast::ExprAddrOf(..) | ast::ExprCall(..) |
ast::ExprAssign(..) | ast::ExprAssignOp(..) |
ast::ExprClosure(..) | ast::ExprRet(..) |
ast::ExprUnary(..) | ast::ExprSlice(..) |
ast::ExprUnary(..) | ast::ExprSlice(..) | ast::ExprRange(..) |
ast::ExprMethodCall(..) | ast::ExprCast(..) |
ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
ast::ExprBinary(..) | ast::ExprWhile(..) |
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4261,6 +4261,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprCall(..) |
ast::ExprMethodCall(..) |
ast::ExprStruct(..) |
ast::ExprRange(..) |
ast::ExprTup(..) |
ast::ExprIf(..) |
ast::ExprMatch(..) |
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_back/svh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ mod svh_visitor {
SawExprAssignOp(ast::BinOp),
SawExprIndex,
SawExprSlice,
SawExprRange,
SawExprPath,
SawExprAddrOf(ast::Mutability),
SawExprRet,
Expand Down Expand Up @@ -280,6 +281,7 @@ mod svh_visitor {
ExprTupField(_, id) => SawExprTupField(id.node),
ExprIndex(..) => SawExprIndex,
ExprSlice(..) => SawExprSlice,
ExprRange(..) => SawExprRange,
ExprPath(..) => SawExprPath,
ExprAddrOf(m, _) => SawExprAddrOf(m),
ExprBreak(id) => SawExprBreak(id.map(content)),
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_trans/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3494,6 +3494,11 @@ fn populate_scope_map(cx: &CrateContext,
end.as_ref().map(|x| walk_expr(cx, &**x, scope_stack, scope_map));
}

ast::ExprRange(ref start, ref end) => {
walk_expr(cx, &**start, scope_stack, scope_map);
end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
}

ast::ExprVec(ref init_expressions) |
ast::ExprTup(ref init_expressions) => {
for ie in init_expressions.iter() {
Expand Down
Loading

0 comments on commit e64a819

Please sign in to comment.