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:
bors 2014-12-24 06:31:13 +00:00
commit e64a8193b0
24 changed files with 452 additions and 15 deletions

View File

@ -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]

View File

@ -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;

View File

@ -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`.
///

View File

@ -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;
}

View File

@ -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())
}

View File

@ -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);

View File

@ -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")
}

View File

@ -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))
}

View File

@ -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;

View File

@ -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(..) => {

View File

@ -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(..) |

View File

@ -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(..) |

View File

@ -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)),

View File

@ -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() {

View File

@ -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);

View File

@ -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,

View File

@ -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>

View File

@ -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))),

View File

@ -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
}
}

View File

@ -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"));

View File

@ -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)
}

View 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
}

View 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
};
}

View 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;
}
}