rust/compiler/rustc_ast_pretty/src/pprust/state.rs

2895 lines
102 KiB
Rust
Raw Normal View History

use crate::pp::Breaks::{Consistent, Inconsistent};
use crate::pp::{self, Breaks};
2019-02-06 18:33:01 +01:00
use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::util::classify;
use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
use rustc_ast::util::parser::{self, AssocOp, Fixity};
2020-04-27 19:56:11 +02:00
use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
use rustc_ast::{GenericArg, MacArgs, ModKind};
2020-04-27 19:56:11 +02:00
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
2020-01-11 10:33:18 +01:00
use rustc_span::edition::Edition;
use rustc_span::source_map::{SourceMap, Spanned};
2020-04-19 13:00:18 +02:00
use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
use rustc_span::{BytePos, FileName, Span};
use std::borrow::Cow;
2019-07-14 15:09:39 +02:00
pub enum MacHeader<'a> {
Path(&'a ast::Path),
Keyword(&'static str),
}
2014-03-16 19:58:11 +01:00
pub enum AnnNode<'a> {
2020-04-19 13:00:18 +02:00
Ident(&'a Ident),
Name(&'a Symbol),
2018-08-22 23:05:19 +02:00
Block(&'a ast::Block),
Item(&'a ast::Item),
SubItem(ast::NodeId),
Expr(&'a ast::Expr),
Pat(&'a ast::Pat),
Crate(&'a ast::Crate),
}
pub trait PpAnn {
2019-12-22 23:42:04 +01:00
fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
}
2015-03-30 15:38:59 +02:00
#[derive(Copy, Clone)]
pub struct NoAnn;
impl PpAnn for NoAnn {}
pub struct Comments<'a> {
2020-02-22 15:07:05 +01:00
sm: &'a SourceMap,
comments: Vec<Comment>,
current: usize,
}
impl<'a> Comments<'a> {
2020-02-22 15:07:05 +01:00
pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
let comments = gather_comments(sm, filename, input);
2020-02-22 15:07:05 +01:00
Comments { sm, comments, current: 0 }
}
pub fn next(&self) -> Option<Comment> {
self.comments.get(self.current).cloned()
}
pub fn trailing_comment(
&self,
span: rustc_span::Span,
next_pos: Option<BytePos>,
) -> Option<Comment> {
if let Some(cmnt) = self.next() {
if cmnt.style != CommentStyle::Trailing {
2019-12-22 23:42:04 +01:00
return None;
}
2020-02-22 15:07:05 +01:00
let span_line = self.sm.lookup_char_pos(span.hi());
let comment_line = self.sm.lookup_char_pos(cmnt.pos);
let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
return Some(cmnt);
}
}
None
}
}
pub struct State<'a> {
pub s: pp::Printer,
comments: Option<Comments<'a>>,
2019-12-22 23:42:04 +01:00
ann: &'a (dyn PpAnn + 'a),
}
2019-06-24 18:12:56 +02:00
crate const INDENT_UNIT: usize = 4;
2014-06-09 22:12:30 +02:00
/// Requires you to pass an input filename and reader so that
2019-05-09 18:04:04 +02:00
/// it can scan the input text for comments to copy forward.
2019-12-22 23:42:04 +01:00
pub fn print_crate<'a>(
2020-02-22 15:07:05 +01:00
sm: &'a SourceMap,
2019-12-22 23:42:04 +01:00
krate: &ast::Crate,
filename: FileName,
input: String,
ann: &'a dyn PpAnn,
is_expanded: bool,
2020-01-11 10:33:18 +01:00
edition: Edition,
2019-12-22 23:42:04 +01:00
) -> String {
let mut s =
State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
// We need to print `#![no_std]` (and its feature gate) so that
// compiling pretty-printed source won't inject libstd again.
// However, we don't want these attributes in the AST because
// of the feature gate, so we fake them up here.
// `#![feature(prelude_import)]`
2020-04-19 13:00:18 +02:00
let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
let fake_attr = attr::mk_attr_inner(list);
s.print_attribute(&fake_attr);
// Currently, in Rust 2018 we don't have `extern crate std;` at the crate
// root, so this is not needed, and actually breaks things.
2020-01-11 10:33:18 +01:00
if edition == Edition::Edition2015 {
// `#![no_std]`
2020-04-19 13:00:18 +02:00
let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
let fake_attr = attr::mk_attr_inner(no_std_meta);
s.print_attribute(&fake_attr);
}
}
s.print_inner_attributes(&krate.attrs);
for item in &krate.items {
s.print_item(item);
}
s.print_remaining_comments();
s.ann.post(&mut s, AnnNode::Crate(krate));
s.s.eof()
2012-02-22 00:34:26 +01:00
}
// This makes printed token streams look slightly nicer,
// and also addresses some specific regressions described in #63896 and #73345.
2020-03-17 15:08:11 +01:00
fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
if let TokenTree::Token(token) = prev {
if let token::DocComment(comment_kind, ..) = token.kind {
return comment_kind != CommentKind::Line;
}
}
match tt {
TokenTree::Token(token) => token.kind != token::Comma,
TokenTree::Delimited(_, DelimToken::Paren, _) => {
!matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }))
}
TokenTree::Delimited(_, DelimToken::Bracket, _) => {
!matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }))
}
TokenTree::Delimited(..) => true,
}
}
2017-06-25 15:51:55 +02:00
fn binop_to_string(op: BinOpToken) -> &'static str {
match op {
2019-12-22 23:42:04 +01:00
token::Plus => "+",
token::Minus => "-",
token::Star => "*",
token::Slash => "/",
token::Percent => "%",
token::Caret => "^",
token::And => "&",
token::Or => "|",
token::Shl => "<<",
token::Shr => ">>",
}
}
fn doc_comment_to_string(
comment_kind: CommentKind,
attr_style: ast::AttrStyle,
data: Symbol,
) -> String {
match (comment_kind, attr_style) {
(CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
(CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
(CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
(CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
}
}
2019-05-19 18:56:45 +02:00
pub fn literal_to_string(lit: token::Lit) -> String {
let token::Lit { kind, symbol, suffix } = lit;
let mut out = match kind {
2019-12-22 23:42:04 +01:00
token::Byte => format!("b'{}'", symbol),
token::Char => format!("'{}'", symbol),
token::Str => format!("\"{}\"", symbol),
token::StrRaw(n) => {
format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
}
token::ByteStr => format!("b\"{}\"", symbol),
token::ByteStrRaw(n) => {
format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
}
token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
2019-05-09 18:04:04 +02:00
};
if let Some(suffix) = suffix {
out.push_str(&suffix.as_str())
}
out
}
2019-07-05 22:00:38 +02:00
fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s)
2014-01-30 02:39:21 +01:00
}
2011-05-29 04:16:18 +02:00
impl std::ops::Deref for State<'_> {
type Target = pp::Printer;
fn deref(&self) -> &Self::Target {
&self.s
}
}
2011-05-29 04:16:18 +02:00
impl std::ops::DerefMut for State<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.s
}
}
2011-05-29 04:16:18 +02:00
pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
fn comments(&mut self) -> &mut Option<Comments<'a>>;
2020-04-19 13:00:18 +02:00
fn print_ident(&mut self, ident: Ident);
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
2011-05-29 04:16:18 +02:00
2019-12-22 23:42:04 +01:00
fn strsep<T, F>(
&mut self,
sep: &'static str,
space_before: bool,
b: Breaks,
elts: &[T],
mut op: F,
) where
F: FnMut(&mut Self, &T),
{
self.rbox(0, b);
if let Some((first, rest)) = elts.split_first() {
op(self, first);
for elt in rest {
if space_before {
self.space();
2018-10-19 16:40:07 +02:00
}
self.word_space(sep);
op(self, elt);
2018-10-19 16:40:07 +02:00
}
}
self.end();
}
fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
2019-12-22 23:42:04 +01:00
where
F: FnMut(&mut Self, &T),
2018-10-19 16:40:07 +02:00
{
self.strsep(",", false, b, elts, op)
2018-10-19 16:40:07 +02:00
}
fn maybe_print_comment(&mut self, pos: BytePos) {
2016-10-12 19:54:41 +02:00
while let Some(ref cmnt) = self.next_comment() {
if cmnt.pos < pos {
self.print_comment(cmnt);
2016-10-12 19:54:41 +02:00
} else {
2019-12-22 23:42:04 +01:00
break;
}
}
}
fn print_comment(&mut self, cmnt: &Comment) {
match cmnt.style {
CommentStyle::Mixed => {
if !self.is_beginning_of_line() {
self.zerobreak();
}
if let Some((last, lines)) = cmnt.lines.split_last() {
self.ibox(0);
for line in lines {
self.word(line.clone());
self.hardbreak()
}
self.word(last.clone());
self.space();
self.end();
}
2019-07-09 15:51:56 +02:00
self.zerobreak()
}
CommentStyle::Isolated => {
self.hardbreak_if_not_bol();
for line in &cmnt.lines {
// Don't print empty lines because they will end up as trailing
// whitespace.
if !line.is_empty() {
2019-07-09 15:51:56 +02:00
self.word(line.clone());
}
2019-07-09 15:51:56 +02:00
self.hardbreak();
}
}
CommentStyle::Trailing => {
2019-07-09 15:51:56 +02:00
if !self.is_beginning_of_line() {
self.word(" ");
2016-10-12 19:54:41 +02:00
}
if cmnt.lines.len() == 1 {
2019-07-09 15:51:56 +02:00
self.word(cmnt.lines[0].clone());
self.hardbreak()
} else {
self.ibox(0);
for line in &cmnt.lines {
if !line.is_empty() {
2019-07-09 15:51:56 +02:00
self.word(line.clone());
}
2019-07-09 15:51:56 +02:00
self.hardbreak();
}
self.end();
}
}
CommentStyle::BlankLine => {
// We need to do at least one, possibly two hardbreaks.
2019-07-09 15:51:56 +02:00
let twice = match self.last_token() {
pp::Token::String(s) => ";" == s,
pp::Token::Begin(_) => true,
pp::Token::End => true,
2019-12-22 23:42:04 +01:00
_ => false,
};
if twice {
2019-07-09 15:51:56 +02:00
self.hardbreak();
}
2019-07-09 15:51:56 +02:00
self.hardbreak();
}
}
2020-02-22 15:07:05 +01:00
if let Some(cmnts) = self.comments() {
cmnts.current += 1;
}
}
fn next_comment(&mut self) -> Option<Comment> {
self.comments().as_mut().and_then(|c| c.next())
}
fn print_literal(&mut self, lit: &ast::Lit) {
self.maybe_print_comment(lit.span.lo());
2019-07-09 15:51:56 +02:00
self.word(lit.token.to_string())
}
2019-12-22 23:42:04 +01:00
fn print_string(&mut self, st: &str, style: ast::StrStyle) {
let st = match style {
2019-12-22 23:42:04 +01:00
ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
ast::StrStyle::Raw(n) => {
format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
}
};
2019-07-09 15:51:56 +02:00
self.word(st)
}
fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
self.print_string(&sym.as_str(), style);
}
2019-12-22 23:42:04 +01:00
fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
}
2019-12-22 23:42:04 +01:00
fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
}
2019-12-22 23:42:04 +01:00
fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
}
2019-12-22 23:42:04 +01:00
fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
}
2019-12-22 23:42:04 +01:00
fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
}
2019-12-22 23:42:04 +01:00
fn print_either_attributes(
&mut self,
attrs: &[ast::Attribute],
kind: ast::AttrStyle,
is_inline: bool,
trailing_hardbreak: bool,
) {
let mut count = 0;
for attr in attrs {
2016-11-14 13:00:25 +01:00
if attr.style == kind {
self.print_attribute_inline(attr, is_inline);
if is_inline {
self.nbsp();
}
count += 1;
}
}
if count > 0 && trailing_hardbreak && !is_inline {
self.hardbreak_if_not_bol();
}
}
fn print_attribute(&mut self, attr: &ast::Attribute) {
self.print_attribute_inline(attr, false)
}
2019-12-22 23:42:04 +01:00
fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
if !is_inline {
self.hardbreak_if_not_bol();
}
self.maybe_print_comment(attr.span.lo());
match attr.kind {
2020-11-05 18:27:48 +01:00
ast::AttrKind::Normal(ref item, _) => {
match attr.style {
ast::AttrStyle::Inner => self.word("#!["),
ast::AttrStyle::Outer => self.word("#["),
}
self.print_attr_item(&item, attr.span);
self.word("]");
}
ast::AttrKind::DocComment(comment_kind, data) => {
self.word(doc_comment_to_string(comment_kind, attr.style, data));
self.hardbreak()
}
}
}
fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
self.ibox(0);
match &item.args {
MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
Some(MacHeader::Path(&item.path)),
false,
None,
delim.to_token(),
tokens,
true,
span,
),
MacArgs::Empty | MacArgs::Eq(..) => {
self.print_path(&item.path, false, 0);
if let MacArgs::Eq(_, token) = &item.args {
self.space();
self.word_space("=");
let token_str = self.token_to_string_ext(token, true);
self.word(token_str);
}
}
}
self.end();
}
fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
match item {
2019-12-22 23:42:04 +01:00
ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
}
}
fn print_meta_item(&mut self, item: &ast::MetaItem) {
self.ibox(INDENT_UNIT);
match item.kind {
ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
ast::MetaItemKind::NameValue(ref value) => {
self.print_path(&item.path, false, 0);
2019-07-09 15:51:56 +02:00
self.space();
self.word_space("=");
self.print_literal(value);
}
ast::MetaItemKind::List(ref items) => {
self.print_path(&item.path, false, 0);
self.popen();
2019-12-22 23:42:04 +01:00
self.commasep(Consistent, &items[..], |s, i| s.print_meta_list_item(i));
self.pclose();
}
}
self.end();
}
/// This doesn't deserve to be called "pretty" printing, but it should be
/// meaning-preserving. A quick hack that might help would be to look at the
/// spans embedded in the TTs to decide where to put spaces and newlines.
/// But it'd be better to parse these according to the grammar of the
/// appropriate macro, transcribe back into the grammar we just parsed from,
/// and then pretty-print the resulting AST nodes (so, e.g., we print
/// expression arguments as expressions). It can be done! I think.
fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
match tt {
TokenTree::Token(token) => {
let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
self.word(token_str);
if let token::DocComment(..) = token.kind {
self.hardbreak()
}
}
TokenTree::Delimited(dspan, delim, tts) => {
self.print_mac_common(
2019-12-22 23:42:04 +01:00
None,
false,
None,
*delim,
2019-12-22 23:42:04 +01:00
tts,
convert_dollar_crate,
dspan.entire(),
);
}
}
}
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
let mut iter = tts.trees().peekable();
2020-03-17 15:08:11 +01:00
while let Some(tt) = iter.next() {
self.print_tt(&tt, convert_dollar_crate);
if let Some(next) = iter.peek() {
if tt_prepend_space(next, &tt) {
self.space();
}
}
}
}
fn print_mac_common(
&mut self,
2019-07-14 15:09:39 +02:00
header: Option<MacHeader<'_>>,
has_bang: bool,
2020-04-19 13:00:18 +02:00
ident: Option<Ident>,
delim: DelimToken,
tts: &TokenStream,
convert_dollar_crate: bool,
span: Span,
) {
if delim == DelimToken::Brace {
self.cbox(INDENT_UNIT);
}
2019-07-14 15:09:39 +02:00
match header {
Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
Some(MacHeader::Keyword(kw)) => self.word(kw),
None => {}
}
if has_bang {
self.word("!");
}
if let Some(ident) = ident {
self.nbsp();
self.print_ident(ident);
}
match delim {
DelimToken::Brace => {
2019-07-14 15:09:39 +02:00
if header.is_some() || has_bang || ident.is_some() {
self.nbsp();
}
self.word("{");
if !tts.is_empty() {
self.space();
}
}
_ => {
let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
self.word(token_str)
}
}
self.ibox(0);
self.print_tts(tts, convert_dollar_crate);
self.end();
match delim {
DelimToken::Brace => self.bclose(span),
_ => {
let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
self.word(token_str)
}
}
}
fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
self.maybe_print_comment(path.span.lo());
for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
if i > 0 {
self.word("::")
}
self.print_path_segment(segment, colons_before_params);
}
}
fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
if let Some(ref args) = segment.args {
self.print_generic_args(args, colons_before_params);
}
}
}
fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
let w = w.into();
// Outer-box is consistent.
self.cbox(INDENT_UNIT);
// Head-box is inconsistent.
self.ibox(w.len() + 1);
// Keyword that starts the head.
2014-03-16 19:58:11 +01:00
if !w.is_empty() {
self.word_nbsp(w);
2014-03-16 19:58:11 +01:00
}
}
fn bopen(&mut self) {
self.word("{");
self.end(); // Close the head-box.
}
fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
self.maybe_print_comment(span.hi());
self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
self.word("}");
2014-03-16 19:58:11 +01:00
if close_box {
self.end(); // Close the outer-box.
2014-03-16 19:58:11 +01:00
}
}
fn bclose(&mut self, span: rustc_span::Span) {
self.bclose_maybe_open(span, true)
2014-03-16 19:58:11 +01:00
}
2014-01-30 02:39:21 +01:00
fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
if !self.is_beginning_of_line() {
self.break_offset(n, off)
2020-10-27 02:02:48 +01:00
} else if off != 0 && self.last_token().is_hardbreak_tok() {
// We do something pretty sketchy here: tuck the nonzero
// offset-adjustment we were going to deposit along with the
// break into the previous hardbreak.
self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
2014-03-16 19:58:11 +01:00
}
2014-01-30 02:39:21 +01:00
}
fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
match *nt {
token::NtExpr(ref e) => self.expr_to_string(e),
token::NtMeta(ref e) => self.attr_item_to_string(e),
token::NtTy(ref e) => self.ty_to_string(e),
token::NtPath(ref e) => self.path_to_string(e),
token::NtItem(ref e) => self.item_to_string(e),
token::NtBlock(ref e) => self.block_to_string(e),
token::NtStmt(ref e) => self.stmt_to_string(e),
token::NtPat(ref e) => self.pat_to_string(e),
token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
token::NtLifetime(e) => e.to_string(),
token::NtLiteral(ref e) => self.expr_to_string(e),
token::NtTT(ref tree) => self.tt_to_string(tree),
token::NtVis(ref e) => self.vis_to_string(e),
}
}
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
fn token_kind_to_string(&self, tok: &TokenKind) -> String {
self.token_kind_to_string_ext(tok, None)
}
fn token_kind_to_string_ext(
&self,
tok: &TokenKind,
convert_dollar_crate: Option<Span>,
) -> String {
match *tok {
token::Eq => "=".to_string(),
token::Lt => "<".to_string(),
token::Le => "<=".to_string(),
token::EqEq => "==".to_string(),
token::Ne => "!=".to_string(),
token::Ge => ">=".to_string(),
token::Gt => ">".to_string(),
token::Not => "!".to_string(),
token::Tilde => "~".to_string(),
token::OrOr => "||".to_string(),
token::AndAnd => "&&".to_string(),
token::BinOp(op) => binop_to_string(op).to_string(),
token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
/* Structural symbols */
token::At => "@".to_string(),
token::Dot => ".".to_string(),
token::DotDot => "..".to_string(),
token::DotDotDot => "...".to_string(),
token::DotDotEq => "..=".to_string(),
token::Comma => ",".to_string(),
token::Semi => ";".to_string(),
token::Colon => ":".to_string(),
token::ModSep => "::".to_string(),
token::RArrow => "->".to_string(),
token::LArrow => "<-".to_string(),
token::FatArrow => "=>".to_string(),
token::OpenDelim(token::Paren) => "(".to_string(),
token::CloseDelim(token::Paren) => ")".to_string(),
token::OpenDelim(token::Bracket) => "[".to_string(),
token::CloseDelim(token::Bracket) => "]".to_string(),
token::OpenDelim(token::Brace) => "{".to_string(),
token::CloseDelim(token::Brace) => "}".to_string(),
token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(),
token::Pound => "#".to_string(),
token::Dollar => "$".to_string(),
token::Question => "?".to_string(),
token::SingleQuote => "'".to_string(),
/* Literals */
token::Literal(lit) => literal_to_string(lit),
/* Name components */
token::Ident(s, is_raw) => {
IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string()
}
token::Lifetime(s) => s.to_string(),
/* Other */
token::DocComment(comment_kind, attr_style, data) => {
doc_comment_to_string(comment_kind, attr_style, data)
}
token::Eof => "<eof>".to_string(),
token::Interpolated(ref nt) => self.nonterminal_to_string(nt),
}
}
/// Print the token precisely, without converting `$crate` into its respective crate name.
fn token_to_string(&self, token: &Token) -> String {
self.token_to_string_ext(token, false)
}
fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> String {
let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
}
fn ty_to_string(&self, ty: &ast::Ty) -> String {
self.to_string(|s| s.print_type(ty))
}
fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
self.to_string(|s| s.print_type_bounds("", bounds))
}
fn pat_to_string(&self, pat: &ast::Pat) -> String {
self.to_string(|s| s.print_pat(pat))
}
fn expr_to_string(&self, e: &ast::Expr) -> String {
self.to_string(|s| s.print_expr(e))
}
fn tt_to_string(&self, tt: &TokenTree) -> String {
self.to_string(|s| s.print_tt(tt, false))
}
fn tts_to_string(&self, tokens: &TokenStream) -> String {
self.to_string(|s| s.print_tts(tokens, false))
}
fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
self.to_string(|s| s.print_stmt(stmt))
}
fn item_to_string(&self, i: &ast::Item) -> String {
self.to_string(|s| s.print_item(i))
}
fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
self.to_string(|s| s.print_generic_params(generic_params))
}
fn path_to_string(&self, p: &ast::Path) -> String {
self.to_string(|s| s.print_path(p, false, 0))
}
fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
self.to_string(|s| s.print_path_segment(p, false))
}
fn vis_to_string(&self, v: &ast::Visibility) -> String {
self.to_string(|s| s.print_visibility(v))
}
fn block_to_string(&self, blk: &ast::Block) -> String {
self.to_string(|s| {
// Containing cbox, will be closed by `print_block` at `}`.
s.cbox(INDENT_UNIT);
// Head-ibox, will be closed by `print_block` after `{`.
s.ibox(0);
s.print_block(blk)
})
}
fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
self.to_string(|s| s.print_meta_list_item(li))
}
fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
self.to_string(|s| s.print_attr_item(ai, ai.path.span))
}
fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
self.to_string(|s| s.print_attribute(attr))
}
fn param_to_string(&self, arg: &ast::Param) -> String {
self.to_string(|s| s.print_param(arg, false))
}
fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
let mut printer = State::new();
f(&mut printer);
printer.s.eof()
}
}
impl<'a> PrintState<'a> for State<'a> {
fn comments(&mut self) -> &mut Option<Comments<'a>> {
&mut self.comments
}
2020-04-19 13:00:18 +02:00
fn print_ident(&mut self, ident: Ident) {
2020-02-22 23:29:36 +01:00
self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
self.ann.post(self, AnnNode::Ident(&ident))
}
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
if colons_before_params {
self.s.word("::")
}
match *args {
ast::GenericArgs::AngleBracketed(ref data) => {
self.s.word("<");
self.commasep(Inconsistent, &data.args, |s, arg| match arg {
ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
});
self.s.word(">")
}
ast::GenericArgs::Parenthesized(ref data) => {
self.s.word("(");
2019-12-01 16:00:08 +01:00
self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
self.s.word(")");
2019-12-01 16:00:08 +01:00
self.print_fn_ret_ty(&data.output);
}
}
}
}
impl<'a> State<'a> {
pub fn new() -> State<'a> {
State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
}
2014-03-16 19:58:11 +01:00
// Synthesizes a comment that was not textually present in the original source
// file.
pub fn synth_comment(&mut self, text: String) {
self.s.word("/*");
self.s.space();
self.s.word(text);
self.s.space();
self.s.word("*/")
2014-01-30 02:39:21 +01:00
}
2014-03-16 19:58:11 +01:00
2019-12-22 23:42:04 +01:00
crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
where
F: FnMut(&mut State<'_>, &T),
G: FnMut(&T) -> rustc_span::Span,
2014-12-08 19:28:32 +01:00
{
self.rbox(0, b);
2014-03-16 19:58:11 +01:00
let len = elts.len();
2017-05-16 09:21:30 +02:00
let mut i = 0;
for elt in elts {
self.maybe_print_comment(get_span(elt).hi());
op(self, elt);
2017-05-16 09:21:30 +02:00
i += 1;
2014-03-16 19:58:11 +01:00
if i < len {
self.s.word(",");
2019-12-22 23:42:04 +01:00
self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
self.space_if_not_bol();
2014-03-16 19:58:11 +01:00
}
}
self.end();
}
2019-12-22 23:42:04 +01:00
crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
}
2020-04-27 19:56:11 +02:00
crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
self.print_inner_attributes(attrs);
2015-01-31 18:20:46 +01:00
for item in &nmod.items {
self.print_foreign_item(item);
}
2014-03-16 19:58:11 +01:00
}
pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
if let Some(lt) = *lifetime {
self.print_lifetime(lt);
self.nbsp();
}
}
pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
self.print_ident(constraint.ident);
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
self.s.space();
match &constraint.kind {
ast::AssocTyConstraintKind::Equality { ty } => {
self.word_space("=");
self.print_type(ty);
}
ast::AssocTyConstraintKind::Bound { bounds } => {
self.print_type_bounds(":", &*bounds);
}
}
}
pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
match generic_arg {
GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
2018-05-27 21:07:09 +02:00
GenericArg::Type(ty) => self.print_type(ty),
GenericArg::Const(ct) => self.print_expr(&ct.value),
}
}
pub fn print_type(&mut self, ty: &ast::Ty) {
self.maybe_print_comment(ty.span.lo());
self.ibox(0);
2019-09-26 18:25:31 +02:00
match ty.kind {
ast::TyKind::Slice(ref ty) => {
self.s.word("[");
self.print_type(ty);
self.s.word("]");
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Ptr(ref mt) => {
self.s.word("*");
self.print_mt(mt, true);
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Rptr(ref lifetime, ref mt) => {
self.s.word("&");
self.print_opt_lifetime(lifetime);
self.print_mt(mt, false);
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Never => {
self.s.word("!");
2019-12-22 23:42:04 +01:00
}
ast::TyKind::Tup(ref elts) => {
self.popen();
2019-12-22 23:42:04 +01:00
self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(ty));
2014-03-16 19:58:11 +01:00
if elts.len() == 1 {
self.s.word(",");
2014-03-16 19:58:11 +01:00
}
self.pclose();
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Paren(ref typ) => {
self.popen();
self.print_type(typ);
self.pclose();
}
ast::TyKind::BareFn(ref f) => {
2019-12-22 23:42:04 +01:00
self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Path(None, ref path) => {
self.print_path(path, false, 0);
}
2019-12-22 23:42:04 +01:00
ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
2017-10-10 16:33:19 +02:00
ast::TyKind::TraitObject(ref bounds, syntax) => {
let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
self.print_type_bounds(prefix, &bounds[..]);
2014-11-07 12:53:45 +01:00
}
ast::TyKind::ImplTrait(_, ref bounds) => {
self.print_type_bounds("impl", &bounds[..]);
}
ast::TyKind::Array(ref ty, ref length) => {
self.s.word("[");
self.print_type(ty);
self.s.word("; ");
self.print_expr(&length.value);
self.s.word("]");
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Typeof(ref e) => {
self.s.word("typeof(");
self.print_expr(&e.value);
self.s.word(")");
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Infer => {
self.s.word("_");
2014-03-16 19:58:11 +01:00
}
ast::TyKind::Err => {
self.popen();
self.s.word("/*ERROR*/");
self.pclose();
}
ast::TyKind::ImplicitSelf => {
self.s.word("Self");
}
2020-02-29 17:32:20 +01:00
ast::TyKind::MacCall(ref m) => {
self.print_mac(m);
}
ast::TyKind::CVarArgs => {
self.s.word("...");
}
2014-03-16 19:58:11 +01:00
}
self.end();
2014-03-16 19:58:11 +01:00
}
2019-12-22 23:42:04 +01:00
crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
self.ann.pre(self, AnnNode::SubItem(id));
self.hardbreak_if_not_bol();
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
2021-01-29 08:31:08 +01:00
ast::ForeignItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
2014-03-16 19:58:11 +01:00
}
ast::ForeignItemKind::Static(ty, mutbl, body) => {
let def = ast::Defaultness::Final;
self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
2014-03-16 19:58:11 +01:00
}
2021-01-29 08:31:08 +01:00
ast::ForeignItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
2017-09-03 20:53:58 +02:00
}
2020-02-29 17:32:20 +01:00
ast::ForeignItemKind::MacCall(m) => {
self.print_mac(m);
if m.args.need_semicolon() {
self.s.word(";");
}
}
2014-03-16 19:58:11 +01:00
}
self.ann.post(self, AnnNode::SubItem(id))
2014-03-16 19:58:11 +01:00
}
fn print_item_const(
2019-12-22 23:42:04 +01:00
&mut self,
2020-04-19 13:00:18 +02:00
ident: Ident,
mutbl: Option<ast::Mutability>,
2019-12-22 23:42:04 +01:00
ty: &ast::Ty,
body: Option<&ast::Expr>,
2019-12-22 23:42:04 +01:00
vis: &ast::Visibility,
defaultness: ast::Defaultness,
2019-12-22 23:42:04 +01:00
) {
self.head("");
self.print_visibility(vis);
self.print_defaultness(defaultness);
let leading = match mutbl {
None => "const",
Some(ast::Mutability::Not) => "static",
Some(ast::Mutability::Mut) => "static mut",
};
self.word_space(leading);
self.print_ident(ident);
self.word_space(":");
self.print_type(ty);
self.s.space();
self.end(); // end the head-ibox
if let Some(body) = body {
self.word_space("=");
self.print_expr(body);
}
self.s.word(";");
self.end(); // end the outer cbox
}
fn print_associated_type(
&mut self,
2020-04-19 13:00:18 +02:00
ident: Ident,
generics: &ast::Generics,
bounds: &ast::GenericBounds,
ty: Option<&ast::Ty>,
vis: &ast::Visibility,
defaultness: ast::Defaultness,
) {
self.head("");
self.print_visibility(vis);
self.print_defaultness(defaultness);
self.word_space("type");
self.print_ident(ident);
self.print_generic_params(&generics.params);
self.print_type_bounds(":", bounds);
self.print_where_clause(&generics.where_clause);
if let Some(ty) = ty {
self.s.space();
self.word_space("=");
self.print_type(ty);
}
self.s.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
/// Pretty-prints an item.
crate fn print_item(&mut self, item: &ast::Item) {
self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(&item.attrs);
self.ann.pre(self, AnnNode::Item(item));
2019-09-26 18:51:36 +02:00
match item.kind {
ast::ItemKind::ExternCrate(orig_name) => {
self.head(visibility_qualified(&item.vis, "extern crate"));
if let Some(orig_name) = orig_name {
self.print_name(orig_name);
self.s.space();
self.s.word("as");
self.s.space();
}
self.print_ident(item.ident);
self.s.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
ast::ItemKind::Use(ref tree) => {
self.head(visibility_qualified(&item.vis, "use"));
self.print_use_tree(tree);
self.s.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
ast::ItemKind::Static(ref ty, mutbl, ref body) => {
let def = ast::Defaultness::Final;
self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
2014-03-16 19:58:11 +01:00
}
ast::ItemKind::Const(def, ref ty, ref body) => {
self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
rustc: Add `const` globals to the language This change is an implementation of [RFC 69][rfc] which adds a third kind of global to the language, `const`. This global is most similar to what the old `static` was, and if you're unsure about what to use then you should use a `const`. The semantics of these three kinds of globals are: * A `const` does not represent a memory location, but only a value. Constants are translated as rvalues, which means that their values are directly inlined at usage location (similar to a #define in C/C++). Constant values are, well, constant, and can not be modified. Any "modification" is actually a modification to a local value on the stack rather than the actual constant itself. Almost all values are allowed inside constants, whether they have interior mutability or not. There are a few minor restrictions listed in the RFC, but they should in general not come up too often. * A `static` now always represents a memory location (unconditionally). Any references to the same `static` are actually a reference to the same memory location. Only values whose types ascribe to `Sync` are allowed in a `static`. This restriction is in place because many threads may access a `static` concurrently. Lifting this restriction (and allowing unsafe access) is a future extension not implemented at this time. * A `static mut` continues to always represent a memory location. All references to a `static mut` continue to be `unsafe`. This is a large breaking change, and many programs will need to be updated accordingly. A summary of the breaking changes is: * Statics may no longer be used in patterns. Statics now always represent a memory location, which can sometimes be modified. To fix code, repurpose the matched-on-`static` to a `const`. static FOO: uint = 4; match n { FOO => { /* ... */ } _ => { /* ... */ } } change this code to: const FOO: uint = 4; match n { FOO => { /* ... */ } _ => { /* ... */ } } * Statics may no longer refer to other statics by value. Due to statics being able to change at runtime, allowing them to reference one another could possibly lead to confusing semantics. If you are in this situation, use a constant initializer instead. Note, however, that statics may reference other statics by address, however. * Statics may no longer be used in constant expressions, such as array lengths. This is due to the same restrictions as listed above. Use a `const` instead. [breaking-change] [rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 17:17:01 +02:00
}
2021-01-29 08:31:08 +01:00
ast::ItemKind::Fn(box ast::FnKind(def, ref sig, ref gen, ref body)) => {
let body = body.as_deref();
self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
2014-03-16 19:58:11 +01:00
}
ast::ItemKind::Mod(unsafety, ref mod_kind) => {
self.head(self.to_string(|s| {
2020-08-23 12:42:19 +02:00
s.print_visibility(&item.vis);
s.print_unsafety(unsafety);
2020-08-23 12:42:19 +02:00
s.word("mod");
}));
self.print_ident(item.ident);
match mod_kind {
ModKind::Loaded(items, ..) => {
self.nbsp();
self.bopen();
self.print_inner_attributes(&item.attrs);
for item in items {
self.print_item(item);
}
self.bclose(item.span);
}
ModKind::Unloaded => {
self.s.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
}
}
2014-03-16 19:58:11 +01:00
}
ast::ItemKind::ForeignMod(ref nmod) => {
self.head(self.to_string(|s| {
2020-08-23 12:42:19 +02:00
s.print_unsafety(nmod.unsafety);
s.word("extern");
}));
if let Some(abi) = nmod.abi {
self.print_literal(&abi.as_lit());
self.nbsp();
}
self.bopen();
self.print_foreign_mod(nmod, &item.attrs);
self.bclose(item.span);
2014-03-16 19:58:11 +01:00
}
2017-03-16 03:27:40 +01:00
ast::ItemKind::GlobalAsm(ref ga) => {
self.head(visibility_qualified(&item.vis, "global_asm!"));
self.s.word(ga.asm.to_string());
self.end();
2017-03-16 03:27:40 +01:00
}
2021-01-29 08:31:08 +01:00
ast::ItemKind::TyAlias(box ast::TyAliasKind(def, ref generics, ref bounds, ref ty)) => {
let ty = ty.as_deref();
self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
2014-03-16 19:58:11 +01:00
}
ast::ItemKind::Enum(ref enum_definition, ref params) => {
2019-12-22 23:42:04 +01:00
self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
2014-03-16 19:58:11 +01:00
}
ast::ItemKind::Struct(ref struct_def, ref generics) => {
self.head(visibility_qualified(&item.vis, "struct"));
self.print_struct(struct_def, generics, item.ident, item.span, true);
2014-03-16 19:58:11 +01:00
}
2016-08-29 07:04:31 +02:00
ast::ItemKind::Union(ref struct_def, ref generics) => {
self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, item.ident, item.span, true);
2016-08-29 07:04:31 +02:00
}
2021-01-29 08:31:08 +01:00
ast::ItemKind::Impl(box ast::ImplKind {
2019-12-22 23:42:04 +01:00
unsafety,
polarity,
defaultness,
constness,
2019-12-22 23:42:04 +01:00
ref generics,
ref of_trait,
ref self_ty,
ref items,
2021-01-29 08:31:08 +01:00
}) => {
self.head("");
self.print_visibility(&item.vis);
self.print_defaultness(defaultness);
self.print_unsafety(unsafety);
self.word_nbsp("impl");
self.print_constness(constness);
if !generics.params.is_empty() {
self.print_generic_params(&generics.params);
self.s.space();
2014-03-16 19:58:11 +01:00
}
if let ast::ImplPolarity::Negative(_) = polarity {
self.s.word("!");
}
if let Some(ref t) = *of_trait {
self.print_trait_ref(t);
self.s.space();
self.word_space("for");
2014-03-16 19:58:11 +01:00
}
self.print_type(self_ty);
self.print_where_clause(&generics.where_clause);
self.s.space();
self.bopen();
self.print_inner_attributes(&item.attrs);
for impl_item in items {
2019-12-01 16:15:10 +01:00
self.print_assoc_item(impl_item);
2014-03-16 19:58:11 +01:00
}
self.bclose(item.span);
2014-03-16 19:58:11 +01:00
}
2021-01-29 08:31:08 +01:00
ast::ItemKind::Trait(box ast::TraitKind(
is_auto,
unsafety,
ref generics,
ref bounds,
ref trait_items,
)) => {
self.head("");
self.print_visibility(&item.vis);
self.print_unsafety(unsafety);
self.print_is_auto(is_auto);
self.word_nbsp("trait");
self.print_ident(item.ident);
self.print_generic_params(&generics.params);
2014-12-24 10:34:57 +01:00
let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds.iter() {
2018-06-14 13:23:46 +02:00
if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
self.s.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
2014-12-24 10:34:57 +01:00
} else {
real_bounds.push(b.clone());
2014-12-24 10:34:57 +01:00
}
}
self.print_type_bounds(":", &real_bounds[..]);
self.print_where_clause(&generics.where_clause);
self.s.word(" ");
self.bopen();
self.print_inner_attributes(&item.attrs);
for trait_item in trait_items {
2019-12-01 16:15:10 +01:00
self.print_assoc_item(trait_item);
2014-03-16 19:58:11 +01:00
}
self.bclose(item.span);
2014-03-16 19:58:11 +01:00
}
2017-10-02 14:27:45 +02:00
ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
self.head("");
self.print_visibility(&item.vis);
self.word_nbsp("trait");
self.print_ident(item.ident);
self.print_generic_params(&generics.params);
2017-10-02 14:27:45 +02:00
let mut real_bounds = Vec::with_capacity(bounds.len());
// FIXME(durka) this seems to be some quite outdated syntax
for b in bounds.iter() {
2018-06-14 13:23:46 +02:00
if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
self.s.space();
self.word_space("for ?");
self.print_trait_ref(&ptr.trait_ref);
2017-10-02 14:27:45 +02:00
} else {
real_bounds.push(b.clone());
}
}
self.nbsp();
self.print_type_bounds("=", &real_bounds[..]);
self.print_where_clause(&generics.where_clause);
self.s.word(";");
2017-10-02 14:27:45 +02:00
}
2020-02-29 17:32:20 +01:00
ast::ItemKind::MacCall(ref mac) => {
self.print_mac(mac);
if mac.args.need_semicolon() {
self.s.word(";");
}
2014-03-16 19:58:11 +01:00
}
ast::ItemKind::MacroDef(ref macro_def) => {
let (kw, has_bang) = if macro_def.macro_rules {
2019-07-14 21:16:16 +02:00
("macro_rules", true)
} else {
self.print_visibility(&item.vis);
("macro", false)
};
self.print_mac_common(
2019-07-14 15:09:39 +02:00
Some(MacHeader::Keyword(kw)),
has_bang,
Some(item.ident),
macro_def.body.delim(),
&macro_def.body.inner_tokens(),
true,
item.span,
);
if macro_def.body.need_semicolon() {
self.word(";");
}
}
2014-03-16 19:58:11 +01:00
}
2018-08-22 23:05:19 +02:00
self.ann.post(self, AnnNode::Item(item))
2014-03-16 19:58:11 +01:00
}
fn print_trait_ref(&mut self, t: &ast::TraitRef) {
self.print_path(&t.path, false, 0)
2014-03-16 19:58:11 +01:00
}
2019-12-22 23:42:04 +01:00
fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
if !generic_params.is_empty() {
self.s.word("for");
self.print_generic_params(generic_params);
self.nbsp();
2014-11-07 12:53:45 +01:00
}
2015-02-09 04:49:27 +01:00
}
2014-11-07 12:53:45 +01:00
fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
self.print_formal_generic_params(&t.bound_generic_params);
2014-11-07 12:53:45 +01:00
self.print_trait_ref(&t.trait_ref)
}
2019-12-22 23:42:04 +01:00
crate fn print_enum_def(
&mut self,
enum_definition: &ast::EnumDef,
generics: &ast::Generics,
2020-04-19 13:00:18 +02:00
ident: Ident,
span: rustc_span::Span,
2019-12-22 23:42:04 +01:00
visibility: &ast::Visibility,
) {
self.head(visibility_qualified(visibility, "enum"));
self.print_ident(ident);
self.print_generic_params(&generics.params);
self.print_where_clause(&generics.where_clause);
self.s.space();
2015-02-19 00:58:07 +01:00
self.print_variants(&enum_definition.variants, span)
2014-03-16 19:58:11 +01:00
}
crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
self.bopen();
2015-01-31 18:20:46 +01:00
for v in variants {
self.space_if_not_bol();
self.maybe_print_comment(v.span.lo());
2019-08-14 02:40:21 +02:00
self.print_outer_attributes(&v.attrs);
self.ibox(INDENT_UNIT);
self.print_variant(v);
self.s.word(",");
self.end();
self.maybe_print_trailing_comment(v.span, None);
2014-03-16 19:58:11 +01:00
}
self.bclose(span)
}
crate fn print_visibility(&mut self, vis: &ast::Visibility) {
match vis.kind {
2018-01-29 06:12:09 +01:00
ast::VisibilityKind::Public => self.word_nbsp("pub"),
ast::VisibilityKind::Crate(sugar) => match sugar {
ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
2019-12-22 23:42:04 +01:00
ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
},
2018-01-29 06:12:09 +01:00
ast::VisibilityKind::Restricted { ref path, .. } => {
let path = self.to_string(|s| s.print_path(path, false, 0));
if path == "self" || path == "super" {
self.word_nbsp(format!("pub({})", path))
} else {
self.word_nbsp(format!("pub(in {})", path))
}
}
ast::VisibilityKind::Inherited => {}
2014-03-16 19:58:11 +01:00
}
}
crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
if let ast::Defaultness::Default(_) = defaultness {
self.word_nbsp("default");
}
}
2019-12-22 23:42:04 +01:00
crate fn print_struct(
&mut self,
struct_def: &ast::VariantData,
generics: &ast::Generics,
2020-04-19 13:00:18 +02:00
ident: Ident,
span: rustc_span::Span,
2019-12-22 23:42:04 +01:00
print_finalizer: bool,
) {
self.print_ident(ident);
self.print_generic_params(&generics.params);
match struct_def {
ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
if let ast::VariantData::Tuple(..) = struct_def {
self.popen();
2019-12-22 23:42:04 +01:00
self.commasep(Inconsistent, struct_def.fields(), |s, field| {
s.maybe_print_comment(field.span.lo());
s.print_outer_attributes(&field.attrs);
s.print_visibility(&field.vis);
s.print_type(&field.ty)
});
self.pclose();
}
self.print_where_clause(&generics.where_clause);
if print_finalizer {
self.s.word(";");
}
self.end();
self.end(); // Close the outer-box.
}
ast::VariantData::Struct(..) => {
self.print_where_clause(&generics.where_clause);
self.nbsp();
self.bopen();
self.hardbreak_if_not_bol();
for field in struct_def.fields() {
self.hardbreak_if_not_bol();
self.maybe_print_comment(field.span.lo());
self.print_outer_attributes(&field.attrs);
self.print_visibility(&field.vis);
self.print_ident(field.ident.unwrap());
self.word_nbsp(":");
self.print_type(&field.ty);
self.s.word(",");
}
self.bclose(span)
}
2014-03-16 19:58:11 +01:00
}
}
crate fn print_variant(&mut self, v: &ast::Variant) {
self.head("");
self.print_visibility(&v.vis);
let generics = ast::Generics::default();
2019-08-14 02:40:21 +02:00
self.print_struct(&v.data, &generics, v.ident, v.span, false);
if let Some(ref d) = v.disr_expr {
self.s.space();
self.word_space("=");
self.print_expr(&d.value)
2014-03-16 19:58:11 +01:00
}
}
2019-12-01 16:15:10 +01:00
crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
self.ann.pre(self, AnnNode::SubItem(id));
self.hardbreak_if_not_bol();
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
2021-01-29 08:31:08 +01:00
ast::AssocItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
}
ast::AssocItemKind::Const(def, ty, body) => {
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
}
2021-01-29 08:31:08 +01:00
ast::AssocItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
}
2020-02-29 17:32:20 +01:00
ast::AssocItemKind::MacCall(m) => {
self.print_mac(m);
if m.args.need_semicolon() {
self.s.word(";");
}
}
}
self.ann.post(self, AnnNode::SubItem(id))
2014-03-16 19:58:11 +01:00
}
crate fn print_stmt(&mut self, st: &ast::Stmt) {
self.maybe_print_comment(st.span.lo());
2019-09-26 18:34:50 +02:00
match st.kind {
2016-06-17 04:30:01 +02:00
ast::StmtKind::Local(ref loc) => {
self.print_outer_attributes(&loc.attrs);
self.space_if_not_bol();
self.ibox(INDENT_UNIT);
self.word_nbsp("let");
self.ibox(INDENT_UNIT);
self.print_local_decl(loc);
self.end();
2016-06-17 04:30:01 +02:00
if let Some(ref init) = loc.init {
self.nbsp();
self.word_space("=");
self.print_expr(init);
2016-06-17 04:30:01 +02:00
}
self.s.word(";");
self.end();
2014-03-16 19:58:11 +01:00
}
ast::StmtKind::Item(ref item) => self.print_item(item),
2016-06-17 04:30:01 +02:00
ast::StmtKind::Expr(ref expr) => {
self.space_if_not_bol();
self.print_expr_outer_attr_style(expr, false);
2019-10-11 13:17:20 +02:00
if classify::expr_requires_semi_to_be_stmt(expr) {
self.s.word(";");
}
2014-03-16 19:58:11 +01:00
}
2016-06-17 04:30:01 +02:00
ast::StmtKind::Semi(ref expr) => {
self.space_if_not_bol();
self.print_expr_outer_attr_style(expr, false);
self.s.word(";");
}
ast::StmtKind::Empty => {
self.space_if_not_bol();
self.s.word(";");
2014-03-16 19:58:11 +01:00
}
2020-02-29 17:32:20 +01:00
ast::StmtKind::MacCall(ref mac) => {
self.space_if_not_bol();
self.print_outer_attributes(&mac.attrs);
self.print_mac(&mac.mac);
if mac.style == ast::MacStmtStyle::Semicolon {
self.s.word(";");
2014-03-16 19:58:11 +01:00
}
}
}
2014-03-16 19:58:11 +01:00
self.maybe_print_trailing_comment(st.span, None)
}
crate fn print_block(&mut self, blk: &ast::Block) {
2014-03-16 19:58:11 +01:00
self.print_block_with_attrs(blk, &[])
}
crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
self.print_block_maybe_unclosed(blk, &[], false)
2014-03-16 19:58:11 +01:00
}
2011-08-15 23:42:33 +02:00
2019-12-22 23:42:04 +01:00
crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
self.print_block_maybe_unclosed(blk, attrs, true)
2014-03-16 19:58:11 +01:00
}
2019-12-22 23:42:04 +01:00
crate fn print_block_maybe_unclosed(
&mut self,
blk: &ast::Block,
attrs: &[ast::Attribute],
close_box: bool,
) {
2014-03-16 19:58:11 +01:00
match blk.rules {
BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
2019-12-22 23:42:04 +01:00
BlockCheckMode::Default => (),
2014-03-16 19:58:11 +01:00
}
self.maybe_print_comment(blk.span.lo());
self.ann.pre(self, AnnNode::Block(blk));
self.bopen();
2014-03-16 19:58:11 +01:00
self.print_inner_attributes(attrs);
2014-03-16 19:58:11 +01:00
for (i, st) in blk.stmts.iter().enumerate() {
2019-09-26 18:34:50 +02:00
match st.kind {
ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
self.maybe_print_comment(st.span.lo());
self.space_if_not_bol();
self.print_expr_outer_attr_style(expr, false);
self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
}
_ => self.print_stmt(st),
2014-03-16 19:58:11 +01:00
}
}
self.bclose_maybe_open(blk.span, close_box);
2018-08-22 23:05:19 +02:00
self.ann.post(self, AnnNode::Block(blk))
2014-03-16 19:58:11 +01:00
}
/// Print a `let pat = scrutinee` expression.
crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
self.s.word("let ");
self.print_pat(pat);
self.s.space();
self.word_space("=");
self.print_expr_cond_paren(
scrutinee,
Self::cond_needs_par(scrutinee)
2019-12-22 23:42:04 +01:00
|| parser::needs_par_as_let_scrutinee(scrutinee.precedence().order()),
)
}
fn print_else(&mut self, els: Option<&ast::Expr>) {
if let Some(_else) = els {
match _else.kind {
// Another `else if` block.
ast::ExprKind::If(ref i, ref then, ref e) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
self.s.word(" else if ");
self.print_expr_as_cond(i);
self.s.space();
self.print_block(then);
2020-01-22 01:38:05 +01:00
self.print_else(e.as_deref())
}
// Final `else` block.
ast::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1);
self.ibox(0);
self.s.word(" else ");
self.print_block(b)
}
// Constraints would be great here!
_ => {
panic!("print_if saw if with weird alternative");
2014-01-30 02:39:21 +01:00
}
2011-06-16 23:08:17 +02:00
}
}
}
2019-12-22 23:42:04 +01:00
crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
self.head("if");
self.print_expr_as_cond(test);
self.s.space();
self.print_block(blk);
2014-08-25 03:04:29 +02:00
self.print_else(elseopt)
}
2020-02-29 17:32:20 +01:00
crate fn print_mac(&mut self, m: &ast::MacCall) {
self.print_mac_common(
2019-08-15 01:13:53 +02:00
Some(MacHeader::Path(&m.path)),
2019-07-14 15:09:39 +02:00
true,
None,
m.args.delim(),
&m.args.inner_tokens(),
2019-07-14 15:09:39 +02:00
true,
m.span(),
);
}
fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
self.popen();
self.commasep_exprs(Inconsistent, args);
2014-03-16 19:58:11 +01:00
self.pclose()
}
crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
}
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
2017-07-20 22:53:56 +02:00
/// `if cond { ... }`.
crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
}
/// Does `expr` need parenthesis when printed in a condition position?
fn cond_needs_par(expr: &ast::Expr) -> bool {
match expr.kind {
2017-07-20 22:53:56 +02:00
// These cases need parens due to the parse error observed in #26461: `if return {}`
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
2019-12-22 23:42:04 +01:00
ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Break(..) => true,
2017-07-20 22:53:56 +02:00
_ => parser::contains_exterior_struct_lit(expr),
}
}
2017-07-20 22:53:56 +02:00
/// Prints `expr` or `(expr)` when `needs_par` holds.
fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
if needs_par {
self.popen();
}
self.print_expr(expr);
if needs_par {
self.pclose();
}
}
2020-04-27 19:56:11 +02:00
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
self.ibox(INDENT_UNIT);
self.s.word("[");
self.print_inner_attributes_inline(attrs);
self.commasep_exprs(Inconsistent, exprs);
self.s.word("]");
self.end();
}
2020-09-21 22:55:58 +02:00
fn print_expr_anon_const(&mut self, expr: &ast::AnonConst, attrs: &[ast::Attribute]) {
self.ibox(INDENT_UNIT);
self.s.word("const");
self.print_inner_attributes_inline(attrs);
self.print_expr(&expr.value);
self.end();
}
2019-12-22 23:42:04 +01:00
fn print_expr_repeat(
&mut self,
element: &ast::Expr,
count: &ast::AnonConst,
2020-04-27 19:56:11 +02:00
attrs: &[ast::Attribute],
2019-12-22 23:42:04 +01:00
) {
self.ibox(INDENT_UNIT);
self.s.word("[");
self.print_inner_attributes_inline(attrs);
self.print_expr(element);
self.word_space(";");
self.print_expr(&count.value);
self.s.word("]");
self.end();
}
2019-12-22 23:42:04 +01:00
fn print_expr_struct(
&mut self,
path: &ast::Path,
fields: &[ast::ExprField],
rest: &ast::StructRest,
2020-04-27 19:56:11 +02:00
attrs: &[ast::Attribute],
2019-12-22 23:42:04 +01:00
) {
self.print_path(path, true, 0);
self.s.word("{");
self.print_inner_attributes_inline(attrs);
self.commasep_cmnt(
Consistent,
fields,
|s, field| {
2020-02-01 18:45:03 +01:00
s.print_outer_attributes(&field.attrs);
s.ibox(INDENT_UNIT);
if !field.is_shorthand {
s.print_ident(field.ident);
s.word_space(":");
}
s.print_expr(&field.expr);
s.end();
},
2019-12-22 23:42:04 +01:00
|f| f.span,
);
match rest {
ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
self.ibox(INDENT_UNIT);
if !fields.is_empty() {
self.s.word(",");
self.s.space();
}
self.s.word("..");
if let ast::StructRest::Base(ref expr) = *rest {
self.print_expr(expr);
2019-12-22 23:42:04 +01:00
}
self.end();
}
ast::StructRest::None if !fields.is_empty() => self.s.word(","),
_ => {}
}
self.s.word("}");
}
2020-04-27 19:56:11 +02:00
fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
self.popen();
self.print_inner_attributes_inline(attrs);
self.commasep_exprs(Inconsistent, exprs);
if exprs.len() == 1 {
self.s.word(",");
}
self.pclose()
}
2019-12-22 23:42:04 +01:00
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
let prec = match func.kind {
ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
_ => parser::PREC_POSTFIX,
};
2017-07-20 22:53:56 +02:00
self.print_expr_maybe_paren(func, prec);
self.print_call_post(args)
}
2019-12-22 23:42:04 +01:00
fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
2015-01-18 01:15:52 +01:00
let base_args = &args[1..];
self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
self.s.word(".");
self.print_ident(segment.ident);
2018-02-23 18:48:54 +01:00
if let Some(ref args) = segment.args {
self.print_generic_args(args, true);
}
self.print_call_post(base_args)
}
2019-12-22 23:42:04 +01:00
fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
2017-07-20 22:53:56 +02:00
let assoc_op = AssocOp::from_ast_binop(op.node);
let prec = assoc_op.precedence() as i8;
let fixity = assoc_op.fixity();
let (left_prec, right_prec) = match fixity {
Fixity::Left => (prec, prec + 1),
Fixity::Right => (prec + 1, prec),
Fixity::None => (prec + 1, prec + 1),
};
let left_prec = match (&lhs.kind, op.node) {
// These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
// the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
(&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
parser::PREC_FORCE_PAREN
}
// We are given `(let _ = a) OP b`.
//
// - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
// as the parser will interpret this as `(let _ = a) OP b`.
//
// - Otherwise, e.g. when we have `(let a = b) < c` in AST,
// parens are required since the parser would interpret `let a = b < c` as
// `let a = (b < c)`. To achieve this, we force parens.
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
parser::PREC_FORCE_PAREN
}
_ => left_prec,
};
self.print_expr_maybe_paren(lhs, left_prec);
self.s.space();
self.word_space(op.node.to_string());
2017-07-20 22:53:56 +02:00
self.print_expr_maybe_paren(rhs, right_prec)
}
2019-12-22 23:42:04 +01:00
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
self.s.word(ast::UnOp::to_string(op));
2017-07-20 22:53:56 +02:00
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
}
2019-12-22 23:42:04 +01:00
fn print_expr_addr_of(
&mut self,
kind: ast::BorrowKind,
mutability: ast::Mutability,
expr: &ast::Expr,
) {
self.s.word("&");
match kind {
ast::BorrowKind::Ref => self.print_mutability(mutability, false),
ast::BorrowKind::Raw => {
self.word_nbsp("raw");
self.print_mutability(mutability, true);
}
}
2017-07-20 22:53:56 +02:00
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
}
pub fn print_expr(&mut self, expr: &ast::Expr) {
self.print_expr_outer_attr_style(expr, true)
}
2019-12-22 23:42:04 +01:00
fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
self.maybe_print_comment(expr.span.lo());
let attrs = &expr.attrs;
if is_inline {
self.print_outer_attributes_inline(attrs);
} else {
self.print_outer_attributes(attrs);
}
self.ibox(INDENT_UNIT);
self.ann.pre(self, AnnNode::Expr(expr));
match expr.kind {
ast::ExprKind::Box(ref expr) => {
self.word_space("box");
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
}
ast::ExprKind::Array(ref exprs) => {
self.print_expr_vec(&exprs[..], attrs);
2014-03-16 19:58:11 +01:00
}
2020-09-21 22:55:58 +02:00
ast::ExprKind::ConstBlock(ref anon_const) => {
self.print_expr_anon_const(anon_const, attrs);
}
ast::ExprKind::Repeat(ref element, ref count) => {
self.print_expr_repeat(element, count, attrs);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Struct(ref path, ref fields, ref rest) => {
self.print_expr_struct(path, &fields[..], rest, attrs);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Tup(ref exprs) => {
self.print_expr_tup(&exprs[..], attrs);
}
ast::ExprKind::Call(ref func, ref args) => {
self.print_expr_call(func, &args[..]);
}
ast::ExprKind::MethodCall(ref segment, ref args, _) => {
self.print_expr_method_call(segment, &args[..]);
}
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
self.print_expr_binary(op, lhs, rhs);
}
ast::ExprKind::Unary(op, ref expr) => {
self.print_expr_unary(op, expr);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::AddrOf(k, m, ref expr) => {
self.print_expr_addr_of(k, m, expr);
}
ast::ExprKind::Lit(ref lit) => {
self.print_literal(lit);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Cast(ref expr, ref ty) => {
2017-07-20 22:53:56 +02:00
let prec = AssocOp::As.precedence() as i8;
self.print_expr_maybe_paren(expr, prec);
self.s.space();
self.word_space("as");
self.print_type(ty);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Type(ref expr, ref ty) => {
2017-07-20 22:53:56 +02:00
let prec = AssocOp::Colon.precedence() as i8;
self.print_expr_maybe_paren(expr, prec);
self.word_space(":");
self.print_type(ty);
2015-02-01 08:59:46 +01:00
}
ast::ExprKind::Let(ref pat, ref scrutinee) => {
self.print_let(pat, scrutinee);
}
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
2020-01-22 01:38:05 +01:00
self.print_if(test, blk, elseopt.as_deref())
2014-08-25 03:04:29 +02:00
}
ast::ExprKind::While(ref test, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
2014-07-26 02:12:51 +02:00
}
self.head("while");
self.print_expr_as_cond(test);
self.s.space();
self.print_block_with_attrs(blk, attrs);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
2014-03-16 19:58:11 +01:00
}
self.head("for");
self.print_pat(pat);
self.s.space();
self.word_space("in");
self.print_expr_as_cond(iter);
self.s.space();
self.print_block_with_attrs(blk, attrs);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Loop(ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
2014-03-16 19:58:11 +01:00
}
self.head("loop");
self.s.space();
self.print_block_with_attrs(blk, attrs);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Match(ref expr, ref arms) => {
self.cbox(INDENT_UNIT);
2019-07-09 15:49:37 +02:00
self.ibox(INDENT_UNIT);
self.word_nbsp("match");
self.print_expr_as_cond(expr);
self.s.space();
self.bopen();
self.print_inner_attributes_no_trailing_hardbreak(attrs);
2015-01-31 18:20:46 +01:00
for arm in arms {
self.print_arm(arm);
2014-03-16 19:58:11 +01:00
}
2019-07-09 13:38:31 +02:00
self.bclose(expr.span);
2014-03-16 19:58:11 +01:00
}
2018-06-07 00:50:59 +02:00
ast::ExprKind::Closure(
2019-12-22 23:42:04 +01:00
capture_clause,
asyncness,
movability,
ref decl,
ref body,
_,
) => {
self.print_movability(movability);
self.print_asyncness(asyncness);
self.print_capture_clause(capture_clause);
2019-12-01 16:00:08 +01:00
self.print_fn_params_and_ret(decl, true);
self.s.space();
self.print_expr(body);
self.end(); // need to close a box
2016-06-23 11:51:18 +02:00
2014-03-16 19:58:11 +01:00
// a box will be closed by print_expr, but we didn't want an overall
// wrapper so we closed the corresponding opening. so create an
// empty box to satisfy the close.
self.ibox(0);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Block(ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
}
2014-03-16 19:58:11 +01:00
// containing cbox, will be closed by print-block at }
self.cbox(INDENT_UNIT);
2014-03-16 19:58:11 +01:00
// head-box, will be closed by print-block after {
self.ibox(0);
self.print_block_with_attrs(blk, attrs);
2014-03-16 19:58:11 +01:00
}
2018-06-07 00:50:59 +02:00
ast::ExprKind::Async(capture_clause, _, ref blk) => {
self.word_nbsp("async");
self.print_capture_clause(capture_clause);
self.s.space();
abolish ICE when pretty-printing async block Joshua Netterfield reported an ICE when the unused-parentheses lint triggered around an async block (#54752). In order to compose an autofixable suggestion, the lint invokes the pretty-printer on the unnecessarily-parenthesized expression. (One wonders why the lint doesn't just use `SourceMap::span_to_snippet` instead, to preserve the formatting of the original source?—but for that, you'd have to ask the author of 5c9f806d.) But then the pretty-printer panics when trying to call `<pprust::State as PrintState>::end` when `State.boxes` is empty. Empirically, the problem would seem to be solved if we start some "boxes" beforehand in the `ast::ExprKind::Async` arm of the big match in `print_expr_outer_attr_style`, exactly like we do in the immediately-preceding match arm for `ast::ExprKind::Block`—it would seem pretty ("pretty") reasonable for the pretty-printing of async blocks to work a lot like the pretty-printing of ordinary non-async blocks, right?? Of course, it would be shamefully cargo-culty to commit code on the basis of this kind of mere reasoning-by-analogy (in contrast to understanding the design of the pretty-printer in such detail that the correctness of the patch is comprehended with all the lucid certainty of mathematical proof, rather than being merely surmised by intuition). But maybe we care more about fixing the bug with high probability today, than with certainty in some indefinite hypothetical future? Maybe the effort is worth a fifth of a shirt?? Humbly resolves #54752.
2018-10-03 06:43:05 +02:00
// cbox/ibox in analogy to the `ExprKind::Block` arm above
self.cbox(INDENT_UNIT);
self.ibox(0);
self.print_block_with_attrs(blk, attrs);
2018-06-07 00:50:59 +02:00
}
2019-07-02 06:30:21 +02:00
ast::ExprKind::Await(ref expr) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
self.s.word(".await");
}
ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
2017-07-20 22:53:56 +02:00
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(lhs, prec + 1);
self.s.space();
self.word_space("=");
self.print_expr_maybe_paren(rhs, prec);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
2017-07-20 22:53:56 +02:00
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(lhs, prec + 1);
self.s.space();
self.s.word(op.node.to_string());
self.word_space("=");
self.print_expr_maybe_paren(rhs, prec);
2014-03-16 19:58:11 +01:00
}
2018-03-18 14:47:09 +01:00
ast::ExprKind::Field(ref expr, ident) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
self.s.word(".");
self.print_ident(ident);
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Index(ref expr, ref index) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
self.s.word("[");
self.print_expr(index);
self.s.word("]");
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Range(ref start, ref end, limits) => {
2017-07-20 22:53:56 +02:00
// Special case for `Range`. `AssocOp` claims that `Range` has higher precedence
// than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
// Here we use a fake precedence value so that any child with lower precedence than
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
let fake_prec = AssocOp::LOr.precedence() as i8;
if let Some(ref e) = *start {
self.print_expr_maybe_paren(e, fake_prec);
}
2016-01-13 07:23:31 +01:00
if limits == ast::RangeLimits::HalfOpen {
self.s.word("..");
2016-01-13 07:23:31 +01:00
} else {
self.s.word("..=");
2016-01-13 07:23:31 +01:00
}
if let Some(ref e) = *end {
self.print_expr_maybe_paren(e, fake_prec);
}
2014-12-13 06:41:02 +01:00
}
ast::ExprKind::Underscore => self.s.word("_"),
2019-12-22 23:42:04 +01:00
ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
ast::ExprKind::Break(opt_label, ref opt_expr) => {
self.s.word("break");
self.s.space();
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.s.space();
2014-03-16 19:58:11 +01:00
}
if let Some(ref expr) = *opt_expr {
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
self.s.space();
}
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::Continue(opt_label) => {
self.s.word("continue");
self.s.space();
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.s.space()
2014-03-16 19:58:11 +01:00
}
}
ast::ExprKind::Ret(ref result) => {
self.s.word("return");
if let Some(ref expr) = *result {
self.s.word(" ");
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
2014-03-16 19:58:11 +01:00
}
}
2020-01-22 15:20:27 +01:00
ast::ExprKind::InlineAsm(ref a) => {
enum AsmArg<'a> {
Template(String),
Operand(&'a InlineAsmOperand),
Options(InlineAsmOptions),
}
let mut args = vec![];
args.push(AsmArg::Template(InlineAsmTemplatePiece::to_string(&a.template)));
args.extend(a.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
if !a.options.is_empty() {
args.push(AsmArg::Options(a.options));
}
self.word("asm!");
self.popen();
self.commasep(Consistent, &args, |s, arg| match arg {
AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked),
AsmArg::Operand(op) => {
let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r
{
InlineAsmRegOrRegClass::Reg(r) => {
s.print_symbol(*r, ast::StrStyle::Cooked)
2020-01-22 15:20:27 +01:00
}
InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
};
match op {
InlineAsmOperand::In { reg, expr } => {
s.word("in");
s.popen();
print_reg_or_class(s, reg);
s.pclose();
s.space();
s.print_expr(expr);
}
InlineAsmOperand::Out { reg, late, expr } => {
s.word(if *late { "lateout" } else { "out" });
s.popen();
print_reg_or_class(s, reg);
s.pclose();
s.space();
match expr {
Some(expr) => s.print_expr(expr),
None => s.word("_"),
}
}
InlineAsmOperand::InOut { reg, late, expr } => {
s.word(if *late { "inlateout" } else { "inout" });
s.popen();
print_reg_or_class(s, reg);
s.pclose();
s.space();
s.print_expr(expr);
}
InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
s.word(if *late { "inlateout" } else { "inout" });
s.popen();
print_reg_or_class(s, reg);
s.pclose();
s.space();
s.print_expr(in_expr);
s.space();
s.word_space("=>");
match out_expr {
Some(out_expr) => s.print_expr(out_expr),
None => s.word("_"),
}
}
InlineAsmOperand::Const { expr } => {
s.word("const");
s.space();
s.print_expr(expr);
}
InlineAsmOperand::Sym { expr } => {
s.word("sym");
s.space();
s.print_expr(expr);
}
}
}
AsmArg::Options(opts) => {
s.word("options");
s.popen();
let mut options = vec![];
if opts.contains(InlineAsmOptions::PURE) {
options.push("pure");
}
if opts.contains(InlineAsmOptions::NOMEM) {
options.push("nomem");
}
if opts.contains(InlineAsmOptions::READONLY) {
options.push("readonly");
}
if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) {
options.push("preserves_flags");
}
if opts.contains(InlineAsmOptions::NORETURN) {
options.push("noreturn");
}
if opts.contains(InlineAsmOptions::NOSTACK) {
options.push("nostack");
}
2020-05-02 00:59:15 +02:00
if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
options.push("att_syntax");
}
2020-01-22 15:20:27 +01:00
s.commasep(Inconsistent, &options, |s, &opt| {
s.word(opt);
});
s.pclose();
}
});
self.pclose();
}
ast::ExprKind::LlvmInlineAsm(ref a) => {
self.s.word("llvm_asm!");
self.popen();
self.print_symbol(a.asm, a.asm_str_style);
self.word_space(":");
2014-04-17 10:35:40 +02:00
self.commasep(Inconsistent, &a.outputs, |s, out| {
let constraint = out.constraint.as_str();
let mut ch = constraint.chars();
std: Stabilize APIs for the 1.9 release This commit applies all stabilizations, renamings, and deprecations that the library team has decided on for the upcoming 1.9 release. All tracking issues have gone through a cycle-long "final comment period" and the specific APIs stabilized/deprecated are: Stable * `std::panic` * `std::panic::catch_unwind` (renamed from `recover`) * `std::panic::resume_unwind` (renamed from `propagate`) * `std::panic::AssertUnwindSafe` (renamed from `AssertRecoverSafe`) * `std::panic::UnwindSafe` (renamed from `RecoverSafe`) * `str::is_char_boundary` * `<*const T>::as_ref` * `<*mut T>::as_ref` * `<*mut T>::as_mut` * `AsciiExt::make_ascii_uppercase` * `AsciiExt::make_ascii_lowercase` * `char::decode_utf16` * `char::DecodeUtf16` * `char::DecodeUtf16Error` * `char::DecodeUtf16Error::unpaired_surrogate` * `BTreeSet::take` * `BTreeSet::replace` * `BTreeSet::get` * `HashSet::take` * `HashSet::replace` * `HashSet::get` * `OsString::with_capacity` * `OsString::clear` * `OsString::capacity` * `OsString::reserve` * `OsString::reserve_exact` * `OsStr::is_empty` * `OsStr::len` * `std::os::unix::thread` * `RawPthread` * `JoinHandleExt` * `JoinHandleExt::as_pthread_t` * `JoinHandleExt::into_pthread_t` * `HashSet::hasher` * `HashMap::hasher` * `CommandExt::exec` * `File::try_clone` * `SocketAddr::set_ip` * `SocketAddr::set_port` * `SocketAddrV4::set_ip` * `SocketAddrV4::set_port` * `SocketAddrV6::set_ip` * `SocketAddrV6::set_port` * `SocketAddrV6::set_flowinfo` * `SocketAddrV6::set_scope_id` * `<[T]>::copy_from_slice` * `ptr::read_volatile` * `ptr::write_volatile` * The `#[deprecated]` attribute * `OpenOptions::create_new` Deprecated * `std::raw::Slice` - use raw parts of `slice` module instead * `std::raw::Repr` - use raw parts of `slice` module instead * `str::char_range_at` - use slicing plus `chars()` plus `len_utf8` * `str::char_range_at_reverse` - use slicing plus `chars().rev()` plus `len_utf8` * `str::char_at` - use slicing plus `chars()` * `str::char_at_reverse` - use slicing plus `chars().rev()` * `str::slice_shift_char` - use `chars()` plus `Chars::as_str` * `CommandExt::session_leader` - use `before_exec` instead. Closes #27719 cc #27751 (deprecating the `Slice` bits) Closes #27754 Closes #27780 Closes #27809 Closes #27811 Closes #27830 Closes #28050 Closes #29453 Closes #29791 Closes #29935 Closes #30014 Closes #30752 Closes #31262 cc #31398 (still need to deal with `before_exec`) Closes #31405 Closes #31572 Closes #31755 Closes #31756
2016-04-07 19:42:53 +02:00
match ch.next() {
Some('=') if out.is_rw => {
2019-12-22 23:42:04 +01:00
s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
}
2019-12-22 23:42:04 +01:00
_ => s.print_string(&constraint, ast::StrStyle::Cooked),
}
s.popen();
s.print_expr(&out.expr);
s.pclose();
});
self.s.space();
self.word_space(":");
self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
s.print_symbol(co, ast::StrStyle::Cooked);
s.popen();
s.print_expr(o);
s.pclose();
});
self.s.space();
self.word_space(":");
2014-04-17 10:35:40 +02:00
self.commasep(Inconsistent, &a.clobbers, |s, &co| {
s.print_symbol(co, ast::StrStyle::Cooked);
});
2014-12-17 14:02:50 +01:00
let mut options = vec![];
2014-12-17 14:02:50 +01:00
if a.volatile {
options.push("volatile");
}
if a.alignstack {
options.push("alignstack");
}
if a.dialect == ast::LlvmAsmDialect::Intel {
2014-12-17 14:02:50 +01:00
options.push("intel");
}
if !options.is_empty() {
self.s.space();
self.word_space(":");
2019-12-22 23:42:04 +01:00
self.commasep(Inconsistent, &options, |s, &co| {
s.print_string(co, ast::StrStyle::Cooked);
});
2014-12-17 14:02:50 +01:00
}
self.pclose();
2014-03-16 19:58:11 +01:00
}
2020-02-29 17:32:20 +01:00
ast::ExprKind::MacCall(ref m) => self.print_mac(m),
ast::ExprKind::Paren(ref e) => {
self.popen();
self.print_inner_attributes_inline(attrs);
self.print_expr(e);
self.pclose();
2019-12-22 23:42:04 +01:00
}
2016-12-26 14:34:03 +01:00
ast::ExprKind::Yield(ref e) => {
self.s.word("yield");
if let Some(ref expr) = *e {
self.s.space();
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
2016-12-26 14:34:03 +01:00
}
}
ast::ExprKind::Try(ref e) => {
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
self.s.word("?")
2014-03-16 19:58:11 +01:00
}
ast::ExprKind::TryBlock(ref blk) => {
self.head("try");
self.s.space();
self.print_block_with_attrs(blk, attrs)
}
ast::ExprKind::Err => {
self.popen();
self.s.word("/*ERROR*/");
self.pclose()
}
2014-03-16 19:58:11 +01:00
}
self.ann.post(self, AnnNode::Expr(expr));
self.end();
}
crate fn print_local_decl(&mut self, loc: &ast::Local) {
self.print_pat(&loc.pat);
2015-01-02 12:55:31 +01:00
if let Some(ref ty) = loc.ty {
self.word_space(":");
self.print_type(ty);
}
}
pub fn print_usize(&mut self, i: usize) {
self.s.word(i.to_string())
}
2020-04-19 13:00:18 +02:00
crate fn print_name(&mut self, name: Symbol) {
self.s.word(name.to_string());
2018-08-22 23:05:19 +02:00
self.ann.post(self, AnnNode::Name(&name))
2014-03-16 19:58:11 +01:00
}
2019-12-22 23:42:04 +01:00
fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
self.s.word("<");
self.print_type(&qself.ty);
if qself.position > 0 {
self.s.space();
self.word_space("as");
let depth = path.segments.len() - qself.position;
self.print_path(path, false, depth);
}
self.s.word(">");
2020-11-12 12:41:19 +01:00
for item_segment in &path.segments[qself.position..] {
self.s.word("::");
self.print_ident(item_segment.ident);
if let Some(ref args) = item_segment.args {
self.print_generic_args(args, colons_before_params)
}
2016-12-10 07:45:58 +01:00
}
}
crate fn print_pat(&mut self, pat: &ast::Pat) {
self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat));
2014-03-16 19:58:11 +01:00
/* Pat isn't normalized, but the beauty of it
2019-12-22 23:42:04 +01:00
is that it doesn't matter */
2019-09-26 17:18:31 +02:00
match pat.kind {
PatKind::Wild => self.s.word("_"),
2018-03-18 14:47:09 +01:00
PatKind::Ident(binding_mode, ident, ref sub) => {
2014-03-16 19:58:11 +01:00
match binding_mode {
ast::BindingMode::ByRef(mutbl) => {
self.word_nbsp("ref");
self.print_mutability(mutbl, false);
2014-03-16 19:58:11 +01:00
}
ast::BindingMode::ByValue(ast::Mutability::Not) => {}
ast::BindingMode::ByValue(ast::Mutability::Mut) => {
self.word_nbsp("mut");
2014-03-16 19:58:11 +01:00
}
}
self.print_ident(ident);
if let Some(ref p) = *sub {
2019-10-14 18:12:04 +02:00
self.s.space();
self.s.word_space("@");
self.print_pat(p);
2014-03-16 19:58:11 +01:00
}
}
2019-07-09 09:12:14 +02:00
PatKind::TupleStruct(ref path, ref elts) => {
self.print_path(path, true, 0);
self.popen();
2019-07-09 09:12:14 +02:00
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.pclose();
2013-11-08 04:25:39 +01:00
}
2018-10-19 16:40:07 +02:00
PatKind::Or(ref pats) => {
self.strsep("|", true, Inconsistent, &pats[..], |s, p| s.print_pat(p));
2018-10-19 16:40:07 +02:00
}
PatKind::Path(None, ref path) => {
self.print_path(path, true, 0);
}
PatKind::Path(Some(ref qself), ref path) => {
self.print_qpath(path, qself, false);
}
2016-02-11 19:16:33 +01:00
PatKind::Struct(ref path, ref fields, etc) => {
self.print_path(path, true, 0);
self.nbsp();
self.word_space("{");
self.commasep_cmnt(
2019-12-22 23:42:04 +01:00
Consistent,
&fields[..],
2014-03-16 19:58:11 +01:00
|s, f| {
s.cbox(INDENT_UNIT);
if !f.is_shorthand {
s.print_ident(f.ident);
s.word_nbsp(":");
}
s.print_pat(&f.pat);
s.end();
2014-03-16 19:58:11 +01:00
},
2019-12-22 23:42:04 +01:00
|f| f.pat.span,
);
2014-03-16 19:58:11 +01:00
if etc {
2019-12-22 23:42:04 +01:00
if !fields.is_empty() {
self.word_space(",");
}
self.s.word("..");
2014-03-16 19:58:11 +01:00
}
self.s.space();
self.s.word("}");
2014-03-16 19:58:11 +01:00
}
2019-07-09 09:12:14 +02:00
PatKind::Tuple(ref elts) => {
self.popen();
2019-07-09 09:12:14 +02:00
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
if elts.len() == 1 {
self.s.word(",");
2014-03-16 19:58:11 +01:00
}
self.pclose();
2014-03-16 19:58:11 +01:00
}
2016-02-11 19:16:33 +01:00
PatKind::Box(ref inner) => {
self.s.word("box ");
self.print_pat(inner);
2014-03-16 19:58:11 +01:00
}
2016-02-11 19:16:33 +01:00
PatKind::Ref(ref inner, mutbl) => {
self.s.word("&");
if mutbl == ast::Mutability::Mut {
self.s.word("mut ");
}
if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) =
inner.kind
{
self.popen();
self.print_pat(inner);
self.pclose();
} else {
self.print_pat(inner);
}
2014-03-16 19:58:11 +01:00
}
PatKind::Lit(ref e) => self.print_expr(&**e),
PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
if let Some(e) = begin {
self.print_expr(e);
self.s.space();
}
match *end_kind {
RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("..."),
RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..="),
RangeEnd::Excluded => self.s.word(".."),
}
if let Some(e) = end {
self.print_expr(e);
}
2014-03-16 19:58:11 +01:00
}
2019-07-09 09:12:14 +02:00
PatKind::Slice(ref elts) => {
self.s.word("[");
2019-07-09 09:12:14 +02:00
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.s.word("]");
2014-03-16 19:58:11 +01:00
}
2019-07-07 00:26:55 +02:00
PatKind::Rest => self.s.word(".."),
PatKind::Paren(ref inner) => {
self.popen();
self.print_pat(inner);
self.pclose();
}
2020-02-29 17:32:20 +01:00
PatKind::MacCall(ref m) => self.print_mac(m),
}
2018-08-22 23:05:19 +02:00
self.ann.post(self, AnnNode::Pat(pat))
}
fn print_arm(&mut self, arm: &ast::Arm) {
// Note, I have no idea why this check is necessary, but here it is.
if arm.attrs.is_empty() {
self.s.space();
}
self.cbox(INDENT_UNIT);
self.ibox(0);
self.maybe_print_comment(arm.pat.span.lo());
self.print_outer_attributes(&arm.attrs);
self.print_pat(&arm.pat);
self.s.space();
2019-06-23 11:32:16 +02:00
if let Some(ref e) = arm.guard {
self.word_space("if");
self.print_expr(e);
self.s.space();
}
self.word_space("=>");
match arm.body.kind {
ast::ExprKind::Block(ref blk, opt_label) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
}
// The block will close the pattern's ibox.
self.print_block_unclosed_indent(blk);
2014-11-22 16:24:58 +01:00
// If it is a user-provided unsafe block, print a comma after it.
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
self.s.word(",");
2014-11-22 16:24:58 +01:00
}
}
_ => {
self.end(); // Close the ibox for the pattern.
self.print_expr(&arm.body);
self.s.word(",");
}
}
self.end(); // Close enclosing cbox.
}
fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
2016-03-06 13:54:44 +01:00
match explicit_self.node {
SelfKind::Value(m) => {
self.print_mutability(m, false);
self.s.word("self")
2014-03-16 19:58:11 +01:00
}
2016-03-06 13:54:44 +01:00
SelfKind::Region(ref lt, m) => {
self.s.word("&");
self.print_opt_lifetime(lt);
self.print_mutability(m, false);
self.s.word("self")
2014-03-16 19:58:11 +01:00
}
2016-03-06 13:54:44 +01:00
SelfKind::Explicit(ref typ, m) => {
self.print_mutability(m, false);
self.s.word("self");
self.word_space(":");
self.print_type(typ)
}
}
}
fn print_fn_full(
&mut self,
sig: &ast::FnSig,
2020-04-19 13:00:18 +02:00
name: Ident,
generics: &ast::Generics,
vis: &ast::Visibility,
defaultness: ast::Defaultness,
body: Option<&ast::Block>,
attrs: &[ast::Attribute],
) {
if body.is_some() {
self.head("");
}
self.print_visibility(vis);
self.print_defaultness(defaultness);
self.print_fn(&sig.decl, sig.header, Some(name), generics);
if let Some(body) = body {
self.nbsp();
self.print_block_with_attrs(body, attrs);
} else {
self.s.word(";");
}
}
2019-12-22 23:42:04 +01:00
crate fn print_fn(
&mut self,
decl: &ast::FnDecl,
header: ast::FnHeader,
2020-04-19 13:00:18 +02:00
name: Option<Ident>,
2019-12-22 23:42:04 +01:00
generics: &ast::Generics,
) {
self.print_fn_header_info(header);
if let Some(name) = name {
self.nbsp();
self.print_ident(name);
}
self.print_generic_params(&generics.params);
2019-12-01 16:00:08 +01:00
self.print_fn_params_and_ret(decl, false);
self.print_where_clause(&generics.where_clause)
2014-03-16 19:58:11 +01:00
}
2019-12-01 16:00:08 +01:00
crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
self.word(open);
self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
self.word(close);
self.print_fn_ret_ty(&decl.output)
}
crate fn print_movability(&mut self, movability: ast::Movability) {
match movability {
ast::Movability::Static => self.word_space("static"),
2019-12-22 23:42:04 +01:00
ast::Movability::Movable => {}
}
}
crate fn print_asyncness(&mut self, asyncness: ast::Async) {
2018-06-07 00:50:59 +02:00
if asyncness.is_async() {
self.word_nbsp("async");
2018-06-07 00:50:59 +02:00
}
}
crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
match capture_clause {
ast::CaptureBy::Value => self.word_space("move"),
2019-12-22 23:42:04 +01:00
ast::CaptureBy::Ref => {}
}
}
pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
if !bounds.is_empty() {
self.s.word(prefix);
2014-03-16 19:58:11 +01:00
let mut first = true;
2015-01-31 18:20:46 +01:00
for bound in bounds {
if !(first && prefix.is_empty()) {
self.nbsp();
}
2014-03-16 19:58:11 +01:00
if first {
first = false;
} else {
self.word_space("+");
2014-03-16 19:58:11 +01:00
}
match bound {
2018-06-14 13:23:46 +02:00
GenericBound::Trait(tref, modifier) => {
if modifier == &TraitBoundModifier::Maybe {
self.s.word("?");
}
self.print_poly_trait_ref(tref);
}
GenericBound::Outlives(lt) => self.print_lifetime(*lt),
}
2014-03-16 19:58:11 +01:00
}
}
}
crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
2017-03-25 22:14:18 +01:00
self.print_name(lifetime.ident.name)
2014-03-16 19:58:11 +01:00
}
crate fn print_lifetime_bounds(
2019-12-22 23:42:04 +01:00
&mut self,
lifetime: ast::Lifetime,
bounds: &ast::GenericBounds,
) {
self.print_lifetime(lifetime);
2016-06-29 14:53:01 +02:00
if !bounds.is_empty() {
self.s.word(": ");
2016-06-29 14:53:01 +02:00
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
self.s.word(" + ");
2016-06-29 14:53:01 +02:00
}
match bound {
ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
_ => panic!(),
}
2016-06-29 14:53:01 +02:00
}
}
}
crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
if generic_params.is_empty() {
return;
}
self.s.word("<");
self.commasep(Inconsistent, &generic_params, |s, param| {
2019-08-02 08:36:08 +02:00
s.print_outer_attributes_inline(&param.attrs);
2018-05-26 20:16:21 +02:00
match param.kind {
ast::GenericParamKind::Lifetime => {
let lt = ast::Lifetime { id: param.id, ident: param.ident };
s.print_lifetime_bounds(lt, &param.bounds)
}
2018-05-28 14:33:28 +02:00
ast::GenericParamKind::Type { ref default } => {
s.print_ident(param.ident);
s.print_type_bounds(":", &param.bounds);
2019-08-02 08:36:08 +02:00
if let Some(ref default) = default {
s.s.space();
s.word_space("=");
s.print_type(default)
2018-05-26 20:16:21 +02:00
}
}
ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
s.word_space("const");
s.print_ident(param.ident);
s.s.space();
s.word_space(":");
s.print_type(ty);
s.print_type_bounds(":", &param.bounds);
if let Some(ref _default) = default {
// FIXME(const_generics_defaults): print the `default` value here
}
}
}
});
self.s.word(">");
2011-08-03 06:26:54 +02:00
}
crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
if where_clause.predicates.is_empty() && !where_clause.has_where_token {
return;
}
self.s.space();
self.word_space("where");
for (i, predicate) in where_clause.predicates.iter().enumerate() {
if i != 0 {
self.word_space(",");
}
2015-11-17 15:24:49 +01:00
match *predicate {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
ref bound_generic_params,
ref bounded_ty,
ref bounds,
..
}) => {
self.print_formal_generic_params(bound_generic_params);
self.print_type(bounded_ty);
self.print_type_bounds(":", bounds);
}
2019-12-22 23:42:04 +01:00
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
ref lifetime,
ref bounds,
..
}) => {
self.print_lifetime_bounds(*lifetime, bounds);
}
2019-12-22 23:42:04 +01:00
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
ref lhs_ty,
ref rhs_ty,
..
}) => {
self.print_type(lhs_ty);
self.s.space();
self.word_space("=");
self.print_type(rhs_ty);
}
}
}
}
crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
match tree.kind {
ast::UseTreeKind::Simple(rename, ..) => {
self.print_path(&tree.prefix, false, 0);
if let Some(rename) = rename {
self.s.space();
self.word_space("as");
self.print_ident(rename);
2014-03-16 19:58:11 +01:00
}
}
ast::UseTreeKind::Glob => {
if !tree.prefix.segments.is_empty() {
self.print_path(&tree.prefix, false, 0);
self.s.word("::");
}
self.s.word("*");
2014-03-16 19:58:11 +01:00
}
ast::UseTreeKind::Nested(ref items) => {
if tree.prefix.segments.is_empty() {
self.s.word("{");
2014-03-16 19:58:11 +01:00
} else {
self.print_path(&tree.prefix, false, 0);
self.s.word("::{");
2014-03-16 19:58:11 +01:00
}
self.commasep(Inconsistent, &items[..], |this, &(ref tree, _)| {
this.print_use_tree(tree)
});
self.s.word("}");
2014-03-16 19:58:11 +01:00
}
}
}
pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
2014-03-16 19:58:11 +01:00
match mutbl {
ast::Mutability::Mut => self.word_nbsp("mut"),
2019-12-22 23:42:04 +01:00
ast::Mutability::Not => {
if print_const {
self.word_nbsp("const");
}
}
}
}
crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
self.print_mutability(mt.mutbl, print_const);
2016-02-08 23:55:55 +01:00
self.print_type(&mt.ty)
}
crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
self.ibox(INDENT_UNIT);
self.print_outer_attributes_inline(&input.attrs);
2019-09-26 18:25:31 +02:00
match input.ty.kind {
ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
2014-03-16 19:58:11 +01:00
_ => {
if let Some(eself) = input.to_self() {
self.print_explicit_self(&eself);
} else {
2019-09-26 17:18:31 +02:00
let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
ident.name == kw::Empty
2016-03-06 13:54:44 +01:00
} else {
false
};
if !invalid {
self.print_pat(&input.pat);
self.s.word(":");
self.s.space();
2014-03-16 19:58:11 +01:00
}
self.print_type(&input.ty);
}
}
2012-05-04 21:33:04 +02:00
}
self.end();
2014-03-16 19:58:11 +01:00
}
2020-02-15 04:10:59 +01:00
crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
2019-12-01 16:00:08 +01:00
self.space_if_not_bol();
self.ibox(INDENT_UNIT);
self.word_space("->");
self.print_type(ty);
self.end();
self.maybe_print_comment(ty.span.lo());
}
}
2019-12-22 23:42:04 +01:00
crate fn print_ty_fn(
&mut self,
ext: ast::Extern,
unsafety: ast::Unsafe,
2019-12-22 23:42:04 +01:00
decl: &ast::FnDecl,
2020-04-19 13:00:18 +02:00
name: Option<Ident>,
2019-12-22 23:42:04 +01:00
generic_params: &[ast::GenericParam],
) {
self.ibox(INDENT_UNIT);
if !generic_params.is_empty() {
self.s.word("for");
self.print_generic_params(generic_params);
}
let generics = ast::Generics {
params: Vec::new(),
where_clause: ast::WhereClause {
has_where_token: false,
predicates: Vec::new(),
span: rustc_span::DUMMY_SP,
},
span: rustc_span::DUMMY_SP,
};
let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
self.print_fn(decl, header, name, &generics);
self.end();
2014-01-30 02:39:21 +01:00
}
2014-03-16 19:58:11 +01:00
2019-12-22 23:42:04 +01:00
crate fn maybe_print_trailing_comment(
&mut self,
span: rustc_span::Span,
2019-12-22 23:42:04 +01:00
next_pos: Option<BytePos>,
) {
if let Some(cmnts) = self.comments() {
if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
self.print_comment(&cmnt);
2014-01-30 02:39:21 +01:00
}
}
}
crate fn print_remaining_comments(&mut self) {
2014-03-16 19:58:11 +01:00
// If there aren't any remaining comments, then we need to manually
// make sure there is a line break at the end.
if self.next_comment().is_none() {
self.s.hardbreak();
2014-03-16 19:58:11 +01:00
}
while let Some(ref cmnt) = self.next_comment() {
self.print_comment(cmnt);
2014-03-16 19:58:11 +01:00
}
}
crate fn print_fn_header_info(&mut self, header: ast::FnHeader) {
self.print_constness(header.constness);
self.print_asyncness(header.asyncness);
self.print_unsafety(header.unsafety);
match header.ext {
ast::Extern::None => {}
ast::Extern::Implicit => {
self.word_nbsp("extern");
}
ast::Extern::Explicit(abi) => {
self.word_nbsp("extern");
self.print_literal(&abi.as_lit());
self.nbsp();
}
}
self.s.word("fn")
2012-05-25 08:44:58 +02:00
}
crate fn print_unsafety(&mut self, s: ast::Unsafe) {
match s {
ast::Unsafe::No => {}
ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
2014-03-16 19:58:11 +01:00
}
2012-05-25 08:44:58 +02:00
}
crate fn print_constness(&mut self, s: ast::Const) {
match s {
ast::Const::No => {}
ast::Const::Yes(_) => self.word_nbsp("const"),
}
}
crate fn print_is_auto(&mut self, s: ast::IsAuto) {
match s {
ast::IsAuto::Yes => self.word_nbsp("auto"),
ast::IsAuto::No => {}
}
}
}