// This file describes nearly all Rust AST types.  It is used by gen/process_ast.py to generate
// impls of various traits for all AST nodes.
//
// There are three types of declarations that can appear in this file.
//  - `struct`s: Similar to Rust struct declarations, except that only field names are given, not
//    their types.  Both "normal" and tuple structs are supported.  In normal structs declarations,
//    the field names must match the actual names of the fields.  For tuple structs, names must
//    still be provided, but they can be chosen arbitrarily (except they must be valid Rust
//    identifiers, i.e., not keywords).
//  - `enum`s: Similar to Rust enum declarations.  Each variant follows the same format as a struct
//    declaration.  Both tuple-like and struct-like variants are supported.
//  - `flag`s: These indicate types with no interesting internal structure, such as `Mutability` (an
//    enum with two nullary variants, `Mutable` and `Immutable`).  The code generators will either
//    ignore these or use a simple default implementation.
//
// Top-level declarations, enum variants, and struct/variant fields may all be prefixed with
// attributes.  The attribute format is `#[attr]` or `#[key=value]` (where `value` is a single
// word).  Consult the doc comments for the code generator modules for information on the supported
// attributes and their effects.


#[no_span]
struct Crate {
    #[seq_rewrite_outer_span='calc_outer_span(&self.attrs, self.spans.inner_span.shrink_to_lo())']
    attrs,
    #[mac_table_seq] items,
    spans,
    id,
    is_placeholder,
}


#[rewrite_print_recover] #[rewrite_seq_item] #[rewrite_extra_strategies=item_header]
#[nonterminal] #[extend_span]
struct Item { ident, #[match=ignore] attrs, id, kind, vis, span, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
enum ItemKind {
    ExternCrate(name),
    Use(vp),
    Static(ty, mutbl, init),
    Const(def, ty, init),
    Fn(fn),
    Mod(unsafety, kind),
    ForeignMod(fm),
    GlobalAsm(asm),
    TyAlias(ta),
    Enum(def, generics),
    Struct(vd, generics),
    Union(vd, generics),
    Trait(trait),
    TraitAlias(generics, bounds),
    Impl(impl),
    MacCall(mac),
    MacroDef(tts),
}

enum Inline {
    Yes,
    No,
}

// Ignore inline because we flip it from false to true when printing (see
// `<Item as PrintParse>::to_string`).
enum ModKind {
    Loaded(#[mac_table_seq] items, #[rewrite_ignore] inline, spans),
    Unloaded,
}

struct ModSpans { inner_span, inject_use_span }

struct TyAliasWhereClause(has_where_token, span);
struct TyAlias { defaultness, generics, where_clauses, where_predicates_split, bounds, ty }

struct Impl {
    defaultness,
    unsafety,
    generics,
    constness,
    polarity,
    of_trait,
    self_ty,
    #[mac_table_seq] items,
}

struct Fn { defaultness, generics, sig, body }

enum Extern {
    None,
    Implicit(span),
    Explicit(s, span),
}

enum UseTreeKind {
    Simple(ident, id1, id2),
    Glob,
    Nested(nested),
}

struct UseTree { kind, prefix, span }

#[extend_span]
struct AssocItem { id, ident, #[match=ignore] attrs, vis, kind, span, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
enum AssocItemKind {
    Const(defaultness, ty, init),
    Fn(fn),
    TyAlias(ta),
    MacCall(mac),
}

struct TraitRef { path, ref_id }

struct EnumDef { variants }
#[extend_span]
struct Variant { #[match=ignore] attrs, id, span, vis, ident, data, disr_expr, is_placeholder }
enum VariantData {
    Struct(fields, recovered),
    Tuple(fields, id),
    Unit(id),
}

#[extend_span]
struct FieldDef { #[match=ignore] attrs, id, span, vis, ident, ty, is_placeholder }

struct ForeignMod { unsafety, abi, #[mac_table_seq] items }
#[rewrite_print_recover] #[rewrite_seq_item] #[extend_span]
struct ForeignItem { ident, #[match=ignore] attrs, kind, id, span, vis, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
enum ForeignItemKind {
    Fn(fn),
    Static(ty, mutbl, init),
    TyAlias(ta),
    MacCall(mac),
}


struct Generics { params, where_clause, span }
#[extend_span]
struct GenericParam { id, ident, attrs, bounds, is_placeholder, kind, colon_span }
enum GenericParamKind {
    Lifetime,
    Type { default },
    Const { ty, kw_span, default },
}
struct WhereClause { has_where_token, predicates, span }
enum WherePredicate {
    BoundPredicate(pred),
    RegionPredicate(pred),
    EqPredicate(pred),
}

struct WhereBoundPredicate { span, bounded_ty, bounds, bound_generic_params }
struct WhereRegionPredicate { span, lifetime, bounds }
struct WhereEqPredicate { id, span, lhs_ty, rhs_ty }

enum TraitBoundModifier {
    None,
    Maybe,
    MaybeConst,
    MaybeConstMaybe,
}

#[match=ignore]
struct Visibility { kind, span, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }

#[match=ignore]
enum VisibilityKind {
    Public,
    Restricted { path, id },
    Inherited,
}

#[match=custom] #[rewrite_print_recover] #[mac_table_record] #[nonterminal]
struct Ty { id, kind, span, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
struct MutTy { ty, mutbl }
enum TyKind {
    Slice(ty),
    Array(ty, len),
    Ptr(mty),
    Rptr(lt, mty),
    BareFn(ty),
    Never,
    Tup(tys),
    Path(qself, path),
    TraitObject(bounds, trait_object_syntax),
    ImplTrait(id, bounds),
    Paren(ty),
    Typeof(expr),
    Infer,
    ImplicitSelf,
    #[mac_table_record] MacCall(mac),
    Err,
    CVarArgs,
}

enum TraitObjectSyntax {
    Dyn,
    None,
}

enum LitIntType {
    Signed(ty),
    Unsigned(ty),
    Unsuffixed,
}

enum IntTy {
    Isize,
    I8,
    I16,
    I32,
    I64,
    I128,
}

enum UintTy {
    Usize,
    U8,
    U16,
    U32,
    U64,
    U128,
}

enum FloatTy {
    F32,
    F64,
}

struct AssocConstraint { id, ident, gen_args, kind, span }
enum AssocConstraintKind {
    Equality { term },
    Bound { bounds },
}
enum Term {
    Ty(ty),
    Const(const),
}

#[boxed]
struct BareFnTy { unsafety, ext, generic_params, decl, decl_span }
struct Lifetime { id, ident }
enum GenericBound {
    Trait(poly_trait_ref, modifier),
    Outlives(lt),
}

struct PolyTraitRef { bound_generic_params, trait_ref, span }

struct FnSig { header, decl, span }

struct FnDecl { inputs, output }
struct FnHeader { unsafety, asyncness, constness, ext }
#[rewrite_print]
struct Param { attrs, ty, pat, id, span, is_placeholder }
enum FnRetTy {
    Default(span),
    Ty(ty),
}

struct Trait {
    unsafety,
    is_auto,
    generics,
    bounds,
    items,
}

#[match=custom] #[rewrite_print_recover] #[rewrite_seq_item] #[nonterminal]
struct Stmt { id, kind, span }
#[no_debug]
enum StmtKind {
    Local(local),
    Item(item),
    Expr(expr),
    Semi(expr),
    Empty,
    MacCall(mac),
}

#[extend_span]
struct Local { id, pat, ty, kind, span, #[match=ignore] attrs, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
enum LocalKind {
    Decl,
    Init(expr),
    InitElse(expr, block),
}


#[match=custom] #[rewrite_print_recover] #[extend_span] #[mac_table_record] #[nonterminal]
struct Expr { id, kind, span, #[match=ignore] attrs, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
#[prec_contains_expr]
enum ExprKind {
    Box(#[prec=PREFIX] expr),
    Array(#[mac_table_seq] elems),
    ConstBlock(anon_const),
    Call(#[prec=POSTFIX] #[prec_special=Callee] func, #[mac_table_seq] args),
    MethodCall(path_seg, #[prec_first=POSTFIX] #[mac_table_seq] args, span),
    Tup(#[mac_table_seq] elems),
    Binary(op, #[prec_left_of_binop=op] a, #[prec_right_of_binop=op] b),
    Unary(op, #[prec=PREFIX] a),
    Lit(lit),
    Cast(#[prec=As] expr, ty),
    Type(#[prec=Colon] expr, ty),
    Let(pats, #[prec_special=Cond] expr, span),
    If(#[prec_special=Cond] cond, then_body, else_body),
    While(#[prec_special=Cond] cond, body, label),
    ForLoop(pat, #[prec_special=Cond] iter, body, label),
    Loop(body, label),
    Match(#[prec_special=Cond] target, arms),
    Closure(binder, cap, is_async, mov, decl, body, span),
    Block(body, label),
    Async(cap, id, block),
    Await(expr),
    TryBlock(body),
    Assign(#[lvalue_mut] #[prec_inc=Assign] lhs, #[prec=Assign] rhs, span),
    AssignOp(op, #[lvalue_mut] #[prec_inc=Assign] lhs, #[prec=Assign] rhs),
    Field(#[lr_propagate] #[prec=POSTFIX] expr, ident),
    Index(#[lr_propagate] #[prec=POSTFIX] arr, idx),
    // 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.)
    Range(#[prec=LOr] lo, #[prec=LOr] hi, limits),
    Underscore,
    Path(qself, path),
    AddrOf(borrowkind, mutbl, #[lvalue_kind=mutbl] #[prec=PREFIX] expr),
    Break(label, #[prec=JUMP] expr),
    Continue(label),
    Ret(#[prec=JUMP] expr),
    InlineAsm(asm),
    #[mac_table_record] MacCall(mac),
    Struct(expr),
    Repeat(item, count),
    Paren(expr),
    Try(#[prec=POSTFIX] expr),
    Yield(#[prec=JUMP] expr),
    Yeet(expr),
    Err,
}

struct StructExpr {
    qself,
    path,
    fields,
    rest,
}

enum StructRest {
    Base(expr),
    Rest(span),
    None,
}

enum Movability {
    Static,
    Movable,
}

enum ClosureBinder {
    NotPresent,
    For { span, generic_params },
}

enum UnOp {
    Deref,
    Not,
    Neg,
}
enum BinOpKind {
    Add,
    Sub,
    Mul,
    Div,
    Rem,
    And,
    Or,
    BitXor,
    BitAnd,
    BitOr,
    Shl,
    Shr,
    Eq,
    Lt,
    Le,
    Ne,
    Ge,
    Gt,
}

#[extend_span]
struct ExprField { attrs, id, span, ident, expr, is_shorthand, is_placeholder }
#[extend_span]
struct PatField { ident, pat, is_shorthand, attrs, id, span, is_placeholder }
#[extend_span]
struct Arm { attrs, pat, guard, body, span, id, is_placeholder }
#[match=custom] #[rewrite_print_recover] #[nonterminal]
struct Block {
    #[mac_table_seq] stmts,
    id,
    rules,
    span,
    #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens,
    could_be_bare_literal,
}


#[match=custom] #[mac_table_record] #[nonterminal]
struct Pat { id, kind, span, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
enum PatKind {
    Wild,
    Ident(mode, id, pat),
    Struct(qself, path, fields, dotdot),
    TupleStruct(qself, path, fields),
    Or(paths),
    Path(qself, path),
    Tuple(pats),
    Box(pat),
    Ref(pat, mutbl),
    Lit(expr),
    Range(lo, hi, end),
    Slice(pats),
    Rest,
    Paren(pat),
    #[mac_table_record] MacCall(mac),
}

#[match=custom]
struct Lit { token, kind, span }

struct StrLit { style, symbol, suffix, span, symbol_unescaped }

enum LitKind {
    Str(sym, style),
    ByteStr(bytes),
    Byte(x),
    Char(x),
    Int(x, ty),
    Float(sym, ty),
    Bool(x),
    Err(sym),
}

enum LitFloatType {
    Suffixed(ty),
    Unsuffixed,
}

struct TokenLit { kind, symbol, suffix }

enum TokenLitKind {
    Bool,
    Byte,
    Char,
    Integer,
    Float,
    Str,
    StrRaw(n),
    ByteStr,
    ByteStrRaw(n),
    Err,
}

enum Defaultness {
    Default(span),
    Final,
}

enum Const {
    Yes(span),
    No,
}

enum ImplPolarity {
    Positive,
    Negative(span),
}

enum IsAuto {
    Yes,
    No,
}

enum Unsafe {
    Yes(span),
    No,
}

enum Async {
    Yes { span, closure_id, return_impl_trait_id },
    No,
}

flag Abi;
enum Mutability {
    Mut,
    Not,
}

enum BorrowKind {
    Ref,
    Raw,
}

enum RangeEnd {
    Included(syntax),
    Excluded,
}
enum RangeSyntax {
    DotDotDot,
    DotDotEq,
}
enum BindingMode {
    ByRef(mutbl),
    ByValue(mutbl),
}
enum CaptureBy {
    Value,
    Ref,
}
enum BlockCheckMode {
    Default,
    Unsafe(source),
}
enum UnsafeSource {
    CompilerGenerated,
    UserProvided,
}
enum StrStyle {
    Cooked,
    Raw(n),
}
enum RangeLimits {
    HalfOpen,
    Closed,
}


#[no_node_id] #[rewrite_print] #[rewrite_custom=SeqItem]
struct Attribute { kind, id, style, span }
enum AttrKind {
    Normal(item, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens),
    DocComment(kind, symbol),
}
struct AttrItem { path, args, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
enum AttrStyle {
    Outer,
    Inner,
}

enum CommentKind {
    Line,
    Block,
}

#[match=custom] #[nonterminal]
struct Path { span, segments, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens }
struct PathSegment { ident, id, args }

enum GenericArgs {
    AngleBracketed(abpd),
    Parenthesized(ppd),
}
struct AngleBracketedArgs { span, args }
enum AngleBracketedArg {
    Arg(arg),
    Constraint(cons),
}
struct ParenthesizedArgs { span, inputs, inputs_span, output }
enum GenericArg {
    Lifetime(lt),
    Type(ty),
    Const(c),
}
struct QSelf { ty, path_span, position }


struct MacCallStmt {
    mac,
    style,
    #[match=ignore] attrs,
    #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens,
}
struct MacCall { path, args, prior_type_ascription }
enum MacStmtStyle {
    Semicolon,
    Braces,
    NoBraces,
}
#[equiv_mode=ignore]
flag TokenStream;
#[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore]
flag LazyTokenStream;
struct MacroDef { body, macro_rules }

enum MacArgs {
    Empty,
    Delimited(span, delim, #[equiv_mode=ignore] #[match=ignore] #[rewrite_ignore] tokens),
    Eq(span, value),
}

enum MacArgsEq {
    Ast(expr),
    Hir(lit),
}

struct InlineAsm {
    template,
    template_strs,
    operands,
    clobber_abis,
    options,
    line_spans,
}
enum InlineAsmTemplatePiece {
    String(s),
    Placeholder { operand_idx, modifier, span },
}
enum InlineAsmOperand {
    In { reg, expr },
    Out { reg, late, expr },
    InOut { reg, late, expr },
    SplitInOut { reg, late, in_expr, out_expr },
    Const { anon_const },
    Sym { sym },
}
enum InlineAsmRegOrRegClass {
    Reg(symbol),
    RegClass(symbol),
}
struct InlineAsmSym { id, qself, path }
#[match=eq] flag InlineAsmOptions;

#[match=custom] struct Label { ident }

enum MacDelimiter {
    Parenthesis,
    Bracket,
    Brace,
}

struct AnonConst {
    id,
    value,
}

#[match=custom] #[equiv_mode=custom] struct Ident { name, span }
#[match=eq] flag Symbol;
#[equiv_mode=ignore] #[match=eq] flag SyntaxContext;

#[equiv_mode=ignore] #[rewrite_ignore]
flag Span;
#[equiv_mode=ignore] #[rewrite_ignore] #[list_node_ids=custom] #[mac_table_custom]
flag NodeId;
#[equiv_mode=ignore] #[rewrite_ignore]
flag AttrId;

flag usize;
#[match=eq] flag bool;
#[match=eq] flag u128;
#[match=eq] flag u16;
#[match=eq] flag u8;
#[match=eq] flag char;
#[match=eq] flag String;


enum Nonterminal {
    NtItem(i),
    NtBlock(b),
    NtStmt(s),
    NtPat(p),
    NtExpr(y),
    NtTy(t),
    NtIdent(i, raw),
    NtLifetime(ident),
    NtLiteral(expr),
    NtMeta(m),
    NtPath(p),
    NtVis(v),
}

enum TokenTree {
    Token(t, spacing),
    Delimited(span, d, tts),
}

struct DelimSpan { open, close }

enum Delimiter {
    Parenthesis,
    Bracket,
    Brace,
    Invisible,
}

struct Token { kind, span }

enum TokenKind {
    Eq,
    Lt,
    Le,
    EqEq,
    Ne,
    Ge,
    Gt,
    AndAnd,
    OrOr,
    Not,
    Tilde,
    BinOp(op),
    BinOpEq(op),
    At,
    Dot,
    DotDot,
    DotDotDot,
    DotDotEq,
    Comma,
    Semi,
    Colon,
    ModSep,
    RArrow,
    LArrow,
    FatArrow,
    Pound,
    Dollar,
    Question,
    SingleQuote,
    OpenDelim(delim),
    CloseDelim(delim),
    Literal(lit),
    Ident(s, is_raw),
    Lifetime(s),
    Interpolated(nt),
    DocComment(kind, style, symbol),
    Eof,
}

enum BinOpToken {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    Caret,
    And,
    Or,
    Shl,
    Shr,
}

enum Spacing {
    Alone,
    Joint,
}

#[fold_kind=MetaItemKind]
struct MetaItem { path, kind, span }
enum MetaItemKind {
    Word,
    List(l),
    NameValue(lit),
}
enum NestedMetaItem {
    MetaItem(mi),
    Literal(lit),
}
