From dbb655a1e3a6e0b5525b8ef8109a0546d874f707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 13 Jun 2017 18:36:01 +0200 Subject: [PATCH] Change the for-loop desugar so the `break` does not affect type inference. Fixes #42618 --- src/libcore/iter/mod.rs | 6 ++++-- src/librustc/hir/lowering.rs | 37 ++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index ee811513487..c91fd16391a 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -191,10 +191,12 @@ //! { //! let result = match IntoIterator::into_iter(values) { //! mut iter => loop { -//! let x = match iter.next() { -//! Some(val) => val, +//! let next; +//! match iter.next() { +//! Some(val) => next = val, //! None => break, //! }; +//! let x = next; //! let () = { println!("{}", x); }; //! }, //! }; diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a6ab67e0469..1283d136d32 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2170,11 +2170,13 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { // let result = match ::std::iter::IntoIterator::into_iter() { // mut iter => { // [opt_ident]: loop { - // let = match ::std::iter::Iterator::next(&mut iter) { - // ::std::option::Option::Some(val) => val, + // let next; + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some(val) => next = val, // ::std::option::Option::None => break // }; - // SemiExpr(); + // let = next; + // StmtExpr(); // } // } // }; @@ -2186,13 +2188,18 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { let iter = self.str_to_ident("iter"); - // `::std::option::Option::Some(val) => val` + let next_ident = self.str_to_ident("next"); + let next_pat = self.pat_ident(e.span, next_ident); + + // `::std::option::Option::Some(val) => next = val` let pat_arm = { let val_ident = self.str_to_ident("val"); let val_pat = self.pat_ident(e.span, val_ident); let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id)); + let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id)); + let assign = P(self.expr(e.span, hir::ExprAssign(next_expr, val_expr), ThinVec::new())); let some_pat = self.pat_some(e.span, val_pat); - self.arm(hir_vec![some_pat], val_expr) + self.arm(hir_vec![some_pat], assign) }; // `::std::option::Option::None => break` @@ -2222,10 +2229,20 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { hir::MatchSource::ForLoopDesugar), ThinVec::new())) }; + let match_stmt = respan(e.span, hir::StmtExpr(match_expr, self.next_id())); + let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id)); + + // `let next` + let next_let = self.stmt_let_pat(e.span, + None, + next_pat, + hir::LocalSource::ForLoopDesugar); + + // `let = next` let pat = self.lower_pat(pat); let pat_let = self.stmt_let_pat(e.span, - match_expr, + Some(next_expr), pat, hir::LocalSource::ForLoopDesugar); @@ -2234,7 +2251,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { let body_expr = P(self.expr_block(body_block, ThinVec::new())); let body_stmt = respan(e.span, hir::StmtExpr(body_expr, self.next_id())); - let loop_block = P(self.block_all(e.span, hir_vec![pat_let, body_stmt], None)); + let loop_block = P(self.block_all(e.span, hir_vec![next_let, match_stmt, pat_let, body_stmt], None)); // `[opt_ident]: loop { ... }` let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident), @@ -2601,14 +2618,14 @@ fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec) -> h fn stmt_let_pat(&mut self, sp: Span, - ex: P, + ex: Option>, pat: P, source: hir::LocalSource) -> hir::Stmt { let local = P(hir::Local { pat: pat, ty: None, - init: Some(ex), + init: ex, id: self.next_id(), span: sp, attrs: ThinVec::new(), @@ -2626,7 +2643,7 @@ fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P) self.pat_ident(sp, ident) }; let pat_id = pat.id; - (self.stmt_let_pat(sp, ex, pat, hir::LocalSource::Normal), pat_id) + (self.stmt_let_pat(sp, Some(ex), pat, hir::LocalSource::Normal), pat_id) } fn block_expr(&mut self, expr: P) -> hir::Block {