about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2014-12-18 17:55:04 +1300
committerNick Cameron <ncameron@mozilla.com>2014-12-30 13:06:24 +1300
commited8f5039115308ca9d5591126e4d8a77864d4730 (patch)
treefef6c67dd64068ff73c4509d078d25ba88fa4f21 /src
parent71123902e17ad339649f33423995eac78da40e3c (diff)
downloadrust-ed8f5039115308ca9d5591126e4d8a77864d4730.tar.gz
rust-ed8f5039115308ca9d5591126e4d8a77864d4730.zip
Add hypothetical support for ranges with only an upper bound
Note that this doesn't add the surface syntax.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/ops.rs8
-rw-r--r--src/libcoretest/ops.rs6
-rw-r--r--src/librustc/middle/cfg/construct.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/lang_items.rs1
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc_trans/trans/debuginfo.rs2
-rw-r--r--src/librustc_trans/trans/expr.rs24
-rw-r--r--src/librustc_typeck/check/mod.rs62
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/fold.rs2
-rw-r--r--src/libsyntax/parse/parser.rs2
-rw-r--r--src/libsyntax/print/pprust.rs4
-rw-r--r--src/libsyntax/visit.rs2
14 files changed, 81 insertions, 40 deletions
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 0cd8c1d69d1..f6b79ccc42b 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -908,6 +908,14 @@ impl<Idx: Clone + Step> Iterator<Idx> for RangeFrom<Idx> {
     }
 }
 
+/// A range which is only bounded above.
+#[deriving(Copy)]
+#[lang="range_to"]
+pub struct RangeTo<Idx> {
+    /// The upper bound of the range (exclusive).
+    pub end: Idx,
+}
+
 
 /// The `Deref` trait is used to specify the functionality of dereferencing
 /// operations like `*v`.
diff --git a/src/libcoretest/ops.rs b/src/libcoretest/ops.rs
index a8889ce9e34..3c8a6d480f7 100644
--- a/src/libcoretest/ops.rs
+++ b/src/libcoretest/ops.rs
@@ -56,6 +56,12 @@ fn test_range_from() {
 }
 
 #[test]
+fn test_range_to() {
+    // Not much to test.
+    let _ = RangeTo { end: 42u };
+}
+
+#[test]
 fn test_full_range() {
     // Not much to test.
     let _ = FullRange;
diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs
index f50790f7e9b..540f8a20dde 100644
--- a/src/librustc/middle/cfg/construct.rs
+++ b/src/librustc/middle/cfg/construct.rs
@@ -440,7 +440,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             ast::ExprRange(ref start, ref end) => {
-                let fields = Some(&**start).into_iter()
+                let fields = start.as_ref().map(|e| &**e).into_iter()
                     .chain(end.as_ref().map(|e| &**e).into_iter());
                 self.straightline(expr, pred, fields)
             }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 1dfd602794f..f564e5cfefb 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -450,7 +450,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             }
 
             ast::ExprRange(ref start, ref end) => {
-                self.consume_expr(&**start);
+                start.as_ref().map(|e| self.consume_expr(&**e));
                 end.as_ref().map(|e| self.consume_expr(&**e));
             }
 
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 90e3e2bb34a..2aef4307199 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -269,6 +269,7 @@ lets_do_this! {
     SliceMutTraitLangItem,           "slice_mut",               slice_mut_trait;
     RangeStructLangItem,             "range",                   range_struct;
     RangeFromStructLangItem,         "range_from",              range_from_struct;
+    RangeToStructLangItem,           "range_to",                range_to_struct;
     FullRangeStructLangItem,         "full_range",              full_range_struct;
 
     UnsafeTypeLangItem,              "unsafe",                  unsafe_type;
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index f59a67e2e80..cbd34c7f258 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1199,7 +1199,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           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)
+            e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ))
           }
 
           ast::ExprBox(None, ref e) |
diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs
index ea2d42bebdf..0b0a5ecb59e 100644
--- a/src/librustc_trans/trans/debuginfo.rs
+++ b/src/librustc_trans/trans/debuginfo.rs
@@ -3546,7 +3546,7 @@ fn create_scope_map(cx: &CrateContext,
             }
 
             ast::ExprRange(ref start, ref end) => {
-                walk_expr(cx, &**start, scope_stack, scope_map);
+                start.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
                 end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map));
             }
 
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 60b5a08c7c5..7c4788a29ef 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -1064,22 +1064,34 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             }
 
             // A range just desugars into a struct.
-            let (did, fields) = match end {
-                &Some(ref end) => {
+            // Note that the type of the start and end may not be the same, but
+            // they should only differ in their lifetime, which should not matter
+            // in trans.
+            let (did, fields, ty_params) = match (start, end) {
+                (&Some(ref start), &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)
+                    (tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)])
                 }
-                &None => {
+                (&Some(ref start), &None) => {
                     // Desugar to RangeFrom
                     let fields = vec!(make_field("start", start.clone()));
-                    (tcx.lang_items.range_from_struct(), fields)
+                    (tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)])
+                }
+                (&None, &Some(ref end)) => {
+                    // Desugar to RangeTo
+                    let fields = vec!(make_field("end", end.clone()));
+                    (tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)])
+                }
+                _ => {
+                    // Desugar to FullRange
+                    (tcx.lang_items.full_range_struct(), vec![], vec![])
                 }
             };
 
             if let Some(did) = did {
-                let substs = Substs::new_type(vec![node_id_type(bcx, start.id)], vec![]);
+                let substs = Substs::new_type(ty_params, vec![]);
                 trans_struct(bcx,
                              fields.as_slice(),
                              None,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 68cf139338a..b677fb1af92 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4308,46 +4308,58 @@ 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 {
+          let t_start = start.as_ref().map(|e| {
             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)
+            fcx.expr_ty(&**e)
+          });
+          let t_end = end.as_ref().map(|e| {
+            check_expr(fcx, &**e);
+            fcx.expr_ty(&**e)
+          });
+
+          let idx_type = match (t_start, t_end) {
+            (Some(ty), None) | (None, Some(ty)) => Some(ty),
+            (Some(t_start), Some(t_end)) if t_start == ty::mk_err() || t_end == ty::mk_err() => {
+                Some(ty::mk_err())
             }
-          } else {
-            t_start
+            (Some(t_start), Some(t_end)) => {
+                Some(infer::common_supertype(fcx.infcx(),
+                                             infer::RangeExpression(expr.span),
+                                             true,
+                                             t_start,
+                                             t_end))
+            }
+            _ => None
           };
 
           // 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() {
+          let range_type = if idx_type == Some(ty::mk_err()) {
             ty::mk_err()
+          } else if idx_type.is_none() {
+            // Neither start nor end => FullRange
+            if let Some(did) = tcx.lang_items.full_range_struct() {
+                let substs = Substs::new_type(vec![], vec![]);
+                ty::mk_struct(tcx, did, substs)
+            } else {
+                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()
+            let did = match (start, end) {
+                (&Some(_), &Some(_)) => tcx.lang_items.range_struct(),
+                (&Some(_), &None) => tcx.lang_items.range_from_struct(),
+                (&None, &Some(_)) => tcx.lang_items.range_to_struct(),
+                (&None, &None) => {
+                    tcx.sess.span_bug(expr.span,"full range should be dealt with above")
+                }
             };
 
             if let Some(did) = did {
                 let polytype = ty::lookup_item_type(tcx, did);
-                let substs = Substs::new_type(vec![idx_type], vec![]);
+                let substs = Substs::new_type(vec![idx_type.unwrap()], vec![]);
                 let bounds = polytype.generics.to_bounds(tcx, &substs);
                 fcx.add_obligations_for_parameters(
                     traits::ObligationCause::new(expr.span,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index d4932fbb5f1..e53e2cea1cc 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -724,7 +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>>),
+    ExprRange(Option<P<Expr>>, Option<P<Expr>>),
 
     /// Variable reference, possibly containing `::` and/or
     /// type parameters, e.g. foo::bar::<baz>
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index c58901701f5..ede023c4e8b 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1391,7 +1391,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                           m)
             }
             ExprRange(e1, e2) => {
-                ExprRange(folder.fold_expr(e1),
+                ExprRange(e1.map(|x| folder.fold_expr(x)),
                           e2.map(|x| folder.fold_expr(x)))
             }
             ExprPath(pth) => ExprPath(folder.fold_path(pth)),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a2e2abab03e..ec1e966926a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2144,7 +2144,7 @@ impl<'a> Parser<'a> {
                     start: P<Expr>,
                     end: Option<P<Expr>>)
                     -> ast::Expr_ {
-        ExprRange(start, end)
+        ExprRange(Some(start), end)
     }
 
     pub fn mk_field(&mut self, expr: P<Expr>, ident: ast::SpannedIdent) -> ast::Expr_ {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 623f20bccd2..a4b349c5f23 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1760,7 +1760,9 @@ impl<'a> State<'a> {
                 try!(word(&mut self.s, "]"));
             }
             ast::ExprRange(ref start, ref end) => {
-                try!(self.print_expr(&**start));
+                if let &Some(ref e) = start {
+                    try!(self.print_expr(&**e));
+                }
                 try!(word(&mut self.s, ".."));
                 if let &Some(ref e) = end {
                     try!(self.print_expr(&**e));
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 714339d0f0a..cde9ba932be 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -872,7 +872,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             walk_expr_opt(visitor, end)
         }
         ExprRange(ref start, ref end) => {
-            visitor.visit_expr(&**start);
+            walk_expr_opt(visitor, start);
             walk_expr_opt(visitor, end)
         }
         ExprPath(ref path) => {