Skip to content

Commit b9035c2

Browse files
committed
auto merge of #15809 : pcwalton/rust/dedesugar-for, r=pnkfelix
librustc: Stop desugaring `for` expressions and translate them directly. This makes edge cases in which the `Iterator` trait was not in scope and/or `Option` or its variants were not in scope work properly. This breaks code that looks like: struct MyStruct { ... } impl MyStruct { fn next(&mut self) -> Option<int> { ... } } for x in MyStruct { ... } { ... } Change ad-hoc `next` methods like the above to implementations of the `Iterator` trait. For example: impl Iterator<int> for MyStruct { fn next(&mut self) -> Option<int> { ... } } Closes #15392. [breaking-change]
2 parents a455345 + caa564b commit b9035c2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+614
-163
lines changed

src/libcore/char.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717

1818
use mem::transmute;
1919
use option::{None, Option, Some};
20-
use iter::{Iterator, range_step};
20+
use iter::range_step;
21+
22+
#[cfg(stage0)]
23+
use iter::Iterator; // NOTE(stage0): Remove after snapshot.
2124

2225
// UTF-8 ranges and tags for encoding characters
2326
static TAG_CONT: u8 = 0b1000_0000u8;

src/libcore/fmt/float.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@
1313
use char;
1414
use collections::Collection;
1515
use fmt;
16-
use iter::{Iterator, range, DoubleEndedIterator};
16+
use iter::{range, DoubleEndedIterator};
1717
use num::{Float, FPNaN, FPInfinite, ToPrimitive, Primitive};
1818
use num::{Zero, One, cast};
19-
use option::{None, Some};
2019
use result::Ok;
2120
use slice::{ImmutableVector, MutableVector};
2221
use slice;
2322
use str::StrSlice;
2423

24+
#[cfg(stage0)]
25+
use iter::Iterator; // NOTE(stage0): Remove after snapshot.
26+
#[cfg(stage0)]
27+
use option::{Some, None}; // NOTE(stage0): Remove after snapshot.
28+
2529
/// A flag that specifies whether to use exponential (scientific) notation.
2630
pub enum ExponentFormat {
2731
/// Do not use exponential notation.

src/libcore/fmt/num.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616

1717
use collections::Collection;
1818
use fmt;
19-
use iter::{Iterator, DoubleEndedIterator};
19+
use iter::DoubleEndedIterator;
2020
use num::{Int, cast, zero};
21-
use option::{Some, None};
2221
use slice::{ImmutableVector, MutableVector};
2322

23+
#[cfg(stage0)]
24+
use iter::Iterator; // NOTE(stage0): Remove after snapshot.
25+
#[cfg(stage0)]
26+
use option::{Some, None}; // NOTE(stage0): Remove after snapshot.
27+
2428
/// A type that represents a specific radix
2529
trait GenericRadix {
2630
/// The number of digits.

src/libcore/iter.rs

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub trait Extendable<A>: FromIterator<A> {
9595
/// is returned. A concrete Iterator implementation may choose to behave however
9696
/// it wishes, either by returning `None` infinitely, or by doing something
9797
/// else.
98+
#[lang="iterator"]
9899
pub trait Iterator<A> {
99100
/// Advance the iterator and return the next value. Return `None` when the end is reached.
100101
fn next(&mut self) -> Option<A>;

src/libcore/option.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,12 @@ use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSize};
147147
use mem;
148148
use slice;
149149

150-
/// The `Option`
150+
// Note that this is not a lang item per se, but it has a hidden dependency on
151+
// `Iterator`, which is one. The compiler assumes that the `next` method of
152+
// `Iterator` is an enumeration with one type parameter and two variants,
153+
// which basically means it must be `Option`.
154+
155+
/// The `Option` type.
151156
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show)]
152157
pub enum Option<T> {
153158
/// No value

src/libcore/ptr.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,14 @@
9090
use mem;
9191
use clone::Clone;
9292
use intrinsics;
93-
use iter::{range, Iterator};
93+
use iter::range;
9494
use option::{Some, None, Option};
9595

9696
use cmp::{PartialEq, Eq, PartialOrd, Equiv, Ordering, Less, Equal, Greater};
9797

98+
#[cfg(stage0)]
99+
use iter::Iterator; // NOTE(stage0): Remove after snapshot.
100+
98101
pub use intrinsics::copy_memory;
99102
pub use intrinsics::copy_nonoverlapping_memory;
100103
pub use intrinsics::set_memory;

src/libcore/str.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use iter::{Map, Iterator};
2828
use iter::{DoubleEndedIterator, ExactSize};
2929
use iter::range;
3030
use num::{CheckedMul, Saturating};
31-
use option::{None, Option, Some};
31+
use option::{Option, None, Some};
3232
use raw::Repr;
3333
use slice::ImmutableVector;
3434
use slice;
@@ -1027,9 +1027,12 @@ pub mod traits {
10271027
use cmp::{Ord, Ordering, Less, Equal, Greater, PartialEq, PartialOrd, Equiv, Eq};
10281028
use collections::Collection;
10291029
use iter::Iterator;
1030-
use option::{Option, Some, None};
1030+
use option::{Option, Some};
10311031
use str::{Str, StrSlice, eq_slice};
10321032

1033+
#[cfg(stage0)]
1034+
use option::None; // NOTE(stage0): Remove after snapshot.
1035+
10331036
impl<'a> Ord for &'a str {
10341037
#[inline]
10351038
fn cmp(&self, other: & &'a str) -> Ordering {

src/libcoretest/iter.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ fn test_iterator_take_while() {
137137
let ys = [0u, 1, 2, 3, 5, 13];
138138
let mut it = xs.iter().take_while(|&x| *x < 15u);
139139
let mut i = 0;
140-
for &x in it {
141-
assert_eq!(x, ys[i]);
140+
for x in it {
141+
assert_eq!(*x, ys[i]);
142142
i += 1;
143143
}
144144
assert_eq!(i, ys.len());
@@ -150,8 +150,8 @@ fn test_iterator_skip_while() {
150150
let ys = [15, 16, 17, 19];
151151
let mut it = xs.iter().skip_while(|&x| *x < 15u);
152152
let mut i = 0;
153-
for &x in it {
154-
assert_eq!(x, ys[i]);
153+
for x in it {
154+
assert_eq!(*x, ys[i]);
155155
i += 1;
156156
}
157157
assert_eq!(i, ys.len());

src/librustc/middle/borrowck/check_loans.rs

+6
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ impl<'a> CheckLoanCtxt<'a> {
440440
euv::AddrOf(..) |
441441
euv::AutoRef(..) |
442442
euv::ClosureInvocation(..) |
443+
euv::ForLoop(..) |
443444
euv::RefBinding(..) => {
444445
format!("previous borrow of `{}` occurs here",
445446
self.bccx.loan_path_to_string(&*old_loan.loan_path))
@@ -668,6 +669,11 @@ impl<'a> CheckLoanCtxt<'a> {
668669
return;
669670
}
670671

672+
// Initializations are OK.
673+
if mode == euv::Init {
674+
return
675+
}
676+
671677
// For immutable local variables, assignments are legal
672678
// if they cannot already have been assigned
673679
if self.is_local_variable_or_arg(assignee_cmt.clone()) {

src/librustc/middle/borrowck/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,8 @@ impl<'a> BorrowckCtxt<'a> {
651651
euv::OverloadedOperator |
652652
euv::AddrOf |
653653
euv::RefBinding |
654-
euv::AutoRef => {
654+
euv::AutoRef |
655+
euv::ForLoop => {
655656
format!("cannot borrow {} as mutable", descr)
656657
}
657658
euv::ClosureInvocation => {
@@ -712,6 +713,10 @@ impl<'a> BorrowckCtxt<'a> {
712713
BorrowViolation(euv::ClosureInvocation) => {
713714
"closure invocation"
714715
}
716+
717+
BorrowViolation(euv::ForLoop) => {
718+
"`for` loop"
719+
}
715720
};
716721

717722
match cause {

src/librustc/middle/cfg/construct.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ impl<'a> CFGBuilder<'a> {
240240
// v 3
241241
// [expr]
242242
//
243-
// Note that `break` and `loop` statements
243+
// Note that `break` and `continue` statements
244244
// may cause additional edges.
245245

246246
// Is the condition considered part of the loop?
@@ -258,7 +258,44 @@ impl<'a> CFGBuilder<'a> {
258258
expr_exit
259259
}
260260

261-
ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
261+
ast::ExprForLoop(ref pat, ref head, ref body, _) => {
262+
//
263+
// [pred]
264+
// |
265+
// v 1
266+
// [head]
267+
// |
268+
// v 2
269+
// [loopback] <--+ 7
270+
// | |
271+
// v 3 |
272+
// +------[cond] |
273+
// | | |
274+
// | v 5 |
275+
// | [pat] |
276+
// | | |
277+
// | v 6 |
278+
// v 4 [body] -----+
279+
// [expr]
280+
//
281+
// Note that `break` and `continue` statements
282+
// may cause additional edges.
283+
284+
let head = self.expr(head.clone(), pred); // 1
285+
let loopback = self.add_dummy_node([head]); // 2
286+
let cond = self.add_dummy_node([loopback]); // 3
287+
let expr_exit = self.add_node(expr.id, [cond]); // 4
288+
self.loop_scopes.push(LoopScope {
289+
loop_id: expr.id,
290+
continue_index: loopback,
291+
break_index: expr_exit,
292+
});
293+
let pat = self.pat(&**pat, cond); // 5
294+
let body = self.block(&**body, pat); // 6
295+
self.add_contained_edge(body, loopback); // 7
296+
self.loop_scopes.pop();
297+
expr_exit
298+
}
262299

263300
ast::ExprLoop(ref body, _) => {
264301
//

src/librustc/middle/check_loop.rs

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ impl<'a> Visitor<Context> for CheckLoopVisitor<'a> {
4242
ast::ExprLoop(ref b, _) => {
4343
self.visit_block(&**b, Loop);
4444
}
45+
ast::ExprForLoop(_, ref e, ref b, _) => {
46+
self.visit_expr(&**e, cx);
47+
self.visit_block(&**b, Loop);
48+
}
4549
ast::ExprFnBlock(_, ref b) |
4650
ast::ExprProc(_, ref b) |
4751
ast::ExprUnboxedFn(_, ref b) => {

src/librustc/middle/check_match.rs

+18
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,24 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
170170
.collect();
171171
check_exhaustive(cx, ex.span, &matrix);
172172
},
173+
ExprForLoop(ref pat, _, _, _) => {
174+
let mut static_inliner = StaticInliner {
175+
tcx: cx.tcx
176+
};
177+
match is_refutable(cx, static_inliner.fold_pat(*pat)) {
178+
Some(uncovered_pat) => {
179+
cx.tcx.sess.span_err(
180+
pat.span,
181+
format!("refutable pattern in `for` loop binding: \
182+
`{}` not covered",
183+
pat_to_string(&*uncovered_pat)).as_slice());
184+
},
185+
None => {}
186+
}
187+
188+
// Check legality of move bindings.
189+
check_legality_of_move_bindings(cx, false, [ *pat ]);
190+
}
173191
_ => ()
174192
}
175193
}

src/librustc/middle/dead.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -354,11 +354,11 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
354354
// depending on whether a crate is built as bin or lib, and we want
355355
// the warning to be consistent, we also seed the worklist with
356356
// exported symbols.
357-
for &id in exported_items.iter() {
358-
worklist.push(id);
357+
for id in exported_items.iter() {
358+
worklist.push(*id);
359359
}
360-
for &id in reachable_symbols.iter() {
361-
worklist.push(id);
360+
for id in reachable_symbols.iter() {
361+
worklist.push(*id);
362362
}
363363

364364
// Seed entry point

src/librustc/middle/expr_use_visitor.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ pub enum LoanCause {
7979
AutoRef,
8080
RefBinding,
8181
OverloadedOperator,
82-
ClosureInvocation
82+
ClosureInvocation,
83+
ForLoop,
8384
}
8485

8586
#[deriving(PartialEq,Show)]
@@ -395,7 +396,16 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
395396
self.walk_block(&**blk);
396397
}
397398

398-
ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
399+
ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
400+
// The pattern lives as long as the block.
401+
debug!("walk_expr for loop case: blk id={}", blk.id);
402+
self.walk_expr(&**head);
403+
404+
let head_cmt = return_if_err!(self.mc.cat_expr(&**head));
405+
self.walk_pat(head_cmt, pat.clone());
406+
407+
self.walk_block(&**blk);
408+
}
399409

400410
ast::ExprUnary(_, ref lhs) => {
401411
if !self.walk_overloaded_operator(expr, &**lhs, []) {

src/librustc/middle/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -299,5 +299,7 @@ lets_do_this! {
299299
NoShareItem, "no_share_bound", no_share_bound;
300300
ManagedItem, "managed_bound", managed_bound;
301301

302+
IteratorItem, "iterator", iterator;
303+
302304
StackExhaustedLangItem, "stack_exhausted", stack_exhausted;
303305
}

0 commit comments

Comments
 (0)