Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions src/classify.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
use crate::expr::Expr;
#[cfg(feature = "parsing")]
use crate::generics::TypeParamBound;
#[cfg(feature = "parsing")]
use crate::path::{Path, PathArguments};
#[cfg(feature = "parsing")]
use crate::punctuated::Punctuated;
#[cfg(feature = "parsing")]
use crate::ty::{ReturnType, Type};
#[cfg(feature = "parsing")]
use proc_macro2::{Delimiter, TokenStream, TokenTree};
#[cfg(feature = "parsing")]
use std::ops::ControlFlow;

pub(crate) fn requires_terminator(expr: &Expr) -> bool {
// see https://github.com/rust-lang/rust/blob/9a19e7604/compiler/rustc_ast/src/util/classify.rs#L7-L26
Expand Down Expand Up @@ -43,3 +55,130 @@ pub(crate) fn requires_terminator(expr: &Expr) -> bool {
| Expr::Verbatim(_) => true
}
}

/// Whether the expression's last token is `}`.
#[cfg(feature = "parsing")]
pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool {
loop {
match expr {
Expr::Array(_) => return false,
Expr::Assign(e) => expr = &e.right,
Expr::Async(_) => return true,
Expr::Await(_) => return false,
Expr::Binary(e) => expr = &e.right,
Expr::Block(_) => return true,
Expr::Break(e) => match &e.expr {
Some(e) => expr = e,
None => return false,
},
Expr::Call(_) => return false,
Expr::Cast(e) => return type_trailing_brace(&e.ty),
Expr::Closure(e) => expr = &e.body,
Expr::Const(_) => return true,
Expr::Continue(_) => return false,
Expr::Field(_) => return false,
Expr::ForLoop(_) => return true,
Expr::Group(_) => return false,
Expr::If(_) => return true,
Expr::Index(_) => return false,
Expr::Infer(_) => return false,
Expr::Let(e) => expr = &e.expr,
Expr::Lit(_) => return false,
Expr::Loop(_) => return true,
Expr::Macro(e) => return e.mac.delimiter.is_brace(),
Expr::Match(_) => return true,
Expr::MethodCall(_) => return false,
Expr::Paren(_) => return false,
Expr::Path(_) => return false,
Expr::Range(e) => match &e.end {
Some(end) => expr = end,
None => return false,
},
Expr::Reference(e) => expr = &e.expr,
Expr::Repeat(_) => return false,
Expr::Return(e) => match &e.expr {
Some(e) => expr = e,
None => return false,
},
Expr::Struct(_) => return true,
Expr::Try(_) => return false,
Expr::TryBlock(_) => return true,
Expr::Tuple(_) => return false,
Expr::Unary(e) => expr = &e.expr,
Expr::Unsafe(_) => return true,
Expr::Verbatim(e) => return tokens_trailing_brace(e),
Expr::While(_) => return true,
Expr::Yield(e) => match &e.expr {
Some(e) => expr = e,
None => return false,
},
}
}
}

#[cfg(feature = "parsing")]
fn type_trailing_brace(mut ty: &Type) -> bool {
fn last_type_in_path(path: &Path) -> Option<&Type> {
match &path.segments.last().unwrap().arguments {
PathArguments::None | PathArguments::AngleBracketed(_) => None,
PathArguments::Parenthesized(arg) => match &arg.output {
ReturnType::Default => None,
ReturnType::Type(_, ret) => Some(ret),
},
}
}

fn last_type_in_bounds(
bounds: &Punctuated<TypeParamBound, Token![+]>,
) -> ControlFlow<bool, &Type> {
match bounds.last().unwrap() {
TypeParamBound::Trait(t) => match last_type_in_path(&t.path) {
Some(t) => ControlFlow::Continue(t),
None => ControlFlow::Break(false),
},
TypeParamBound::Lifetime(_) => ControlFlow::Break(false),
TypeParamBound::Verbatim(t) => ControlFlow::Break(tokens_trailing_brace(t)),
}
}

loop {
match ty {
Type::Array(_) => return false,
Type::BareFn(t) => match &t.output {
ReturnType::Default => return false,
ReturnType::Type(_, ret) => ty = ret,
},
Type::Group(_) => return false,
Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) {
ControlFlow::Break(trailing_brace) => return trailing_brace,
ControlFlow::Continue(t) => ty = t,
},
Type::Infer(_) => return false,
Type::Macro(t) => return t.mac.delimiter.is_brace(),
Type::Never(_) => return false,
Type::Paren(_) => return false,
Type::Path(t) => match last_type_in_path(&t.path) {
Some(t) => ty = t,
None => return false,
},
Type::Ptr(t) => ty = &t.elem,
Type::Reference(t) => ty = &t.elem,
Type::Slice(_) => return false,
Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) {
ControlFlow::Break(trailing_brace) => return trailing_brace,
ControlFlow::Continue(t) => ty = t,
},
Type::Tuple(_) => return false,
Type::Verbatim(t) => return tokens_trailing_brace(t),
}
}
}

#[cfg(feature = "parsing")]
fn tokens_trailing_brace(tokens: &TokenStream) -> bool {
if let Some(TokenTree::Group(last)) = tokens.clone().into_iter().last() {
last.delimiter() == Delimiter::Brace
} else {
false
}
}
11 changes: 1 addition & 10 deletions src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ pub(crate) mod parsing {
};
use crate::lifetime::Lifetime;
use crate::lit::LitStr;
use crate::mac::{self, Macro, MacroDelimiter};
use crate::mac::{self, Macro};
use crate::parse::discouraged::Speculative as _;
use crate::parse::{Parse, ParseBuffer, ParseStream};
use crate::pat::{Pat, PatType, PatWild};
Expand Down Expand Up @@ -2872,15 +2872,6 @@ pub(crate) mod parsing {
}
}

impl MacroDelimiter {
pub(crate) fn is_brace(&self) -> bool {
match self {
MacroDelimiter::Brace(_) => true,
MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
}
}
}

#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for StaticMutability {
fn parse(input: ParseStream) -> Result<Self> {
Expand Down
8 changes: 8 additions & 0 deletions src/mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ impl MacroDelimiter {
MacroDelimiter::Bracket(token) => &token.span,
}
}

#[cfg(all(feature = "full", feature = "parsing"))]
pub(crate) fn is_brace(&self) -> bool {
match self {
MacroDelimiter::Brace(_) => true,
MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
}
}
}

impl Macro {
Expand Down
4 changes: 2 additions & 2 deletions src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ pub(crate) mod parsing {
let eq_token: Token![=] = eq_token;
let expr: Expr = input.parse()?;

let diverge = if let Some(else_token) = input.parse()? {
let else_token: Token![else] = else_token;
let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) {
let else_token: Token![else] = input.parse()?;
let diverge = ExprBlock {
attrs: Vec::new(),
label: None,
Expand Down