rust/compiler/rustc_expand/src/build.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

629 lines
20 KiB
Rust
Raw Normal View History

use crate::base::ExtCtxt;
use rustc_ast::attr;
use rustc_ast::ptr::P;
2021-06-22 18:00:58 +00:00
use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp};
use rustc_data_structures::sync::Lrc;
use rustc_span::source_map::Spanned;
2020-04-19 11:00:18 +00:00
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
2022-09-08 07:22:52 +00:00
use thin_vec::ThinVec;
impl<'a> ExtCtxt<'a> {
2020-04-19 11:00:18 +00:00
pub fn path(&self, span: Span, strs: Vec<Ident>) -> ast::Path {
self.path_all(span, false, strs, vec![])
}
2020-04-19 11:00:18 +00:00
pub fn path_ident(&self, span: Span, id: Ident) -> ast::Path {
self.path(span, vec![id])
}
2020-04-19 11:00:18 +00:00
pub fn path_global(&self, span: Span, strs: Vec<Ident>) -> ast::Path {
self.path_all(span, true, strs, vec![])
}
pub fn path_all(
&self,
span: Span,
global: bool,
2020-04-19 11:00:18 +00:00
mut idents: Vec<Ident>,
args: Vec<ast::GenericArg>,
) -> ast::Path {
2018-12-02 12:15:42 +00:00
assert!(!idents.is_empty());
let add_root = global && !idents[0].is_path_segment_keyword();
2022-09-08 07:22:52 +00:00
let mut segments = ThinVec::with_capacity(idents.len() + add_root as usize);
2018-12-02 12:15:42 +00:00
if add_root {
segments.push(ast::PathSegment::path_root(span));
}
let last_ident = idents.pop().unwrap();
2018-03-19 00:54:56 +00:00
segments.extend(
idents.into_iter().map(|ident| ast::PathSegment::from_ident(ident.with_span_pos(span))),
);
let args = if !args.is_empty() {
let args = args.into_iter().map(ast::AngleBracketedArg::Arg).collect();
ast::AngleBracketedArgs { args, span }.into()
2016-12-10 06:45:58 +00:00
} else {
None
2016-12-10 06:45:58 +00:00
};
2018-08-31 00:01:26 +00:00
segments.push(ast::PathSegment {
ident: last_ident.with_span_pos(span),
id: ast::DUMMY_NODE_ID,
args,
});
2020-08-21 22:51:23 +00:00
ast::Path { span, segments, tokens: None }
}
pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
ast::MutTy { ty, mutbl }
}
2019-09-26 16:25:31 +00:00
pub fn ty(&self, span: Span, kind: ast::TyKind) -> P<ast::Ty> {
P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None })
}
Optimize the code produced by `derive(Debug)`. This commit adds new methods that combine sequences of existing formatting methods. - `Formatter::debug_{tuple,struct}_field[12345]_finish`, equivalent to a `Formatter::debug_{tuple,struct}` + N x `Debug{Tuple,Struct}::field` + `Debug{Tuple,Struct}::finish` call sequence. - `Formatter::debug_{tuple,struct}_fields_finish` is similar, but can handle any number of fields by using arrays. These new methods are all marked as `doc(hidden)` and unstable. They are intended for the compiler's own use. Special-casing up to 5 fields gives significantly better performance results than always using arrays (as was tried in #95637). The commit also changes the `Debug` deriving code to use these new methods. For example, where the old `Debug` code for a struct with two fields would be like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => { let debug_trait_builder = &mut ::core::fmt::Formatter::debug_struct(f, "S2"); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f1", &&(*__self_0_0)); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f2", &&(*__self_0_1)); ::core::fmt::DebugStruct::finish(debug_trait_builder) } } } ``` the new code is like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => ::core::fmt::Formatter::debug_struct_field2_finish( f, "S2", "f1", &&(*__self_0_0), "f2", &&(*__self_0_1), ), } } ``` This shrinks the code produced for `Debug` instances considerably, reducing compile times and binary sizes. Co-authored-by: Scott McMurray <scottmcm@users.noreply.github.com>
2022-06-17 07:08:36 +00:00
pub fn ty_infer(&self, span: Span) -> P<ast::Ty> {
self.ty(span, ast::TyKind::Infer)
}
pub fn ty_path(&self, path: ast::Path) -> P<ast::Ty> {
self.ty(path.span, ast::TyKind::Path(None, path))
}
// Might need to take bounds as an argument in the future, if you ever want
// to generate a bounded existential trait type.
2020-04-19 11:00:18 +00:00
pub fn ty_ident(&self, span: Span, ident: Ident) -> P<ast::Ty> {
self.ty_path(self.path_ident(span, ident))
}
pub fn anon_const(&self, span: Span, kind: ast::ExprKind) -> ast::AnonConst {
ast::AnonConst {
id: ast::DUMMY_NODE_ID,
2020-05-19 20:56:20 +00:00
value: P(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind,
span,
attrs: AttrVec::new(),
tokens: None,
}),
}
}
2020-04-19 11:00:18 +00:00
pub fn const_ident(&self, span: Span, ident: Ident) -> ast::AnonConst {
self.anon_const(span, ast::ExprKind::Path(None, self.path_ident(span, ident)))
}
pub fn ty_rptr(
&self,
span: Span,
ty: P<ast::Ty>,
2013-07-05 12:33:52 +00:00
lifetime: Option<ast::Lifetime>,
mutbl: ast::Mutability,
) -> P<ast::Ty> {
self.ty(span, ast::TyKind::Rptr(lifetime, self.ty_mt(ty, mutbl)))
}
pub fn ty_ptr(&self, span: Span, ty: P<ast::Ty>, mutbl: ast::Mutability) -> P<ast::Ty> {
self.ty(span, ast::TyKind::Ptr(self.ty_mt(ty, mutbl)))
}
pub fn typaram(
&self,
2014-04-03 00:53:57 +00:00
span: Span,
2020-04-19 11:00:18 +00:00
ident: Ident,
bounds: ast::GenericBounds,
2018-05-27 19:07:09 +00:00
default: Option<P<ast::Ty>>,
) -> ast::GenericParam {
ast::GenericParam {
2018-03-19 00:54:56 +00:00
ident: ident.with_span_pos(span),
id: ast::DUMMY_NODE_ID,
attrs: AttrVec::new(),
2018-05-28 12:33:28 +00:00
bounds,
2018-05-27 19:07:09 +00:00
kind: ast::GenericParamKind::Type { default },
is_placeholder: false,
2022-04-28 19:59:41 +00:00
colon_span: None,
}
}
pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID }
2014-11-07 11:53:45 +00:00
}
pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
2014-11-07 11:53:45 +00:00
ast::PolyTraitRef {
bound_generic_params: Vec::new(),
trait_ref: self.trait_ref(path),
span,
}
}
pub fn trait_bound(&self, path: ast::Path) -> ast::GenericBound {
2018-06-14 11:23:46 +00:00
ast::GenericBound::Trait(
self.poly_trait_ref(path.span, path),
ast::TraitBoundModifier::None,
)
}
2020-04-19 11:00:18 +00:00
pub fn lifetime(&self, span: Span, ident: Ident) -> ast::Lifetime {
2018-03-19 00:54:56 +00:00
ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) }
}
Optimize the code produced by `derive(Debug)`. This commit adds new methods that combine sequences of existing formatting methods. - `Formatter::debug_{tuple,struct}_field[12345]_finish`, equivalent to a `Formatter::debug_{tuple,struct}` + N x `Debug{Tuple,Struct}::field` + `Debug{Tuple,Struct}::finish` call sequence. - `Formatter::debug_{tuple,struct}_fields_finish` is similar, but can handle any number of fields by using arrays. These new methods are all marked as `doc(hidden)` and unstable. They are intended for the compiler's own use. Special-casing up to 5 fields gives significantly better performance results than always using arrays (as was tried in #95637). The commit also changes the `Debug` deriving code to use these new methods. For example, where the old `Debug` code for a struct with two fields would be like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => { let debug_trait_builder = &mut ::core::fmt::Formatter::debug_struct(f, "S2"); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f1", &&(*__self_0_0)); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f2", &&(*__self_0_1)); ::core::fmt::DebugStruct::finish(debug_trait_builder) } } } ``` the new code is like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => ::core::fmt::Formatter::debug_struct_field2_finish( f, "S2", "f1", &&(*__self_0_0), "f2", &&(*__self_0_1), ), } } ``` This shrinks the code produced for `Debug` instances considerably, reducing compile times and binary sizes. Co-authored-by: Scott McMurray <scottmcm@users.noreply.github.com>
2022-06-17 07:08:36 +00:00
pub fn lifetime_static(&self, span: Span) -> ast::Lifetime {
self.lifetime(span, Ident::new(kw::StaticLifetime, span))
}
pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) }
}
pub fn stmt_let_pat(&self, sp: Span, pat: P<ast::Pat>, ex: P<ast::Expr>) -> ast::Stmt {
let local = P(ast::Local {
pat,
ty: None,
id: ast::DUMMY_NODE_ID,
kind: LocalKind::Init(ex),
span: sp,
attrs: AttrVec::new(),
tokens: None,
});
self.stmt_local(local, sp)
}
2020-04-19 11:00:18 +00:00
pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt {
Optimize the code produced by `derive(Debug)`. This commit adds new methods that combine sequences of existing formatting methods. - `Formatter::debug_{tuple,struct}_field[12345]_finish`, equivalent to a `Formatter::debug_{tuple,struct}` + N x `Debug{Tuple,Struct}::field` + `Debug{Tuple,Struct}::finish` call sequence. - `Formatter::debug_{tuple,struct}_fields_finish` is similar, but can handle any number of fields by using arrays. These new methods are all marked as `doc(hidden)` and unstable. They are intended for the compiler's own use. Special-casing up to 5 fields gives significantly better performance results than always using arrays (as was tried in #95637). The commit also changes the `Debug` deriving code to use these new methods. For example, where the old `Debug` code for a struct with two fields would be like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => { let debug_trait_builder = &mut ::core::fmt::Formatter::debug_struct(f, "S2"); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f1", &&(*__self_0_0)); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f2", &&(*__self_0_1)); ::core::fmt::DebugStruct::finish(debug_trait_builder) } } } ``` the new code is like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => ::core::fmt::Formatter::debug_struct_field2_finish( f, "S2", "f1", &&(*__self_0_0), "f2", &&(*__self_0_1), ), } } ``` This shrinks the code produced for `Debug` instances considerably, reducing compile times and binary sizes. Co-authored-by: Scott McMurray <scottmcm@users.noreply.github.com>
2022-06-17 07:08:36 +00:00
self.stmt_let_ty(sp, mutbl, ident, None, ex)
}
pub fn stmt_let_ty(
&self,
sp: Span,
mutbl: bool,
ident: Ident,
ty: Option<P<ast::Ty>>,
ex: P<ast::Expr>,
) -> ast::Stmt {
let pat = if mutbl {
2022-08-30 22:34:35 +00:00
self.pat_ident_binding_mode(sp, ident, ast::BindingAnnotation::MUT)
} else {
self.pat_ident(sp, ident)
};
2014-09-13 16:06:01 +00:00
let local = P(ast::Local {
pat,
Optimize the code produced by `derive(Debug)`. This commit adds new methods that combine sequences of existing formatting methods. - `Formatter::debug_{tuple,struct}_field[12345]_finish`, equivalent to a `Formatter::debug_{tuple,struct}` + N x `Debug{Tuple,Struct}::field` + `Debug{Tuple,Struct}::finish` call sequence. - `Formatter::debug_{tuple,struct}_fields_finish` is similar, but can handle any number of fields by using arrays. These new methods are all marked as `doc(hidden)` and unstable. They are intended for the compiler's own use. Special-casing up to 5 fields gives significantly better performance results than always using arrays (as was tried in #95637). The commit also changes the `Debug` deriving code to use these new methods. For example, where the old `Debug` code for a struct with two fields would be like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => { let debug_trait_builder = &mut ::core::fmt::Formatter::debug_struct(f, "S2"); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f1", &&(*__self_0_0)); let _ = ::core::fmt::DebugStruct::field(debug_trait_builder, "f2", &&(*__self_0_1)); ::core::fmt::DebugStruct::finish(debug_trait_builder) } } } ``` the new code is like this: ``` fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { match *self { Self { f1: ref __self_0_0, f2: ref __self_0_1, } => ::core::fmt::Formatter::debug_struct_field2_finish( f, "S2", "f1", &&(*__self_0_0), "f2", &&(*__self_0_1), ), } } ``` This shrinks the code produced for `Debug` instances considerably, reducing compile times and binary sizes. Co-authored-by: Scott McMurray <scottmcm@users.noreply.github.com>
2022-06-17 07:08:36 +00:00
ty,
id: ast::DUMMY_NODE_ID,
2021-06-22 18:00:58 +00:00
kind: LocalKind::Init(ex),
span: sp,
2019-12-03 15:38:34 +00:00
attrs: AttrVec::new(),
tokens: None,
});
2022-06-02 12:00:04 +00:00
self.stmt_local(local, sp)
}
// Generates `let _: Type;`, which is usually used for type assertions.
pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
2016-08-26 16:23:42 +00:00
let local = P(ast::Local {
pat: self.pat_wild(span),
ty: Some(ty),
id: ast::DUMMY_NODE_ID,
2021-06-22 18:00:58 +00:00
kind: LocalKind::Decl,
span,
2019-12-03 15:38:34 +00:00
attrs: AttrVec::new(),
tokens: None,
2016-08-26 16:23:42 +00:00
});
2022-06-02 12:00:04 +00:00
self.stmt_local(local, span)
}
pub fn stmt_local(&self, local: P<ast::Local>, span: Span) -> ast::Stmt {
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
2016-08-26 16:23:42 +00:00
}
pub fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp }
}
pub fn block_expr(&self, expr: P<ast::Expr>) -> P<ast::Block> {
self.block(
expr.span,
vec![ast::Stmt {
id: ast::DUMMY_NODE_ID,
2016-06-23 09:51:18 +00:00
span: expr.span,
2019-09-26 16:34:50 +00:00
kind: ast::StmtKind::Expr(expr),
2016-06-23 09:51:18 +00:00
}],
)
}
pub fn block(&self, span: Span, stmts: Vec<ast::Stmt>) -> P<ast::Block> {
P(ast::Block {
stmts,
id: ast::DUMMY_NODE_ID,
rules: BlockCheckMode::Default,
span,
tokens: None,
could_be_bare_literal: false,
})
}
pub fn expr(&self, span: Span, kind: ast::ExprKind) -> P<ast::Expr> {
2020-05-19 20:56:20 +00:00
P(ast::Expr { id: ast::DUMMY_NODE_ID, kind, span, attrs: AttrVec::new(), tokens: None })
}
pub fn expr_path(&self, path: ast::Path) -> P<ast::Expr> {
self.expr(path.span, ast::ExprKind::Path(None, path))
}
2020-04-19 11:00:18 +00:00
pub fn expr_ident(&self, span: Span, id: Ident) -> P<ast::Expr> {
self.expr_path(self.path_ident(span, id))
}
pub fn expr_self(&self, span: Span) -> P<ast::Expr> {
self.expr_ident(span, Ident::with_dummy_span(kw::SelfLower))
}
pub fn expr_field(&self, span: Span, expr: P<Expr>, field: Ident) -> P<ast::Expr> {
self.expr(span, ast::ExprKind::Field(expr, field))
}
pub fn expr_binary(
&self,
sp: Span,
op: ast::BinOpKind,
2014-09-13 16:06:01 +00:00
lhs: P<ast::Expr>,
rhs: P<ast::Expr>,
) -> P<ast::Expr> {
self.expr(sp, ast::ExprKind::Binary(Spanned { node: op, span: sp }, lhs, rhs))
}
pub fn expr_deref(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
2019-09-21 19:07:28 +00:00
self.expr(sp, ast::ExprKind::Unary(UnOp::Deref, e))
}
pub fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
self.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Not, e))
}
pub fn expr_call(
&self,
span: Span,
expr: P<ast::Expr>,
args: Vec<P<ast::Expr>>,
) -> P<ast::Expr> {
self.expr(span, ast::ExprKind::Call(expr, args))
}
2020-04-19 11:00:18 +00:00
pub fn expr_call_ident(&self, span: Span, id: Ident, args: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr(span, ast::ExprKind::Call(self.expr_ident(span, id), args))
}
pub fn expr_call_global(
&self,
sp: Span,
2020-04-19 11:00:18 +00:00
fn_path: Vec<Ident>,
2014-09-13 16:06:01 +00:00
args: Vec<P<ast::Expr>>,
) -> P<ast::Expr> {
let pathexpr = self.expr_path(self.path_global(sp, fn_path));
self.expr_call(sp, pathexpr, args)
}
pub fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> {
self.expr(b.span, ast::ExprKind::Block(b, None))
}
pub fn field_imm(&self, span: Span, ident: Ident, e: P<ast::Expr>) -> ast::ExprField {
ast::ExprField {
2018-03-18 13:47:09 +00:00
ident: ident.with_span_pos(span),
expr: e,
span,
is_shorthand: false,
2019-12-03 15:38:34 +00:00
attrs: AttrVec::new(),
2019-08-14 01:22:51 +00:00
id: ast::DUMMY_NODE_ID,
is_placeholder: false,
}
}
pub fn expr_struct(
&self,
span: Span,
path: ast::Path,
fields: Vec<ast::ExprField>,
) -> P<ast::Expr> {
self.expr(
span,
ast::ExprKind::Struct(P(ast::StructExpr {
qself: None,
path,
fields,
rest: ast::StructRest::None,
})),
)
}
pub fn expr_struct_ident(
&self,
span: Span,
2020-04-19 11:00:18 +00:00
id: Ident,
fields: Vec<ast::ExprField>,
2014-09-13 16:06:01 +00:00
) -> P<ast::Expr> {
self.expr_struct(span, self.path_ident(span, id), fields)
}
fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P<ast::Expr> {
let token_lit = lit_kind.to_token_lit();
self.expr(span, ast::ExprKind::Lit(token_lit))
}
pub fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr> {
self.expr_lit(
span,
ast::LitKind::Int(i as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize)),
)
}
pub fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U32)))
2015-02-23 03:07:38 +00:00
}
pub fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitKind::Bool(value))
}
pub fn expr_str(&self, sp: Span, s: Symbol) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked))
}
pub fn expr_char(&self, sp: Span, ch: char) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitKind::Char(ch))
}
pub fn expr_byte_str(&self, sp: Span, bytes: Vec<u8>) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(bytes)))
}
/// `[expr1, expr2, ...]`
pub fn expr_array(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr(sp, ast::ExprKind::Array(exprs))
}
/// `&[expr1, expr2, ...]`
pub fn expr_array_ref(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr_addr_of(sp, self.expr_array(sp, exprs))
}
pub fn expr_cast(&self, sp: Span, expr: P<ast::Expr>, ty: P<ast::Ty>) -> P<ast::Expr> {
self.expr(sp, ast::ExprKind::Cast(expr, ty))
}
pub fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
self.expr_call_global(sp, some, vec![expr])
}
pub fn expr_none(&self, sp: Span) -> P<ast::Expr> {
let none = self.std_path(&[sym::option, sym::Option, sym::None]);
self.expr_path(self.path_global(sp, none))
}
pub fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr(sp, ast::ExprKind::Tup(exprs))
}
pub fn expr_fail(&self, span: Span, msg: Symbol) -> P<ast::Expr> {
self.expr_call_global(
span,
[sym::std, sym::rt, sym::begin_panic].iter().map(|s| Ident::new(*s, span)).collect(),
vec![self.expr_str(span, msg)],
2017-06-27 02:26:52 +00:00
)
}
pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
self.expr_fail(span, Symbol::intern("internal error: entered unreachable code"))
}
pub fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]);
self.expr_call_global(sp, ok, vec![expr])
}
pub fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> {
let ok = self.std_path(&[sym::result, sym::Result, sym::Ok]);
let ok_path = self.path_global(sp, ok);
let err = self.std_path(&[sym::result, sym::Result, sym::Err]);
let err_path = self.path_global(sp, err);
let binding_variable = Ident::new(sym::__try_var, sp);
let binding_pat = self.pat_ident(sp, binding_variable);
let binding_expr = self.expr_ident(sp, binding_variable);
// `Ok(__try_var)` pattern
let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]);
// `Err(__try_var)` (pattern and expression respectively)
let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]);
let err_inner_expr =
self.expr_call(sp, self.expr_path(err_path), vec![binding_expr.clone()]);
// `return Err(__try_var)`
let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr)));
// `Ok(__try_var) => __try_var`
let ok_arm = self.arm(sp, ok_pat, binding_expr);
// `Err(__try_var) => return Err(__try_var)`
let err_arm = self.arm(sp, err_pat, err_expr);
// `match head { Ok() => ..., Err() => ... }`
self.expr_match(sp, head, vec![ok_arm, err_arm])
}
2019-09-26 15:18:31 +00:00
pub fn pat(&self, span: Span, kind: PatKind) -> P<ast::Pat> {
P(ast::Pat { id: ast::DUMMY_NODE_ID, kind, span, tokens: None })
}
pub fn pat_wild(&self, span: Span) -> P<ast::Pat> {
2016-02-11 18:16:33 +00:00
self.pat(span, PatKind::Wild)
}
pub fn pat_lit(&self, span: Span, expr: P<ast::Expr>) -> P<ast::Pat> {
2016-02-11 18:16:33 +00:00
self.pat(span, PatKind::Lit(expr))
}
2020-04-19 11:00:18 +00:00
pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> {
2022-08-30 22:34:35 +00:00
self.pat_ident_binding_mode(span, ident, ast::BindingAnnotation::NONE)
}
pub fn pat_ident_binding_mode(
&self,
span: Span,
2020-04-19 11:00:18 +00:00
ident: Ident,
2022-08-30 22:34:35 +00:00
ann: ast::BindingAnnotation,
2014-09-13 16:06:01 +00:00
) -> P<ast::Pat> {
2022-08-30 22:34:35 +00:00
let pat = PatKind::Ident(ann, ident.with_span_pos(span), None);
self.pat(span, pat)
}
pub fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> {
self.pat(span, PatKind::Path(None, path))
}
pub fn pat_tuple_struct(
&self,
span: Span,
path: ast::Path,
subpats: Vec<P<ast::Pat>>,
) -> P<ast::Pat> {
self.pat(span, PatKind::TupleStruct(None, path, subpats))
}
pub fn pat_struct(
&self,
span: Span,
path: ast::Path,
field_pats: Vec<ast::PatField>,
) -> P<ast::Pat> {
self.pat(span, PatKind::Struct(None, path, field_pats, false))
}
pub fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Tuple(pats))
}
pub fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
let some = self.std_path(&[sym::option, sym::Option, sym::Some]);
let path = self.path_global(span, some);
self.pat_tuple_struct(span, path, vec![pat])
}
pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm {
ast::Arm {
attrs: AttrVec::new(),
pat,
guard: None,
2017-08-26 22:09:31 +00:00
body: expr,
2019-03-30 22:54:29 +00:00
span,
2019-08-14 01:22:51 +00:00
id: ast::DUMMY_NODE_ID,
is_placeholder: false,
}
}
pub fn arm_unreachable(&self, span: Span) -> ast::Arm {
self.arm(span, self.pat_wild(span), self.expr_unreachable(span))
}
pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: Vec<ast::Arm>) -> P<Expr> {
self.expr(span, ast::ExprKind::Match(arg, arms))
}
pub fn expr_if(
&self,
span: Span,
cond: P<ast::Expr>,
2014-09-13 16:06:01 +00:00
then: P<ast::Expr>,
els: Option<P<ast::Expr>>,
) -> P<ast::Expr> {
let els = els.map(|x| self.expr_block(self.block_expr(x)));
self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els))
}
2020-04-19 11:00:18 +00:00
pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: P<ast::Expr>) -> P<ast::Expr> {
let fn_decl = self.fn_decl(
2019-09-21 19:05:31 +00:00
ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(),
2020-02-15 03:10:59 +00:00
ast::FnRetTy::Default(span),
);
// FIXME -- We are using `span` as the span of the `|...|`
// part of the lambda, but it probably (maybe?) corresponds to
// the entire lambda body. Probably we should extend the API
// here, but that's not entirely clear.
self.expr(
span,
ast::ExprKind::Closure(Box::new(ast::Closure {
binder: ast::ClosureBinder::NotPresent,
capture_clause: ast::CaptureBy::Ref,
asyncness: ast::Async::No,
movability: ast::Movability::Movable,
fn_decl,
body,
fn_decl_span: span,
})),
)
}
pub fn lambda0(&self, span: Span, body: P<ast::Expr>) -> P<ast::Expr> {
self.lambda(span, Vec::new(), body)
}
2020-04-19 11:00:18 +00:00
pub fn lambda1(&self, span: Span, body: P<ast::Expr>, ident: Ident) -> P<ast::Expr> {
self.lambda(span, vec![ident], body)
}
2020-04-19 11:00:18 +00:00
pub fn lambda_stmts_1(&self, span: Span, stmts: Vec<ast::Stmt>, ident: Ident) -> P<ast::Expr> {
self.lambda1(span, self.expr_block(self.block(span, stmts)), ident)
}
2020-04-19 11:00:18 +00:00
pub fn param(&self, span: Span, ident: Ident, ty: P<ast::Ty>) -> ast::Param {
let arg_pat = self.pat_ident(span, ident);
ast::Param {
2019-12-03 15:38:34 +00:00
attrs: AttrVec::default(),
id: ast::DUMMY_NODE_ID,
pat: arg_pat,
2019-07-26 22:52:37 +00:00
span,
ty,
is_placeholder: false,
}
}
2022-05-28 09:12:34 +00:00
// `self` is unused but keep it as method for the convenience use.
2020-02-15 03:10:59 +00:00
pub fn fn_decl(&self, inputs: Vec<ast::Param>, output: ast::FnRetTy) -> P<ast::FnDecl> {
P(ast::FnDecl { inputs, output })
}
pub fn item(
&self,
span: Span,
name: Ident,
attrs: ast::AttrVec,
2019-09-26 16:51:36 +00:00
kind: ast::ItemKind,
) -> P<ast::Item> {
// FIXME: Would be nice if our generated code didn't violate
// Rust coding conventions
2014-09-13 16:06:01 +00:00
P(ast::Item {
ident: name,
attrs,
2014-09-13 16:06:01 +00:00
id: ast::DUMMY_NODE_ID,
2019-09-26 16:51:36 +00:00
kind,
vis: ast::Visibility {
span: span.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
span,
tokens: None,
2014-09-13 16:06:01 +00:00
})
}
pub fn item_static(
&self,
span: Span,
name: Ident,
ty: P<ast::Ty>,
mutbl: ast::Mutability,
2014-09-13 16:06:01 +00:00
expr: P<ast::Expr>,
) -> P<ast::Item> {
self.item(span, name, AttrVec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr)))
}
pub fn item_const(
&self,
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 15:17:01 +00:00
span: Span,
name: Ident,
ty: P<ast::Ty>,
expr: P<ast::Expr>,
) -> P<ast::Item> {
let def = ast::Defaultness::Final;
self.item(span, name, AttrVec::new(), ast::ItemKind::Const(def, ty, Some(expr)))
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 15:17:01 +00:00
}
pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute {
2022-09-02 08:29:40 +00:00
attr::mk_attr_outer(&self.sess.parse_sess.attr_id_generator, mi)
}
2020-04-19 11:00:18 +00:00
pub fn meta_word(&self, sp: Span, w: Symbol) -> ast::MetaItem {
attr::mk_word_item(Ident::new(w, sp))
}
}