fn find_scope(&self,
expr: &hir::Expr,
- label: Option<hir::Label>) -> LoopScope {
- match label {
- None => *self.loop_scopes.last().unwrap(),
- Some(label) => {
- for l in &self.loop_scopes {
- if l.loop_id == label.loop_id {
- return *l;
- }
- }
- span_bug!(expr.span, "no loop scope for id {}", label.loop_id);
+ label: hir::Label) -> LoopScope {
+ for l in &self.loop_scopes {
+ if l.loop_id == label.loop_id {
+ return *l;
}
}
+ span_bug!(expr.span, "no loop scope for id {}", label.loop_id);
}
}
ExprPath(ref qpath) => {
visitor.visit_qpath(qpath, expression.id, expression.span);
}
- ExprBreak(None, ref opt_expr) => {
+ ExprBreak(label, ref opt_expr) => {
+ label.ident.map(|ident| {
+ visitor.visit_def_mention(Def::Label(label.loop_id));
+ visitor.visit_name(ident.span, ident.node.name);
+ });
walk_list!(visitor, visit_expr, opt_expr);
}
- ExprBreak(Some(label), ref opt_expr) => {
- visitor.visit_def_mention(Def::Label(label.loop_id));
- visitor.visit_name(label.span, label.name);
- walk_list!(visitor, visit_expr, opt_expr);
- }
- ExprAgain(None) => {}
- ExprAgain(Some(label)) => {
- visitor.visit_def_mention(Def::Label(label.loop_id));
- visitor.visit_name(label.span, label.name);
+ ExprAgain(label) => {
+ label.ident.map(|ident| {
+ visitor.visit_def_mention(Def::Label(label.loop_id));
+ visitor.visit_name(ident.span, ident.node.name);
+ });
}
ExprRet(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
use std::collections::BTreeMap;
use std::iter;
+use std::mem;
use syntax::attr;
use syntax::ast::*;
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: FxHashMap<hir::BodyId, hir::Body>,
+ loop_scopes: Vec<NodeId>,
+
type_def_lifetime_params: DefIdMap<usize>,
}
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
bodies: FxHashMap(),
+ loop_scopes: Vec::new(),
type_def_lifetime_params: DefIdMap(),
}.lower_crate(krate)
}
span
}
+ fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
+ where F: FnOnce(&mut LoweringContext) -> T
+ {
+ let len = self.loop_scopes.len();
+ self.loop_scopes.push(loop_id);
+ let result = f(self);
+ assert_eq!(len + 1, self.loop_scopes.len(),
+ "Loop scopes should be added and removed in stack order");
+ self.loop_scopes.pop().unwrap();
+ result
+ }
+
+ fn with_new_loop_scopes<T, F>(&mut self, f: F) -> T
+ where F: FnOnce(&mut LoweringContext) -> T
+ {
+ let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new());
+ let result = f(self);
+ mem::replace(&mut self.loop_scopes, loop_scopes);
+ result
+ }
+
fn with_parent_def<T, F>(&mut self, parent_id: NodeId, f: F) -> T
where F: FnOnce(&mut LoweringContext) -> T
{
o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
}
- fn lower_label(&mut self, id: NodeId, label: Option<Spanned<Ident>>) -> Option<hir::Label> {
- label.map(|sp_ident| {
- hir::Label {
- span: sp_ident.span,
- name: sp_ident.node.name,
+ fn lower_label(&mut self, label: Option<(NodeId, Spanned<Ident>)>) -> hir::Label {
+ match label {
+ Some((id, label_ident)) => hir::Label {
+ ident: Some(label_ident),
loop_id: match self.expect_full_def(id) {
Def::Label(loop_id) => loop_id,
_ => DUMMY_NODE_ID
}
+ },
+ None => hir::Label {
+ ident: None,
+ loop_id: match self.loop_scopes.last() {
+ Some(innermost_loop_id) => *innermost_loop_id,
+ _ => DUMMY_NODE_ID
+ }
}
- })
+ }
}
fn lower_attrs(&mut self, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
self.record_body(value, None))
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
- let body = self.lower_block(body);
- let body = self.expr_block(body, ThinVec::new());
- let body_id = self.record_body(body, Some(decl));
- hir::ItemFn(self.lower_fn_decl(decl),
- self.lower_unsafety(unsafety),
- self.lower_constness(constness),
- abi,
- self.lower_generics(generics),
- body_id)
+ self.with_new_loop_scopes(|this| {
+ let body = this.lower_block(body);
+ let body = this.expr_block(body, ThinVec::new());
+ let body_id = this.record_body(body, Some(decl));
+ hir::ItemFn(this.lower_fn_decl(decl),
+ this.lower_unsafety(unsafety),
+ this.lower_constness(constness),
+ abi,
+ this.lower_generics(generics),
+ body_id)
+ })
}
ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt)
}
ExprKind::While(ref cond, ref body, opt_ident) => {
- hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body),
- self.lower_opt_sp_ident(opt_ident))
+ self.with_loop_scope(e.id, |this|
+ hir::ExprWhile(
+ P(this.lower_expr(cond)),
+ this.lower_block(body),
+ this.lower_opt_sp_ident(opt_ident)))
}
ExprKind::Loop(ref body, opt_ident) => {
- hir::ExprLoop(self.lower_block(body),
- self.lower_opt_sp_ident(opt_ident),
- hir::LoopSource::Loop)
+ self.with_loop_scope(e.id, |this|
+ hir::ExprLoop(this.lower_block(body),
+ this.lower_opt_sp_ident(opt_ident),
+ hir::LoopSource::Loop))
}
ExprKind::Match(ref expr, ref arms) => {
hir::ExprMatch(P(self.lower_expr(expr)),
hir::MatchSource::Normal)
}
ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => {
- self.with_parent_def(e.id, |this| {
- let expr = this.lower_expr(body);
- hir::ExprClosure(this.lower_capture_clause(capture_clause),
- this.lower_fn_decl(decl),
- this.record_body(expr, Some(decl)),
- fn_decl_span)
+ self.with_new_loop_scopes(|this| {
+ this.with_parent_def(e.id, |this| {
+ let expr = this.lower_expr(body);
+ hir::ExprClosure(this.lower_capture_clause(capture_clause),
+ this.lower_fn_decl(decl),
+ this.record_body(expr, Some(decl)),
+ fn_decl_span)
+ })
})
}
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)),
hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
}
ExprKind::Break(opt_ident, ref opt_expr) => {
- hir::ExprBreak(self.lower_label(e.id, opt_ident),
+ hir::ExprBreak(
+ self.lower_label(opt_ident.map(|ident| (e.id, ident))),
opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
}
- ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)),
+ ExprKind::Continue(opt_ident) =>
+ hir::ExprAgain(
+ self.lower_label(opt_ident.map(|ident| (e.id, ident)))),
ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
ExprKind::InlineAsm(ref asm) => {
let hir_asm = hir::InlineAsm {
// }
// }
+ let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| (
+ this.lower_block(body),
+ this.expr_break(e.span, ThinVec::new()),
+ P(this.lower_expr(sub_expr)),
+ ));
+
// `<pat> => <body>`
let pat_arm = {
- let body = self.lower_block(body);
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pat = self.lower_pat(pat);
self.arm(hir_vec![pat], body_expr)
// `_ => break`
let break_arm = {
let pat_under = self.pat_wild(e.span);
- let break_expr = self.expr_break(e.span, ThinVec::new());
self.arm(hir_vec![pat_under], break_expr)
};
// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
- let sub_expr = P(self.lower_expr(sub_expr));
let match_expr = self.expr(e.span,
hir::ExprMatch(sub_expr,
arms,
// `::std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
- let body_block = self.lower_block(body);
+ let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body));
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let pat = self.lower_pat(pat);
let some_pat = self.pat_some(e.span, pat);
// `::std::option::Option::None => break`
let break_arm = {
- let break_expr = self.expr_break(e.span, ThinVec::new());
+ let break_expr = self.with_loop_scope(e.id, |this|
+ this.expr_break(e.span, ThinVec::new()));
let pat = self.pat_none(e.span);
self.arm(hir_vec![pat], break_expr)
};
}
fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
- P(self.expr(span, hir::ExprBreak(None, None), attrs))
+ let expr_break = hir::ExprBreak(self.lower_label(None), None);
+ P(self.expr(span, expr_break, attrs))
}
fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<hir::Expr>)
use syntax_pos::{Span, ExpnId, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
-use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
+use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use syntax::ptr::P;
use syntax::symbol::{Symbol, keywords};
/// A referencing operation (`&a` or `&mut a`)
ExprAddrOf(Mutability, P<Expr>),
/// A `break`, with an optional label to break
- ExprBreak(Option<Label>, Option<P<Expr>>),
+ ExprBreak(Label, Option<P<Expr>>),
/// A `continue`, with an optional label
- ExprAgain(Option<Label>),
+ ExprAgain(Label),
/// A `return`, with an optional value to be returned
ExprRet(Option<P<Expr>>),
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub struct Label {
- pub span: Span,
- pub name: Name,
+ pub ident: Option<Spanned<Ident>>,
pub loop_id: NodeId
}
hir::ExprPath(ref qpath) => {
self.print_qpath(qpath, true)?
}
- hir::ExprBreak(opt_label, ref opt_expr) => {
+ hir::ExprBreak(label, ref opt_expr) => {
word(&mut self.s, "break")?;
space(&mut self.s)?;
- if let Some(label) = opt_label {
- self.print_name(label.name)?;
+ if let Some(label_ident) = label.ident {
+ self.print_name(label_ident.node.name)?;
space(&mut self.s)?;
}
if let Some(ref expr) = *opt_expr {
space(&mut self.s)?;
}
}
- hir::ExprAgain(opt_label) => {
+ hir::ExprAgain(label) => {
word(&mut self.s, "continue")?;
space(&mut self.s)?;
- if let Some(label) = opt_label {
- self.print_name(label.name)?;
+ if let Some(label_ident) = label.ident {
+ self.print_name(label_ident.node.name)?;
space(&mut self.s)?
}
}
Ok(())
}
- fn find_loop_scope(&self,
- opt_label: Option<hir::Label>,
- sp: Span)
- -> NodeId {
- match opt_label {
- Some(label) => label.loop_id,
- None => {
- // Vanilla 'break' or 'continue', so use the enclosing
- // loop scope
- if self.loop_scope.is_empty() {
- span_bug!(sp, "break outside loop");
- } else {
- *self.loop_scope.last().unwrap()
- }
- }
- }
- }
#[allow(unused_must_use)]
fn ln_str(&self, ln: LiveNode) -> String {
self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
}
- hir::ExprBreak(opt_label, ref opt_expr) => {
+ hir::ExprBreak(label, ref opt_expr) => {
// Find which label this break jumps to
- let sc = self.find_loop_scope(opt_label, expr.span);
+ let sc = label.loop_id;
// Now that we know the label we're going to,
// look it up in the break loop nodes table
}
}
- hir::ExprAgain(opt_label) => {
+ hir::ExprAgain(label) => {
// Find which label this expr continues to
- let sc = self.find_loop_scope(opt_label, expr.span);
+ let sc = label.loop_id;
// Now that we know the label we're going to,
// look it up in the continue loop nodes table
ExprIndex(..) => (SawExprIndex, true),
ExprPath(_) => (SawExprPath, false),
ExprAddrOf(m, _) => (SawExprAddrOf(m), false),
- ExprBreak(label, _) => (SawExprBreak(label.map(|l| l.name.as_str())), false),
- ExprAgain(label) => (SawExprAgain(label.map(|l| l.name.as_str())), false),
+ ExprBreak(label, _) => (SawExprBreak(label.ident.map(|i|
+ i.node.name.as_str())), false),
+ ExprAgain(label) => (SawExprAgain(label.ident.map(|i|
+ i.node.name.as_str())), false),
ExprRet(..) => (SawExprRet, false),
ExprInlineAsm(ref a,..) => (SawExprInlineAsm(StableInlineAsm(a)), false),
ExprStruct(..) => (SawExprStruct, false),
/// resolving `break` and `continue`.
pub fn find_loop_scope(&mut self,
span: Span,
- label: Option<CodeExtent>)
+ label: CodeExtent)
-> &mut LoopScope<'tcx> {
- let loop_scopes = &mut self.loop_scopes;
- match label {
- None => {
- // no label? return the innermost loop scope
- loop_scopes.iter_mut().rev().next()
- }
- Some(label) => {
- // otherwise, find the loop-scope with the correct id
- loop_scopes.iter_mut()
- .rev()
- .filter(|loop_scope| loop_scope.extent == label)
- .next()
- }
- }.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
+ // find the loop-scope with the correct id
+ self.loop_scopes.iter_mut()
+ .rev()
+ .filter(|loop_scope| loop_scope.extent == label)
+ .next()
+ .unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
}
/// Given a span and the current visibility scope, make a SourceInfo.
hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
hir::ExprBreak(label, ref value) => {
ExprKind::Break {
- label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
+ label: cx.tcx.region_maps.node_extent(label.loop_id),
value: value.to_ref(),
}
}
hir::ExprAgain(label) => {
ExprKind::Continue {
- label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
+ label: cx.tcx.region_maps.node_extent(label.loop_id),
}
}
hir::ExprMatch(ref discr, ref arms, _) => {
arg: ExprRef<'tcx>,
},
Break {
- label: Option<CodeExtent>,
+ label: CodeExtent,
value: Option<ExprRef<'tcx>>,
},
Continue {
- label: Option<CodeExtent>,
+ label: CodeExtent,
},
Return {
value: Option<ExprRef<'tcx>>,
}
hir::ExprBreak(label, ref opt_expr) => {
if opt_expr.is_some() {
- let loop_kind = if let Some(label) = label {
- if label.loop_id == ast::DUMMY_NODE_ID {
- None
- } else {
- Some(match self.hir_map.expect_expr(label.loop_id).node {
- hir::ExprWhile(..) => LoopKind::WhileLoop,
- hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
- ref r => span_bug!(e.span,
- "break label resolved to a non-loop: {:?}", r),
- })
- }
- } else if let Loop(kind) = self.cx {
- Some(kind)
- } else {
- // `break` outside a loop - caught below
+ let loop_kind = if label.loop_id == ast::DUMMY_NODE_ID {
None
+ } else {
+ Some(match self.hir_map.expect_expr(label.loop_id).node {
+ hir::ExprWhile(..) => LoopKind::WhileLoop,
+ hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
+ ref r => span_bug!(e.span,
+ "break label resolved to a non-loop: {:?}", r),
+ })
};
match loop_kind {
None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
}
impl<'gcx, 'tcx> EnclosingLoops<'gcx, 'tcx> {
- fn find_loop(&mut self, id: Option<ast::NodeId>) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
- if let Some(id) = id {
- if let Some(ix) = self.by_id.get(&id).cloned() {
- Some(&mut self.stack[ix])
- } else {
- None
- }
+ fn find_loop(&mut self, id: ast::NodeId) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
+ if let Some(ix) = self.by_id.get(&id).cloned() {
+ Some(&mut self.stack[ix])
} else {
- self.stack.last_mut()
+ None
}
}
}
tcx.mk_nil()
}
hir::ExprBreak(label, ref expr_opt) => {
- let loop_id = label.map(|l| l.loop_id);
+ let loop_id = label.loop_id;
let coerce_to = {
let mut enclosing_loops = self.enclosing_loops.borrow_mut();
enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
panic!();
};
assert_eq!(nested_break_value, "hello");
-
- let break_from_while_cond = loop {
- while break {
- panic!();
- }
- break 123;
- };
- assert_eq!(break_from_while_cond, 123);
}