Add hypothetical support for ranges with only an upper bound
Note that this doesn't add the surface syntax.
This commit is contained in:
parent
71123902e1
commit
ed8f503911
14 changed files with 81 additions and 40 deletions
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@ fn test_range_from() {
|
|||
assert!(count == 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_to() {
|
||||
// Not much to test.
|
||||
let _ = RangeTo { end: 42u };
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_full_range() {
|
||||
// Not much to test.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) |
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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_ {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue