Skip to content

Commit ed8f503

Browse files
committed
Add hypothetical support for ranges with only an upper bound
Note that this doesn't add the surface syntax.
1 parent 7112390 commit ed8f503

File tree

14 files changed

+81
-40
lines changed

14 files changed

+81
-40
lines changed

src/libcore/ops.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,14 @@ impl<Idx: Clone + Step> Iterator<Idx> for RangeFrom<Idx> {
908908
}
909909
}
910910

911+
/// A range which is only bounded above.
912+
#[deriving(Copy)]
913+
#[lang="range_to"]
914+
pub struct RangeTo<Idx> {
915+
/// The upper bound of the range (exclusive).
916+
pub end: Idx,
917+
}
918+
911919

912920
/// The `Deref` trait is used to specify the functionality of dereferencing
913921
/// operations like `*v`.

src/libcoretest/ops.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ fn test_range_from() {
5555
assert!(count == 10);
5656
}
5757

58+
#[test]
59+
fn test_range_to() {
60+
// Not much to test.
61+
let _ = RangeTo { end: 42u };
62+
}
63+
5864
#[test]
5965
fn test_full_range() {
6066
// Not much to test.

src/librustc/middle/cfg/construct.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
440440
}
441441

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

src/librustc/middle/expr_use_visitor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
450450
}
451451

452452
ast::ExprRange(ref start, ref end) => {
453-
self.consume_expr(&**start);
453+
start.as_ref().map(|e| self.consume_expr(&**e));
454454
end.as_ref().map(|e| self.consume_expr(&**e));
455455
}
456456

src/librustc/middle/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ lets_do_this! {
269269
SliceMutTraitLangItem, "slice_mut", slice_mut_trait;
270270
RangeStructLangItem, "range", range_struct;
271271
RangeFromStructLangItem, "range_from", range_from_struct;
272+
RangeToStructLangItem, "range_to", range_to_struct;
272273
FullRangeStructLangItem, "full_range", full_range_struct;
273274

274275
UnsafeTypeLangItem, "unsafe", unsafe_type;

src/librustc/middle/liveness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
11991199

12001200
ast::ExprRange(ref e1, ref e2) => {
12011201
let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ));
1202-
self.propagate_through_expr(&**e1, succ)
1202+
e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ))
12031203
}
12041204

12051205
ast::ExprBox(None, ref e) |

src/librustc_trans/trans/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3546,7 +3546,7 @@ fn create_scope_map(cx: &CrateContext,
35463546
}
35473547

35483548
ast::ExprRange(ref start, ref end) => {
3549-
walk_expr(cx, &**start, scope_stack, scope_map);
3549+
start.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
35503550
end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
35513551
}
35523552

src/librustc_trans/trans/expr.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,22 +1064,34 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
10641064
}
10651065

10661066
// A range just desugars into a struct.
1067-
let (did, fields) = match end {
1068-
&Some(ref end) => {
1067+
// Note that the type of the start and end may not be the same, but
1068+
// they should only differ in their lifetime, which should not matter
1069+
// in trans.
1070+
let (did, fields, ty_params) = match (start, end) {
1071+
(&Some(ref start), &Some(ref end)) => {
10691072
// Desugar to Range
10701073
let fields = vec!(make_field("start", start.clone()),
10711074
make_field("end", end.clone()));
1072-
(tcx.lang_items.range_struct(), fields)
1075+
(tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)])
10731076
}
1074-
&None => {
1077+
(&Some(ref start), &None) => {
10751078
// Desugar to RangeFrom
10761079
let fields = vec!(make_field("start", start.clone()));
1077-
(tcx.lang_items.range_from_struct(), fields)
1080+
(tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)])
1081+
}
1082+
(&None, &Some(ref end)) => {
1083+
// Desugar to RangeTo
1084+
let fields = vec!(make_field("end", end.clone()));
1085+
(tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)])
1086+
}
1087+
_ => {
1088+
// Desugar to FullRange
1089+
(tcx.lang_items.full_range_struct(), vec![], vec![])
10781090
}
10791091
};
10801092

10811093
if let Some(did) = did {
1082-
let substs = Substs::new_type(vec![node_id_type(bcx, start.id)], vec![]);
1094+
let substs = Substs::new_type(ty_params, vec![]);
10831095
trans_struct(bcx,
10841096
fields.as_slice(),
10851097
None,

src/librustc_typeck/check/mod.rs

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4308,46 +4308,58 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
43084308
}
43094309
}
43104310
ast::ExprRange(ref start, ref end) => {
4311-
check_expr(fcx, &**start);
4312-
let t_start = fcx.expr_ty(&**start);
4313-
4314-
let idx_type = if let &Some(ref e) = end {
4311+
let t_start = start.as_ref().map(|e| {
43154312
check_expr(fcx, &**e);
4316-
let t_end = fcx.expr_ty(&**e);
4317-
if ty::type_is_error(t_end) {
4318-
ty::mk_err()
4319-
} else if t_start == ty::mk_err() {
4320-
ty::mk_err()
4321-
} else {
4322-
infer::common_supertype(fcx.infcx(),
4323-
infer::RangeExpression(expr.span),
4324-
true,
4325-
t_start,
4326-
t_end)
4313+
fcx.expr_ty(&**e)
4314+
});
4315+
let t_end = end.as_ref().map(|e| {
4316+
check_expr(fcx, &**e);
4317+
fcx.expr_ty(&**e)
4318+
});
4319+
4320+
let idx_type = match (t_start, t_end) {
4321+
(Some(ty), None) | (None, Some(ty)) => Some(ty),
4322+
(Some(t_start), Some(t_end)) if t_start == ty::mk_err() || t_end == ty::mk_err() => {
4323+
Some(ty::mk_err())
43274324
}
4328-
} else {
4329-
t_start
4325+
(Some(t_start), Some(t_end)) => {
4326+
Some(infer::common_supertype(fcx.infcx(),
4327+
infer::RangeExpression(expr.span),
4328+
true,
4329+
t_start,
4330+
t_end))
4331+
}
4332+
_ => None
43304333
};
43314334

43324335
// Note that we don't check the type of start/end satisfy any
43334336
// bounds because right the range structs do not have any. If we add
43344337
// some bounds, then we'll need to check `t_start` against them here.
43354338

4336-
let range_type = if idx_type == ty::mk_err() {
4339+
let range_type = if idx_type == Some(ty::mk_err()) {
43374340
ty::mk_err()
4341+
} else if idx_type.is_none() {
4342+
// Neither start nor end => FullRange
4343+
if let Some(did) = tcx.lang_items.full_range_struct() {
4344+
let substs = Substs::new_type(vec![], vec![]);
4345+
ty::mk_struct(tcx, did, substs)
4346+
} else {
4347+
ty::mk_err()
4348+
}
43384349
} else {
43394350
// Find the did from the appropriate lang item.
4340-
let did = if end.is_some() {
4341-
// Range
4342-
tcx.lang_items.range_struct()
4343-
} else {
4344-
// RangeFrom
4345-
tcx.lang_items.range_from_struct()
4351+
let did = match (start, end) {
4352+
(&Some(_), &Some(_)) => tcx.lang_items.range_struct(),
4353+
(&Some(_), &None) => tcx.lang_items.range_from_struct(),
4354+
(&None, &Some(_)) => tcx.lang_items.range_to_struct(),
4355+
(&None, &None) => {
4356+
tcx.sess.span_bug(expr.span,"full range should be dealt with above")
4357+
}
43464358
};
43474359

43484360
if let Some(did) = did {
43494361
let polytype = ty::lookup_item_type(tcx, did);
4350-
let substs = Substs::new_type(vec![idx_type], vec![]);
4362+
let substs = Substs::new_type(vec![idx_type.unwrap()], vec![]);
43514363
let bounds = polytype.generics.to_bounds(tcx, &substs);
43524364
fcx.add_obligations_for_parameters(
43534365
traits::ObligationCause::new(expr.span,

src/libsyntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ pub enum Expr_ {
724724
ExprTupField(P<Expr>, Spanned<uint>),
725725
ExprIndex(P<Expr>, P<Expr>),
726726
ExprSlice(P<Expr>, Option<P<Expr>>, Option<P<Expr>>, Mutability),
727-
ExprRange(P<Expr>, Option<P<Expr>>),
727+
ExprRange(Option<P<Expr>>, Option<P<Expr>>),
728728

729729
/// Variable reference, possibly containing `::` and/or
730730
/// type parameters, e.g. foo::bar::<baz>

src/libsyntax/fold.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1391,7 +1391,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
13911391
m)
13921392
}
13931393
ExprRange(e1, e2) => {
1394-
ExprRange(folder.fold_expr(e1),
1394+
ExprRange(e1.map(|x| folder.fold_expr(x)),
13951395
e2.map(|x| folder.fold_expr(x)))
13961396
}
13971397
ExprPath(pth) => ExprPath(folder.fold_path(pth)),

src/libsyntax/parse/parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2144,7 +2144,7 @@ impl<'a> Parser<'a> {
21442144
start: P<Expr>,
21452145
end: Option<P<Expr>>)
21462146
-> ast::Expr_ {
2147-
ExprRange(start, end)
2147+
ExprRange(Some(start), end)
21482148
}
21492149

21502150
pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::Expr_ {

src/libsyntax/print/pprust.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1760,7 +1760,9 @@ impl<'a> State<'a> {
17601760
try!(word(&mut self.s, "]"));
17611761
}
17621762
ast::ExprRange(ref start, ref end) => {
1763-
try!(self.print_expr(&**start));
1763+
if let &Some(ref e) = start {
1764+
try!(self.print_expr(&**e));
1765+
}
17641766
try!(word(&mut self.s, ".."));
17651767
if let &Some(ref e) = end {
17661768
try!(self.print_expr(&**e));

src/libsyntax/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
872872
walk_expr_opt(visitor, end)
873873
}
874874
ExprRange(ref start, ref end) => {
875-
visitor.visit_expr(&**start);
875+
walk_expr_opt(visitor, start);
876876
walk_expr_opt(visitor, end)
877877
}
878878
ExprPath(ref path) => {

0 commit comments

Comments
 (0)