Skip to content

Commit

Permalink
Rollup merge of rust-lang#47502 - petrochenkov:label, r=eddyb
Browse files Browse the repository at this point in the history
AST/HIR: Add a separate structure for labels
  • Loading branch information
alexcrichton authored Jan 25, 2018
2 parents 304885d + 2d56abf commit 98b3754
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 202 deletions.
52 changes: 24 additions & 28 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@

use syntax::abi::Abi;
use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
use syntax::codemap::Spanned;
use syntax_pos::Span;
use hir::*;
use hir::def::Def;
Expand Down Expand Up @@ -336,6 +335,9 @@ pub trait Visitor<'v> : Sized {
fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
walk_variant(self, v, g, item_id)
}
fn visit_label(&mut self, label: &'v Label) {
walk_label(self, label)
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
walk_lifetime(self, lifetime)
}
Expand Down Expand Up @@ -370,18 +372,6 @@ pub trait Visitor<'v> : Sized {
}
}

pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
if let Some(name) = opt_name {
visitor.visit_name(span, name);
}
}

pub fn walk_opt_sp_name<'v, V: Visitor<'v>>(visitor: &mut V, opt_sp_name: &Option<Spanned<Name>>) {
if let Some(ref sp_name) = *opt_sp_name {
visitor.visit_name(sp_name.span, sp_name.node);
}
}

/// Walks the contents of a crate. See also `Crate::visit_all_items`.
pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
Expand Down Expand Up @@ -420,6 +410,10 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
walk_list!(visitor, visit_ty, &local.ty);
}

pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
visitor.visit_name(label.span, label.name);
}

pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.id);
match lifetime.name {
Expand Down Expand Up @@ -452,7 +446,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
match item.node {
ItemExternCrate(opt_name) => {
visitor.visit_id(item.id);
walk_opt_name(visitor, item.span, opt_name)
if let Some(name) = opt_name {
visitor.visit_name(item.span, name);
}
}
ItemUse(ref path, _) => {
visitor.visit_id(item.id);
Expand Down Expand Up @@ -993,14 +989,14 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_expr(if_block);
walk_list!(visitor, visit_expr, optional_else);
}
ExprWhile(ref subexpression, ref block, ref opt_sp_name) => {
ExprWhile(ref subexpression, ref block, ref opt_label) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_expr(subexpression);
visitor.visit_block(block);
walk_opt_sp_name(visitor, opt_sp_name);
}
ExprLoop(ref block, ref opt_sp_name, _) => {
ExprLoop(ref block, ref opt_label, _) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
walk_opt_sp_name(visitor, opt_sp_name);
}
ExprMatch(ref subexpression, ref arms, _) => {
visitor.visit_expr(subexpression);
Expand Down Expand Up @@ -1036,28 +1032,28 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
ExprPath(ref qpath) => {
visitor.visit_qpath(qpath, expression.id, expression.span);
}
ExprBreak(label, ref opt_expr) => {
label.ident.map(|ident| {
match label.target_id {
ExprBreak(ref destination, ref opt_expr) => {
if let Some(ref label) = destination.label {
visitor.visit_label(label);
match destination.target_id {
ScopeTarget::Block(node_id) |
ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
visitor.visit_def_mention(Def::Label(node_id)),
ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
};
visitor.visit_name(ident.span, ident.node.name);
});
}
walk_list!(visitor, visit_expr, opt_expr);
}
ExprAgain(label) => {
label.ident.map(|ident| {
match label.target_id {
ExprAgain(ref destination) => {
if let Some(ref label) = destination.label {
visitor.visit_label(label);
match destination.target_id {
ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"),
ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
visitor.visit_def_mention(Def::Label(node_id)),
ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
};
visitor.visit_name(ident.span, ident.node.name);
});
}
}
ExprRet(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
Expand Down
48 changes: 24 additions & 24 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,22 +773,22 @@ impl<'a> LoweringContext<'a> {
*self.name_map.entry(ident).or_insert_with(|| Symbol::from_ident(ident))
}

fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned<Name>> {
o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
label.map(|label| hir::Label { name: label.ident.name, span: label.span })
}

fn lower_loop_destination(&mut self, destination: Option<(NodeId, Spanned<Ident>)>)
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>)
-> hir::Destination
{
match destination {
Some((id, label_ident)) => {
Some((id, label)) => {
let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id)
} else {
hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
};
hir::Destination {
ident: Some(label_ident),
label: self.lower_label(Some(label)),
target_id: hir::ScopeTarget::Loop(target),
}
},
Expand All @@ -798,7 +798,7 @@ impl<'a> LoweringContext<'a> {
.map(|innermost_loop_id| *innermost_loop_id);

hir::Destination {
ident: None,
label: None,
target_id: hir::ScopeTarget::Loop(
loop_id.map(|id| Ok(self.lower_node_id(id).node_id))
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
Expand Down Expand Up @@ -2751,17 +2751,17 @@ impl<'a> LoweringContext<'a> {

hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt)
}
ExprKind::While(ref cond, ref body, opt_ident) => {
ExprKind::While(ref cond, ref body, opt_label) => {
self.with_loop_scope(e.id, |this|
hir::ExprWhile(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, false),
this.lower_opt_sp_ident(opt_ident)))
this.lower_label(opt_label)))
}
ExprKind::Loop(ref body, opt_ident) => {
ExprKind::Loop(ref body, opt_label) => {
self.with_loop_scope(e.id, |this|
hir::ExprLoop(this.lower_block(body, false),
this.lower_opt_sp_ident(opt_ident),
this.lower_label(opt_label),
hir::LoopSource::Loop))
}
ExprKind::Catch(ref body) => {
Expand Down Expand Up @@ -2877,30 +2877,30 @@ impl<'a> LoweringContext<'a> {
hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional,
ImplTraitContext::Disallowed))
}
ExprKind::Break(opt_ident, ref opt_expr) => {
let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
ExprKind::Break(opt_label, ref opt_expr) => {
let destination = if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
ident: opt_ident,
label: None,
target_id: hir::ScopeTarget::Loop(
Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
}
} else {
self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident)))
self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
};
hir::ExprBreak(
label_result,
destination,
opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
}
ExprKind::Continue(opt_ident) =>
ExprKind::Continue(opt_label) =>
hir::ExprAgain(
if self.is_in_loop_condition && opt_ident.is_none() {
if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
ident: opt_ident,
label: None,
target_id: hir::ScopeTarget::Loop(Err(
hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
}
} else {
self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident)))
self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
}),
ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
ExprKind::InlineAsm(ref asm) => {
Expand Down Expand Up @@ -3000,7 +3000,7 @@ impl<'a> LoweringContext<'a> {

// Desugar ExprWhileLet
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
// to:
//
// [opt_ident]: loop {
Expand Down Expand Up @@ -3041,15 +3041,15 @@ impl<'a> LoweringContext<'a> {

// `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr)));
let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
hir::LoopSource::WhileLet);
// add attributes to the outer returned expr node
loop_expr
}

// Desugar ExprForLoop
// From: `[opt_ident]: for <pat> in <head> <body>`
ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => {
ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
// to:
//
// {
Expand Down Expand Up @@ -3150,7 +3150,7 @@ impl<'a> LoweringContext<'a> {
None));

// `[opt_ident]: loop { ... }`
let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
hir::LoopSource::ForLoop);
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
let loop_expr = P(hir::Expr {
Expand Down Expand Up @@ -3270,7 +3270,7 @@ impl<'a> LoweringContext<'a> {
e.span,
hir::ExprBreak(
hir::Destination {
ident: None,
label: None,
target_id: hir::ScopeTarget::Block(catch_node),
},
Some(from_err_expr)
Expand Down
20 changes: 16 additions & 4 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use util::nodemap::{NodeMap, FxHashSet};
use syntax_pos::{Span, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
use syntax::ast::{self, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P;
Expand Down Expand Up @@ -172,6 +172,18 @@ pub const DUMMY_HIR_ID: HirId = HirId {

pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId(!0);

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Label {
pub name: Name,
pub span: Span,
}

impl fmt::Debug for Label {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "label({:?})", self.name)
}
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime {
pub id: NodeId,
Expand Down Expand Up @@ -1276,11 +1288,11 @@ pub enum Expr_ {
/// A while loop, with an optional label
///
/// `'label: while expr { block }`
ExprWhile(P<Expr>, P<Block>, Option<Spanned<Name>>),
ExprWhile(P<Expr>, P<Block>, Option<Label>),
/// Conditionless loop (can be exited with break, continue, or return)
///
/// `'label: loop { block }`
ExprLoop(P<Block>, Option<Spanned<Name>>, LoopSource),
ExprLoop(P<Block>, Option<Label>, LoopSource),
/// A `match` block, with a source that indicates whether or not it is
/// the result of a desugaring, and if so, which kind.
ExprMatch(P<Expr>, HirVec<Arm>, MatchSource),
Expand Down Expand Up @@ -1459,7 +1471,7 @@ impl ScopeTarget {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub struct Destination {
// This is `Some(_)` iff there is an explicit user-specified `label
pub ident: Option<Spanned<Ident>>,
pub label: Option<Label>,

// These errors are caught and then reported during the diagnostics pass in
// librustc_passes/loops.rs
Expand Down
24 changes: 12 additions & 12 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1337,19 +1337,19 @@ impl<'a> State<'a> {
hir::ExprIf(ref test, ref blk, ref elseopt) => {
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
}
hir::ExprWhile(ref test, ref blk, opt_sp_name) => {
if let Some(sp_name) = opt_sp_name {
self.print_name(sp_name.node)?;
hir::ExprWhile(ref test, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_name(label.name)?;
self.word_space(":")?;
}
self.head("while")?;
self.print_expr_as_cond(&test)?;
self.s.space()?;
self.print_block(&blk)?;
}
hir::ExprLoop(ref blk, opt_sp_name, _) => {
if let Some(sp_name) = opt_sp_name {
self.print_name(sp_name.node)?;
hir::ExprLoop(ref blk, opt_label, _) => {
if let Some(label) = opt_label {
self.print_name(label.name)?;
self.word_space(":")?;
}
self.head("loop")?;
Expand Down Expand Up @@ -1424,23 +1424,23 @@ impl<'a> State<'a> {
hir::ExprPath(ref qpath) => {
self.print_qpath(qpath, true)?
}
hir::ExprBreak(label, ref opt_expr) => {
hir::ExprBreak(destination, ref opt_expr) => {
self.s.word("break")?;
self.s.space()?;
if let Some(label_ident) = label.ident {
self.print_name(label_ident.node.name)?;
if let Some(label) = destination.label {
self.print_name(label.name)?;
self.s.space()?;
}
if let Some(ref expr) = *opt_expr {
self.print_expr_maybe_paren(expr, parser::PREC_JUMP)?;
self.s.space()?;
}
}
hir::ExprAgain(label) => {
hir::ExprAgain(destination) => {
self.s.word("continue")?;
self.s.space()?;
if let Some(label_ident) = label.ident {
self.print_name(label_ident.node.name)?;
if let Some(label) = destination.label {
self.print_name(label.name)?;
self.s.space()?
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ impl_stable_hash_for!(enum hir::LifetimeName {
Name(name)
});

impl_stable_hash_for!(struct hir::Label {
span,
name
});

impl_stable_hash_for!(struct hir::Lifetime {
id,
span,
Expand Down Expand Up @@ -619,7 +624,7 @@ impl_stable_hash_for!(enum hir::CaptureClause {
impl_stable_hash_for_spanned!(usize);

impl_stable_hash_for!(struct hir::Destination {
ident,
label,
target_id
});

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) {
fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
match ex.node {
hir::ExprWhile(.., Some(label)) | hir::ExprLoop(_, Some(label), _) => {
Some((label.node, label.span))
Some((label.name, label.span))
}
_ => None,
}
Expand Down
Loading

0 comments on commit 98b3754

Please sign in to comment.