mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 05:56:56 +00:00
auto merge of #19858 : nick29581/rust/ranges, r=aturon
Closes #19794 r? @aturon for the first patch r? @nikomatsakis for the rest
This commit is contained in:
commit
e64a8193b0
@ -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]
|
||||
|
@ -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;
|
||||
|
@ -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'.
|
||||
@ -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`.
|
||||
///
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use test::Bencher;
|
||||
use core::ops::{Range, FullRange, RangeFrom};
|
||||
|
||||
// Overhead of dtors
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
@ -1084,6 +1087,7 @@ impl TypeOrigin {
|
||||
MatchExpressionArm(match_span, _) => match_span,
|
||||
IfExpression(span) => span,
|
||||
IfExpressionWithNoElse(span) => span,
|
||||
RangeExpression(span) => span,
|
||||
EquatePredicate(span) => span,
|
||||
}
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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, _) |
|
||||
@ -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(..) => {
|
||||
|
@ -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(..) |
|
||||
|
@ -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(..) |
|
||||
|
@ -247,6 +247,7 @@ mod svh_visitor {
|
||||
SawExprAssignOp(ast::BinOp),
|
||||
SawExprIndex,
|
||||
SawExprSlice,
|
||||
SawExprRange,
|
||||
SawExprPath,
|
||||
SawExprAddrOf(ast::Mutability),
|
||||
SawExprRet,
|
||||
@ -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)),
|
||||
|
@ -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() {
|
||||
|
@ -39,7 +39,7 @@ use back::abi;
|
||||
use llvm::{mod, ValueRef};
|
||||
use middle::def;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{mod, Subst};
|
||||
use middle::subst::{mod, Subst, Substs};
|
||||
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
@ -66,6 +66,7 @@ use trans::type_::Type;
|
||||
use syntax::{ast, ast_util, codemap};
|
||||
use syntax::print::pprust::{expr_to_string};
|
||||
use syntax::ptr::P;
|
||||
use syntax::parse::token;
|
||||
use std::rc::Rc;
|
||||
|
||||
// Destinations
|
||||
@ -1048,8 +1049,49 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
base.as_ref().map(|e| &**e),
|
||||
expr.span,
|
||||
expr.id,
|
||||
node_id_type(bcx, expr.id),
|
||||
dest)
|
||||
}
|
||||
ast::ExprRange(ref start, ref end) => {
|
||||
// FIXME it is just not right that we are synthesising ast nodes in
|
||||
// trans. Shudder.
|
||||
fn make_field(field_name: &str, expr: P<ast::Expr>) -> ast::Field {
|
||||
ast::Field {
|
||||
ident: codemap::dummy_spanned(token::str_to_ident(field_name)),
|
||||
expr: expr,
|
||||
span: codemap::DUMMY_SP,
|
||||
}
|
||||
}
|
||||
|
||||
// A range just desugars into a struct.
|
||||
let (did, fields) = match end {
|
||||
&Some(ref end) => {
|
||||
// Desugar to Range
|
||||
let fields = vec!(make_field("start", start.clone()),
|
||||
make_field("end", end.clone()));
|
||||
(tcx.lang_items.range_struct(), fields)
|
||||
}
|
||||
&None => {
|
||||
// Desugar to RangeFrom
|
||||
let fields = vec!(make_field("start", start.clone()));
|
||||
(tcx.lang_items.range_from_struct(), fields)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(did) = did {
|
||||
let substs = Substs::new_type(vec![node_id_type(bcx, start.id)], vec![]);
|
||||
trans_struct(bcx,
|
||||
fields.as_slice(),
|
||||
None,
|
||||
expr.span,
|
||||
expr.id,
|
||||
ty::mk_struct(tcx, did, substs),
|
||||
dest)
|
||||
} else {
|
||||
tcx.sess.span_bug(expr.span,
|
||||
"No lang item for ranges (how did we get this far?)")
|
||||
}
|
||||
}
|
||||
ast::ExprTup(ref args) => {
|
||||
let numbered_fields: Vec<(uint, &ast::Expr)> =
|
||||
args.iter().enumerate().map(|(i, arg)| (i, &**arg)).collect();
|
||||
@ -1347,10 +1389,10 @@ fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
base: Option<&ast::Expr>,
|
||||
expr_span: codemap::Span,
|
||||
expr_id: ast::NodeId,
|
||||
ty: Ty<'tcx>,
|
||||
dest: Dest) -> Block<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("trans_rec");
|
||||
|
||||
let ty = node_id_type(bcx, expr_id);
|
||||
let tcx = bcx.tcx();
|
||||
with_field_tys(tcx, ty, Some(expr_id), |discr, field_tys| {
|
||||
let mut need_base = Vec::from_elem(field_tys.len(), true);
|
||||
|
@ -4251,7 +4251,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
check_expr(fcx, e);
|
||||
let e_t = fcx.expr_ty(e);
|
||||
if ty::type_is_error(e_t) {
|
||||
fcx.write_ty(id, e_t);
|
||||
fcx.write_ty(e.id, e_t);
|
||||
some_err = true;
|
||||
}
|
||||
};
|
||||
@ -4291,6 +4291,62 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprRange(ref start, ref end) => {
|
||||
check_expr(fcx, &**start);
|
||||
let t_start = fcx.expr_ty(&**start);
|
||||
|
||||
let idx_type = if let &Some(ref e) = end {
|
||||
check_expr(fcx, &**e);
|
||||
let t_end = fcx.expr_ty(&**e);
|
||||
if ty::type_is_error(t_end) {
|
||||
ty::mk_err()
|
||||
} else if t_start == ty::mk_err() {
|
||||
ty::mk_err()
|
||||
} else {
|
||||
infer::common_supertype(fcx.infcx(),
|
||||
infer::RangeExpression(expr.span),
|
||||
true,
|
||||
t_start,
|
||||
t_end)
|
||||
}
|
||||
} else {
|
||||
t_start
|
||||
};
|
||||
|
||||
// Note that we don't check the type of start/end satisfy any
|
||||
// bounds because right the range structs do not have any. If we add
|
||||
// some bounds, then we'll need to check `t_start` against them here.
|
||||
|
||||
let range_type = if idx_type == ty::mk_err() {
|
||||
ty::mk_err()
|
||||
} else {
|
||||
// Find the did from the appropriate lang item.
|
||||
let did = if end.is_some() {
|
||||
// Range
|
||||
tcx.lang_items.range_struct()
|
||||
} else {
|
||||
// RangeFrom
|
||||
tcx.lang_items.range_from_struct()
|
||||
};
|
||||
|
||||
if let Some(did) = did {
|
||||
let polytype = ty::lookup_item_type(tcx, did);
|
||||
let substs = Substs::new_type(vec![idx_type], vec![]);
|
||||
let bounds = polytype.generics.to_bounds(tcx, &substs);
|
||||
fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(expr.span,
|
||||
fcx.body_id,
|
||||
traits::ItemObligation(did)),
|
||||
&bounds);
|
||||
|
||||
ty::mk_struct(tcx, did, substs)
|
||||
} else {
|
||||
ty::mk_err()
|
||||
}
|
||||
};
|
||||
fcx.write_ty(id, range_type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
debug!("type of expr({}) {} is...", expr.id,
|
||||
|
@ -724,6 +724,7 @@ pub enum Expr_ {
|
||||
ExprTupField(P<Expr>, Spanned<uint>),
|
||||
ExprIndex(P<Expr>, P<Expr>),
|
||||
ExprSlice(P<Expr>, Option<P<Expr>>, Option<P<Expr>>, Mutability),
|
||||
ExprRange(P<Expr>, Option<P<Expr>>),
|
||||
|
||||
/// Variable reference, possibly containing `::` and/or
|
||||
/// type parameters, e.g. foo::bar::<baz>
|
||||
|
@ -1390,6 +1390,10 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
||||
e2.map(|x| folder.fold_expr(x)),
|
||||
m)
|
||||
}
|
||||
ExprRange(e1, e2) => {
|
||||
ExprRange(folder.fold_expr(e1),
|
||||
e2.map(|x| folder.fold_expr(x)))
|
||||
}
|
||||
ExprPath(pth) => ExprPath(folder.fold_path(pth)),
|
||||
ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))),
|
||||
ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))),
|
||||
|
@ -26,7 +26,7 @@ use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
||||
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
|
||||
use ast::{ExprBreak, ExprCall, ExprCast};
|
||||
use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex, ExprSlice};
|
||||
use ast::{ExprLit, ExprLoop, ExprMac};
|
||||
use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
|
||||
use ast::{ExprMethodCall, ExprParen, ExprPath};
|
||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
|
||||
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
|
||||
@ -95,7 +95,8 @@ bitflags! {
|
||||
const UNRESTRICTED = 0b0000,
|
||||
const RESTRICTION_STMT_EXPR = 0b0001,
|
||||
const RESTRICTION_NO_BAR_OP = 0b0010,
|
||||
const RESTRICTION_NO_STRUCT_LITERAL = 0b0100
|
||||
const RESTRICTION_NO_STRUCT_LITERAL = 0b0100,
|
||||
const RESTRICTION_NO_DOTS = 0b1000,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1547,7 +1548,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
// Parse the `; e` in `[ int; e ]`
|
||||
// where `e` is a const expression
|
||||
let t = match self.maybe_parse_fixed_vstore() {
|
||||
let t = match self.maybe_parse_fixed_length_of_vec() {
|
||||
None => TyVec(t),
|
||||
Some(suffix) => TyFixedLengthVec(t, suffix)
|
||||
};
|
||||
@ -1707,12 +1708,12 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_parse_fixed_vstore(&mut self) -> Option<P<ast::Expr>> {
|
||||
pub fn maybe_parse_fixed_length_of_vec(&mut self) -> Option<P<ast::Expr>> {
|
||||
if self.check(&token::Comma) &&
|
||||
self.look_ahead(1, |t| *t == token::DotDot) {
|
||||
self.bump();
|
||||
self.bump();
|
||||
Some(self.parse_expr())
|
||||
Some(self.parse_expr_res(RESTRICTION_NO_DOTS))
|
||||
} else if self.check(&token::Semi) {
|
||||
self.bump();
|
||||
Some(self.parse_expr())
|
||||
@ -2130,7 +2131,8 @@ impl<'a> Parser<'a> {
|
||||
ExprIndex(expr, idx)
|
||||
}
|
||||
|
||||
pub fn mk_slice(&mut self, expr: P<Expr>,
|
||||
pub fn mk_slice(&mut self,
|
||||
expr: P<Expr>,
|
||||
start: Option<P<Expr>>,
|
||||
end: Option<P<Expr>>,
|
||||
mutbl: Mutability)
|
||||
@ -2138,6 +2140,13 @@ impl<'a> Parser<'a> {
|
||||
ExprSlice(expr, start, end, mutbl)
|
||||
}
|
||||
|
||||
pub fn mk_range(&mut self,
|
||||
start: P<Expr>,
|
||||
end: Option<P<Expr>>)
|
||||
-> ast::Expr_ {
|
||||
ExprRange(start, end)
|
||||
}
|
||||
|
||||
pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::Expr_ {
|
||||
ExprField(expr, ident)
|
||||
}
|
||||
@ -2615,7 +2624,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
// e[e] | e[e..] | e[e..e]
|
||||
_ => {
|
||||
let ix = self.parse_expr();
|
||||
let ix = self.parse_expr_res(RESTRICTION_NO_DOTS);
|
||||
match self.token {
|
||||
// e[e..] | e[e..e]
|
||||
token::DotDot => {
|
||||
@ -2628,7 +2637,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
// e[e..e]
|
||||
_ => {
|
||||
let e2 = self.parse_expr();
|
||||
let e2 = self.parse_expr_res(RESTRICTION_NO_DOTS);
|
||||
self.commit_expr_expecting(&*e2,
|
||||
token::CloseDelim(token::Bracket));
|
||||
Some(e2)
|
||||
@ -2654,6 +2663,21 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// A range expression, either `expr..expr` or `expr..`.
|
||||
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
|
||||
self.bump();
|
||||
|
||||
let opt_end = if self.token.can_begin_expr() {
|
||||
let end = self.parse_expr_res(RESTRICTION_NO_DOTS);
|
||||
Some(end)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let hi = self.span.hi;
|
||||
let range = self.mk_range(e, opt_end);
|
||||
return self.mk_expr(lo, hi, range);
|
||||
}
|
||||
_ => return e
|
||||
}
|
||||
}
|
||||
|
@ -1759,6 +1759,13 @@ impl<'a> State<'a> {
|
||||
}
|
||||
try!(word(&mut self.s, "]"));
|
||||
}
|
||||
ast::ExprRange(ref start, ref end) => {
|
||||
try!(self.print_expr(&**start));
|
||||
try!(word(&mut self.s, ".."));
|
||||
if let &Some(ref e) = end {
|
||||
try!(self.print_expr(&**e));
|
||||
}
|
||||
}
|
||||
ast::ExprPath(ref path) => try!(self.print_path(path, true)),
|
||||
ast::ExprBreak(opt_ident) => {
|
||||
try!(word(&mut self.s, "break"));
|
||||
|
@ -871,6 +871,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
walk_expr_opt(visitor, start);
|
||||
walk_expr_opt(visitor, end)
|
||||
}
|
||||
ExprRange(ref start, ref end) => {
|
||||
visitor.visit_expr(&**start);
|
||||
walk_expr_opt(visitor, end)
|
||||
}
|
||||
ExprPath(ref path) => {
|
||||
visitor.visit_path(path, expression.id)
|
||||
}
|
||||
|
26
src/test/compile-fail/range-1.rs
Normal file
26
src/test/compile-fail/range-1.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 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.
|
||||
|
||||
// Test range syntax - type errors.
|
||||
|
||||
pub fn main() {
|
||||
// Mixed types.
|
||||
let _ = 0u..10i;
|
||||
//~^ ERROR start and end of range have incompatible types
|
||||
|
||||
// Float => does not implement iterator.
|
||||
for i in 0f32..42f32 {}
|
||||
//~^ ERROR `for` loop expression has type `core::ops::Range<f32>` which does not implement
|
||||
|
||||
// Unsized type.
|
||||
let arr: &[_] = &[1u, 2, 3];
|
||||
let range = (*arr)..;
|
||||
//~^ ERROR the trait `core::kinds::Sized` is not implemented
|
||||
}
|
19
src/test/compile-fail/range-2.rs
Normal file
19
src/test/compile-fail/range-2.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 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.
|
||||
|
||||
// Test range syntax - borrow errors.
|
||||
|
||||
pub fn main() {
|
||||
let r = {
|
||||
(&42i)..&42
|
||||
//~^ ERROR borrowed value does not live long enough
|
||||
//~^^ ERROR borrowed value does not live long enough
|
||||
};
|
||||
}
|
48
src/test/run-pass/range.rs
Normal file
48
src/test/run-pass/range.rs
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 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.
|
||||
|
||||
// Test range syntax.
|
||||
|
||||
fn foo() -> int { 42 }
|
||||
|
||||
pub fn main() {
|
||||
let mut count = 0;
|
||||
for i in 0u..10 {
|
||||
assert!(i >= 0 && i < 10);
|
||||
count += i;
|
||||
}
|
||||
assert!(count == 45);
|
||||
|
||||
let mut count = 0;
|
||||
let mut range = 0u..10;
|
||||
for i in range {
|
||||
assert!(i >= 0 && i < 10);
|
||||
count += i;
|
||||
}
|
||||
assert!(count == 45);
|
||||
|
||||
let mut count = 0;
|
||||
let mut rf = 3u..;
|
||||
for i in rf.take(10) {
|
||||
assert!(i >= 3 && i < 13);
|
||||
count += i;
|
||||
}
|
||||
assert!(count == 75);
|
||||
|
||||
let _ = 0u..4+4-3;
|
||||
let _ = 0..foo();
|
||||
|
||||
// Test we can use two different types with a common supertype.
|
||||
let x = &42i;
|
||||
{
|
||||
let y = 42i;
|
||||
let _ = x..&y;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user