// Source: https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/ast.rs

module rec Fable.Transforms.Rust.AST.Types

open Fable.Transforms.Rust.AST.Adapters
open Fable.Transforms.Rust.AST.Spans

//! The Rust abstract syntax tree module.
//!
//! This module contains common structures forming the language AST.
//! Two main entities in the module are [`Item`] (which represents an AST element with
//! additional metadata), and [`ItemKind`] (which represents a concrete type and contains
//! information specific to the type of the item).
//!
//! Other module items worth mentioning:
//! - [`Ty`] and [`TyKind`]: A parsed Rust type.
//! - [`Expr`] and [`ExprKind`]: A parsed Rust expression.
//! - [`Pat`] and [`PatKind`]: A parsed Rust pattern. Patterns are often dual to expressions.
//! - [`Stmt`] and [`StmtKind`]: An executable action that does not return a value.
//! - [`FnDecl`], [`FnHeader`] and [`Param`]: Metadata associated with a function declaration.
//! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters.
//! - [`EnumDef`] and [`Variant`]: Enum declaration.
//! - [`Lit`] and [`LitKind`]: Literal expressions.
//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimiter`]: Macro definition and invocation.
//! - [`Attribute`]: Metadata associated with item.
//! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.


// Source: https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/token.rs
module token =

    [<RequireQualifiedAccess>]
    type CommentKind =
        | Line
        | Block

    [<RequireQualifiedAccess>]
    type BinOpToken =
        | Plus
        | Minus
        | Star
        | Slash
        | Percent
        | Caret
        | And
        | Or
        | Shl
        | Shr

    /// A delimiter token.
    [<RequireQualifiedAccess>]
    type DelimToken =
        /// A round parenthesis (i.e., `(` or `)`).
        | Paren
        /// A square bracket (i.e., `[` or `]`).
        | Bracket
        /// A curly brace (i.e., `{` or `}`).
        | Brace
        /// An empty delimiter.
        | NoDelim

    [<RequireQualifiedAccess>]
    type LitKind =
        | Bool
        | Byte
        | Char
        | Integer
        | Float
        | Str
        | StrRaw of u16
        | ByteStr
        | ByteStrRaw of u16
        | Err

    /// A literal token.
    type Lit =
        {
            kind: LitKind
            symbol: Symbol
            suffix: Option<Symbol>
        }

    [<RequireQualifiedAccess>]
    type TokenKind =
        // Expression-operator symbols.
        | Eq
        | Lt
        | Le
        | EqEq
        | Ne
        | Ge
        | Gt
        | AndAnd
        | OrOr
        | Not
        | Tilde
        | BinOp of BinOpToken
        | BinOpEq of BinOpToken

        // Structural symbols
        | At
        | Dot
        | DotDot
        | DotDotDot
        | DotDotEq
        | Comma
        | Semi
        | Colon
        | ModSep
        | RArrow
        | LArrow
        | FatArrow
        | Pound
        | Dollar
        | Question
        /// Used by proc macros for representing lifetimes, not generated by lexer right now.
        | SingleQuote
        /// An opening delimiter (e.g., `{`).
        | OpenDelim of DelimToken
        /// A closing delimiter (e.g., `}`).
        | CloseDelim of DelimToken

        // Literals
        | Literal of Lit

        /// Identifier token.
        /// Do not forget about `NtIdent` when you want to match on identifiers.
        /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
        /// treat regular and interpolated identifiers in the same way.
        | Ident of Symbol * is_raw: bool
        /// Lifetime identifier token.
        /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
        /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
        /// treat regular and interpolated lifetime identifiers in the same way.
        | Lifetime of Symbol

        | Interpolated of Lrc<Nonterminal>

        /// A doc comment token.
        /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
        /// similarly to symbols in string literal tokens.
        | DocComment of CommentKind * AttrStyle * Symbol

        | Eof

    type Token =
        {
            kind: TokenKind
            span: Span
        }

    /// For interpolation during macro expansion.
    [<RequireQualifiedAccess>]
    type Nonterminal =
        | NtItem of P<Item>
        | NtBlock of P<Block>
        | NtStmt of Stmt
        | NtPat of P<Pat>
        | NtExpr of P<Expr>
        | NtTy of P<Ty>
        | NtIdent of Ident * is_raw: bool
        | NtLifetime of Ident
        | NtLiteral of P<Expr>
        /// Stuff inside brackets for attributes
        | NtMeta of P<AttrItem>
        | NtPath of Path
        | NtVis of Visibility
        | NtTT of TokenTree

    // Source: https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/tokenstream.rs

    [<RequireQualifiedAccess>]
    type TokenTree =
        /// A single token.
        | Token of Token
        /// A delimited sequence of token trees.
        | Delimited of DelimSpan * DelimToken * TokenStream

    /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
    ///
    /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
    /// instead of a representation of the abstract syntax tree.
    /// Today's `TokenTree`s can still contain AST via `token.Interpolated` for
    /// backwards compatibility.
    type TokenStream = Lrc<Vec<TreeAndSpacing>>

    type TreeAndSpacing = (TokenTree * Spacing)

    [<RequireQualifiedAccess>]
    type Spacing =
        | Alone
        | Joint

    type DelimSpan =
        {
            open_: Span
            close: Span
        }

type LazyTokenStream = System.Lazy<token.TokenStream>

// Source: https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/ast.rs

/// A "Label" is an identifier of some point in sources,
/// e.g. in the following code:
///
/// ```rust
/// 'outer: loop {
///     break 'outer;
/// }
/// ```
///
/// `'outer` is a label.
type Label = { ident: Ident }

/// A "Lifetime" is an annotation of the scope in which variable
/// can be used, e.g. `'a` in `&'a i32`.
type Lifetime =
    {
        id: NodeId
        ident: Ident
    }

/// A "Path" is essentially Rust's notion of a name.
///
/// It's represented as a sequence of identifiers,
/// along with a bunch of supporting information.
///
/// E.g., `std::cmp::PartialEq`.
type Path =
    {
        span: Span
        /// The segments in the path: the things separated by `::`.
        /// Global paths begin with `kw::PathRoot`.
        segments: Vec<PathSegment>
        tokens: Option<LazyTokenStream>
    }

/// A segment of a path: an identifier, an optional lifetime, and a set of types.
///
/// E.g., `std`, `String` or `Box<T>`.
type PathSegment =
    {
        /// The identifier portion of this path segment.
        ident: Ident

        id: NodeId

        /// Type/lifetime parameters attached to this path. They come in
        /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`.
        /// `None` means that no parameter list is supplied (`Path`)
        /// `Some` means that parameter list is supplied (`Path<X, Y>`)
        /// but it can be empty (`Path<>`).
        /// `P` is used as a size optimization for the common case with no parameters.
        args: Option<P<GenericArgs>>
    }

/// The arguments of a path segment.
///
/// E.g., `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`.
[<RequireQualifiedAccess>]
type GenericArgs =
    /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`.
    | AngleBracketed of AngleBracketedArgs
    /// The `(A, B)` and `C` in `Foo(A, B) -> C`.
    | Parenthesized of ParenthesizedArgs

/// Concrete argument in the sequence of generic args.
[<RequireQualifiedAccess>]
type GenericArg =
    /// `'a` in `Foo<'a>`
    | Lifetime of Lifetime
    /// `Bar` in `Foo<Bar>`
    | Type of P<Ty>
    /// `1` in `Foo<1>`
    | Const of AnonConst

/// A path like `Foo<'a, T>`.
type AngleBracketedArgs =
    {
        /// The overall span.
        span: Span
        /// The comma separated parts in the `<...>`.
        args: Vec<AngleBracketedArg>
    }

/// Either an argument for a parameter e.g., `'a`, `Vec<u8>`, `0`,
/// or a constraint on an associated item, e.g., `Item = String` or `Item: Bound`.
[<RequireQualifiedAccess>]
type AngleBracketedArg =
    /// Argument for a generic parameter.
    | Arg of GenericArg
    /// Constraint for an associated item.
    | Constraint of AssocTyConstraint

/// A path like `Foo(A, B) -> C`.
type ParenthesizedArgs =
    {
        /// ```text
        /// Foo(A, B) -> C
        /// ^^^^^^^^^^^^^^
        /// ```
        span: Span

        /// `(A, B)`
        inputs: Vec<P<Ty>>

        /// ```text
        /// Foo(A, B) -> C
        ///    ^^^^^^
        /// ```
        inputs_span: Span

        /// `C`
        output: FnRetTy
    }

/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
///
/// Negative bounds should also be handled here.
[<RequireQualifiedAccess>]
type TraitBoundModifier =
    /// No modifiers
    | None

    /// `?Trait`
    | Maybe

    /// `?const Trait`
    | MaybeConst

    /// `?const ?Trait`
    //
    // This parses but will be rejected during AST validation.
    | MaybeConstMaybe

/// The AST represents all type param bounds as types.
/// `typeck::collect::compute_bounds` matches these against
/// the "special" built-in traits (see `middle::lang_items`) and
/// detects `Copy`, `Send` and `Sync`.
[<RequireQualifiedAccess>]
type GenericBound =
    | Trait of PolyTraitRef * TraitBoundModifier
    | Outlives of Lifetime

type GenericBounds = Vec<GenericBound>

/// Specifies the enforced ordering for generic parameters. In the future,
/// if we wanted to relax this order, we could override `PartialEq` and
/// `PartialOrd`, to allow the kinds to be unordered.
[<RequireQualifiedAccess>]
type ParamKindOrd =
    | Lifetime
    | Type
    // `unordered` is only `true` if `sess.has_features().const_generics`
    // is active. Specifically, if it's only `min_const_generics`, it will still require
    // ordering consts after types.
    | Const of unordered: bool

[<RequireQualifiedAccess>]
type GenericParamKind =
    /// A lifetime definition (e.g., `'a: 'b + 'c + 'd`).
    | Lifetime
    | Type of default_: Option<P<Ty>>
    | Const of
        ty: P<Ty> *
        /// Span of the `const` keyword.
        kw_span: Span *
        /// Optional default value for the const generic param
        default_: Option<AnonConst>

type GenericParam =
    {
        id: NodeId
        ident: Ident
        attrs: AttrVec
        bounds: GenericBounds
        is_placeholder: bool
        kind: GenericParamKind
    }

/// Represents lifetime, type and const parameters attached to a declaration of
/// a function, enum, trait, etc.
type Generics =
    {
        params_: Vec<GenericParam>
        where_clause: WhereClause
        span: Span
    }

/// A where-clause in a definition.
type WhereClause =
    {
        /// `true` if we ate a `where` token: this can happen
        /// if we parsed no predicates (e.g. `struct Foo where {}`).
        /// This allows us to accurately pretty-print
        /// in `nt_to_tokenstream`
        has_where_token: bool
        predicates: Vec<WherePredicate>
        span: Span
    }

/// A single predicate in a where-clause.
[<RequireQualifiedAccess>]
type WherePredicate =
    /// A type binding (e.g., `for<'c> Foo: Send + Clone + 'c`).
    | BoundPredicate of WhereBoundPredicate
    /// A lifetime predicate (e.g., `'a: 'b + 'c`).
    | RegionPredicate of WhereRegionPredicate
    /// An equality predicate (unsupported).
    | EqPredicate of WhereEqPredicate

/// A type bound.
///
/// E.g., `for<'c> Foo: Send + Clone + 'c`.
type WhereBoundPredicate =
    {
        span: Span
        /// Any generics from a `for` binding.
        bound_generic_params: Vec<GenericParam>
        /// The type being bounded.
        bounded_ty: P<Ty>
        /// Trait and lifetime bounds (`Clone + Send + 'static`).
        bounds: GenericBounds
    }

/// A lifetime predicate.
///
/// E.g., `'a: 'b + 'c`.
type WhereRegionPredicate =
    {
        span: Span
        lifetime: Lifetime
        bounds: GenericBounds
    }

/// An equality predicate (unsupported).
///
/// E.g., `T = int`.
type WhereEqPredicate =
    {
        id: NodeId
        span: Span
        lhs_ty: P<Ty>
        rhs_ty: P<Ty>
    }

type Crate =
    {
        attrs: Vec<Attribute>
        items: Vec<P<Item>>
        span: Span
        /// The order of items in the HIR is unrelated to the order of
        /// items in the AST. However, we generate proc macro harnesses
        /// based on the AST order, and later refer to these harnesses
        /// from the HIR. This field keeps track of the order in which
        /// we generated proc macros harnesses, so that we can map
        /// HIR proc macros items back to their harness items.
        proc_macros: Vec<NodeId>
    }

/// Possible values inside of compile-time attribute lists.
///
/// E.g., the '..' in `#[name(..)]`.
[<RequireQualifiedAccess>]
type NestedMetaItem =
    /// A full MetaItem, for recursive meta items.
    | MetaItem of MetaItem
    /// A literal.
    ///
    /// E.g., `"foo"`, `64`, `true`.
    | Literal of Lit

/// A spanned compile-time attribute item.
///
/// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
type MetaItem =
    {
        path: Path
        kind: MetaItemKind
        span: Span
    }

/// A compile-time attribute item.
///
/// E.g., `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`.
[<RequireQualifiedAccess>]
type MetaItemKind =
    /// Word meta item.
    ///
    /// E.g., `test` as in `#[test]`.
    | Word
    /// List meta item.
    ///
    /// E.g., `derive(..)` as in `#[derive(..)]`.
    | List of Vec<NestedMetaItem>
    /// Name value meta item.
    ///
    /// E.g., `feature = "foo"` as in `#[feature = "foo"]`.
    | NameValue of Lit

/// A block (`{ .. }`).
///
/// E.g., `{ .. }` as in `fn foo() { .. }`.
type Block =
    {
        /// The statements in the block.
        stmts: Vec<Stmt>
        id: NodeId
        /// Distinguishes between `unsafe { ... }` and `{ ... }`.
        rules: BlockCheckMode
        span: Span
        tokens: Option<LazyTokenStream>
    }

/// A match pattern.
///
/// Patterns appear in match statements and some other contexts, such as `let` and `if let`.
type Pat =
    {
        id: NodeId
        kind: PatKind
        span: Span
        tokens: Option<LazyTokenStream>
    }

/// A single field in a struct pattern.
///
/// Patterns like the fields of `Foo { x, ref y, ref mut z }`
/// are treated the same as `x: x, y: ref y, z: ref mut z`,
/// except when `is_shorthand` is true.
type PatField =
    {
        /// The identifier for the field.
        ident: Ident
        /// The pattern the field is destructured to.
        pat: P<Pat>
        is_shorthand: bool
        attrs: AttrVec
        id: NodeId
        span: Span
        is_placeholder: bool
    }

[<RequireQualifiedAccess>]
type BindingMode =
    | ByRef of Mutability
    | ByValue of Mutability

[<RequireQualifiedAccess>]
type RangeEnd =
    | Included of RangeSyntax
    | Excluded

[<RequireQualifiedAccess>]
type RangeSyntax =
    /// `...`
    | DotDotDot
    /// `..=`
    | DotDotEq

[<RequireQualifiedAccess>]
type PatKind =
    /// Represents a wildcard pattern (`_`).
    | Wild

    /// A `PatKind::Ident` may either be a new bound variable (`ref mut binding @ OPT_SUBPATTERN`)
    /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
    /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
    /// during name resolution.
    | Ident of BindingMode * Ident * Option<P<Pat>>

    /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
    /// The `bool` is `true` in the presence of a `..`.
    | Struct of Path * Vec<PatField> * recovered: bool

    /// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
    | TupleStruct of Path * Vec<P<Pat>>

    /// An or-pattern `A | B | C`.
    /// Invariant: `pats.len() >= 2`.
    | Or of Vec<P<Pat>>

    /// A possibly qualified path pattern.
    /// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
    /// or associated constants. Qualified path patterns `<A>::B::C`/`<A as Trait>::B::C` can
    /// only legally refer to associated constants.
    | Path of Option<QSelf> * Path

    /// A tuple pattern (`(a, b)`).
    | Tuple of Vec<P<Pat>>

    /// A `box` pattern.
    | Box of P<Pat>

    /// A reference pattern (e.g., `&mut (a, b)`).
    | Ref of P<Pat> * Mutability

    /// A literal.
    | Lit of P<Expr>

    /// A range pattern (e.g., `1...2`, `1..=2` or `1..2`).
    | Range of Option<P<Expr>> * Option<P<Expr>> * Spanned<RangeEnd>

    /// A slice pattern `[a, b, c]`.
    | Slice of Vec<P<Pat>>

    /// A rest pattern `..`.
    ///
    /// Syntactically it is valid anywhere.
    ///
    /// Semantically however, it only has meaning immediately inside:
    /// - a slice pattern: `[a, .., b]`
    /// - a binding pattern immediately inside a slice pattern: `[a, r @ ..]`
    /// - a tuple pattern: `(a, .., b)`
    /// - a tuple struct/variant pattern: `$path(a, .., b)`.
    ///
    /// In all of these cases, an additional restriction applies
    /// only one rest pattern may occur in the pattern sequences.
    | Rest

    /// Parentheses in patterns used for grouping (i.e., `(PAT)`).
    | Paren of P<Pat>

    /// A macro pattern; pre-expansion.
    | MacCall of MacCall

[<RequireQualifiedAccess>]
type Mutability =
    | Mut
    | Not

/// The kind of borrow in an `AddrOf` expression,
/// e.g., `&place` or `&raw const place`.
[<RequireQualifiedAccess>]
type BorrowKind =
    /// A normal borrow, `&$expr` or `&mut $expr`.
    /// The resulting type is either `&'a T` or `&'a mut T`
    /// where `T = typeof($expr)` and `'a` is some lifetime.
    | Ref
    /// A raw borrow, `&raw const $expr` or `&raw mut $expr`.
    /// The resulting type is either `*const T` or `*mut T`
    /// where `T = typeof($expr)`.
    | Raw

[<RequireQualifiedAccess>]
type BinOpKind =
    /// The `+` operator (addition)
    | Add
    /// The `-` operator (subtraction)
    | Sub
    /// The `*` operator (multiplication)
    | Mul
    /// The `/` operator (division)
    | Div
    /// The `%` operator (modulus)
    | Rem
    /// The `&&` operator (logical and)
    | And
    /// The `||` operator (logical or)
    | Or
    /// The `^` operator (bitwise xor)
    | BitXor
    /// The `&` operator (bitwise and)
    | BitAnd
    /// The `|` operator (bitwise or)
    | BitOr
    /// The `<<` operator (shift left)
    | Shl
    /// The `>>` operator (shift right)
    | Shr
    /// The `==` operator (equality)
    | Eq
    /// The `<` operator (less than)
    | Lt
    /// The `<=` operator (less than or equal to)
    | Le
    /// The `!=` operator (not equal to)
    | Ne
    /// The `>=` operator (greater than or equal to)
    | Ge
    /// The `>` operator (greater than)
    | Gt

type BinOp = Spanned<BinOpKind>

/// Unary operator.
///
/// Note that `&data` is not an operator, it's an `AddrOf` expression.
[<RequireQualifiedAccess>]
type UnOp =
    /// The `*` operator for dereferencing
    | Deref
    /// The `!` operator for logical inversion
    | Not
    /// The `-` operator for negation
    | Neg

/// A statement
type Stmt =
    {
        id: NodeId
        kind: StmtKind
        span: Span
    }

[<RequireQualifiedAccess>]
type StmtKind =
    /// A local (let) binding.
    | Local of P<Local>
    /// An item definition.
    | Item of P<Item>
    /// Expr without trailing semi-colon.
    | Expr of P<Expr>
    /// Expr with a trailing semi-colon.
    | Semi of P<Expr>
    /// Just a trailing semi-colon.
    | Empty
    /// Macro.
    | MacCall of P<MacCallStmt>

type MacCallStmt =
    {
        mac: MacCall
        style: MacStmtStyle
        attrs: AttrVec
        tokens: Option<LazyTokenStream>
    }

[<RequireQualifiedAccess>]
type MacStmtStyle =
    /// The macro statement had a trailing semicolon (e.g., `foo! { ... };`
    /// `foo!(...);`, `foo![...];`).
    | Semicolon
    /// The macro statement had braces (e.g., `foo! { ... }`).
    | Braces
    /// The macro statement had parentheses or brackets and no semicolon (e.g.
    /// `foo!(...)`). All of these will end up being converted into macro
    /// expressions.
    | NoBraces

/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`.
type Local =
    {
        id: NodeId
        pat: P<Pat>
        ty: Option<P<Ty>>
        /// Initializer expression to set the value, if any.
        init: Option<P<Expr>>
        span: Span
        attrs: AttrVec
        tokens: Option<LazyTokenStream>
    }

/// An arm of a 'match'.
///
/// E.g., `0..=10 => { println!("match!") }` as in
///
/// ```
/// match 123 {
///     0..=10 => { println!("match!") },
///     _ => { println!("no match!") },
/// }
/// ```
type Arm =
    {
        attrs: Vec<Attribute>
        /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`
        pat: P<Pat>
        /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`
        guard: Option<P<Expr>>
        /// Match arm body.
        body: P<Expr>
        span: Span
        id: NodeId
        is_placeholder: bool
    }

/// A single field in a struct expression, e.g. `x: value` and `y` in `Foo { x: value, y }`.
type ExprField =
    {
        attrs: AttrVec
        id: NodeId
        span: Span
        ident: Ident
        expr: P<Expr>
        is_shorthand: bool
        is_placeholder: bool
    }

[<RequireQualifiedAccess>]
type BlockCheckMode =
    | Default
    | Unsafe of UnsafeSource

[<RequireQualifiedAccess>]
type UnsafeSource =
    | CompilerGenerated
    | UserProvided

/// A constant (expression) that's not an item or associated item,
/// but needs its own `DefId` for type-checking, const-eval, etc.
/// These are usually found nested inside types (e.g., array lengths)
/// or expressions (e.g., repeat counts), and also used to define
/// explicit discriminant values for enum variants.
type AnonConst =
    {
        id: NodeId
        value: P<Expr>
    }

/// An expression.
type Expr =
    {
        id: NodeId
        kind: ExprKind
        span: Span
        attrs: AttrVec
        tokens: Option<LazyTokenStream>
    }

/// Limit types of a range (inclusive or exclusive)
[<RequireQualifiedAccess>]
type RangeLimits =
    /// Inclusive at the beginning, exclusive at the end
    | HalfOpen
    /// Inclusive at the beginning and end
    | Closed

[<RequireQualifiedAccess>]
type StructRest =
    /// `..x`.
    | Base of P<Expr>
    /// `..`.
    | Rest of Span
    /// No trailing `..` or expression.
    | None

type StructExpr =
    {
        path: Path
        fields: Vec<ExprField>
        rest: StructRest
    }

[<RequireQualifiedAccess>]
type ExprKind =
    /// A `box x` expression.
    | Box of P<Expr>
    /// An array (`[a, b, c, d]`)
    | Array of Vec<P<Expr>>
    /// Allow anonymous constants from an inline `const` block
    | ConstBlock of AnonConst
    /// A function call
    ///
    /// The first field resolves to the function itself
    /// and the second field is the list of arguments.
    /// This also represents calling the constructor of
    /// tuple-like ADTs such as tuple structs and enum variants.
    | Call of P<Expr> * Vec<P<Expr>>
    /// A method call (`x.foo::<'static, Bar, Baz>(a, b, c, d)`)
    ///
    /// The `PathSegment` represents the method name and its generic arguments
    /// (within the angle brackets).
    /// The first element of the vector of an `Expr` is the expression that evaluates
    /// to the object on which the method is being called on (the receiver)
    /// and the remaining elements are the rest of the arguments.
    /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
    /// This `Span` is the span of the function, without the dot and receiver
    /// (e.g. `foo(a, b)` in `x.foo(a, b)`
    | MethodCall of PathSegment * Vec<P<Expr>> * Span
    /// A tuple (e.g., `(a, b, c, d)`).
    | Tup of Vec<P<Expr>>
    /// A binary operation (e.g., `a + b`, `a * b`).
    | Binary of BinOp * P<Expr> * P<Expr>
    /// A unary operation (e.g., `!x`, `*x`).
    | Unary of UnOp * P<Expr>
    /// A literal (e.g., `1`, `"foo"`).
    | Lit of Lit
    /// A cast (e.g., `foo as f64`).
    | Cast of P<Expr> * P<Ty>
    /// A type ascription (e.g., `42: usize`).
    | Type of P<Expr> * P<Ty>
    /// A `let pat = expr` expression that is only semantically allowed in the condition
    /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
    | Let of P<Pat> * P<Expr>
    /// An `if` block, with an optional `else` block.
    ///
    /// `if expr { block } else { expr }`
    | If of P<Expr> * P<Block> * Option<P<Expr>>
    /// A while loop, with an optional label.
    ///
    /// `'label: while expr { block }`
    | While of P<Expr> * P<Block> * Option<Label>
    /// A `for` loop, with an optional label.
    ///
    /// `'label: for pat in expr { block }`
    ///
    /// This is desugared to a combination of `loop` and `match` expressions.
    | ForLoop of P<Pat> * P<Expr> * P<Block> * Option<Label>
    /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
    ///
    /// `'label: loop { block }`
    | Loop of P<Block> * Option<Label>
    /// A `match` block.
    | Match of P<Expr> * Vec<Arm>
    /// A closure (e.g., `move |a, b, c| a + b + c`).
    ///
    /// The final span is the span of the argument block `|...|`.
    | Closure of CaptureBy * Asyncness * Movability * P<FnDecl> * P<Expr> * Span
    /// A block (`'label: { ... }`).
    | Block of P<Block> * Option<Label>
    /// An async block (`async move { ... }`).
    ///
    /// The `NodeId` is the `NodeId` for the closure that results from
    /// desugaring an async block, just like the NodeId field in the
    /// `Async::Yes` variant. This is necessary in order to create a def for the
    /// closure which can be used as a parent of any child defs. Defs
    /// created during lowering cannot be made the parent of any other
    /// preexisting defs.
    | Async of CaptureBy * NodeId * P<Block>
    /// An await expression (`my_future.await`).
    | Await of P<Expr>

    /// A try block (`try { ... }`).
    | TryBlock of P<Block>

    /// An assignment (`a = foo()`).
    /// The `Span` argument is the span of the `=` token.
    | Assign of P<Expr> * P<Expr> * Span
    /// An assignment with an operator.
    ///
    /// E.g., `a += 1`.
    | AssignOp of BinOp * P<Expr> * P<Expr>
    /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
    | Field of P<Expr> * Ident
    /// An indexing operation (e.g., `foo[2]`).
    | Index of P<Expr> * P<Expr>
    /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assignment).
    | Range of Option<P<Expr>> * Option<P<Expr>> * RangeLimits
    /// An underscore, used in destructuring assignment to ignore a value.
    | Underscore

    /// Variable reference, possibly containing `::` and/or type
    /// parameters (e.g., `foo::bar::<baz>`).
    ///
    /// Optionally "qualified" (e.g., `<Vec<T> as SomeTrait>::SomeType`).
    | Path of Option<QSelf> * Path

    /// A referencing operation (`&a`, `&mut a`, `&raw const a` or `&raw mut a`).
    | AddrOf of BorrowKind * Mutability * P<Expr>
    /// A `break`, with an optional label to break, and an optional expression.
    | Break of Option<Label> * Option<P<Expr>>
    /// A `continue`, with an optional label.
    | Continue of Option<Label>
    /// A `return`, with an optional value to be returned.
    | Ret of Option<P<Expr>>

    /// Output of the `asm!()` macro.
    | InlineAsm of P<InlineAsm>
    /// Output of the `llvm_asm!()` macro.
    | LlvmInlineAsm of P<LlvmInlineAsm>

    /// A macro invocation; pre-expansion.
    | MacCall of MacCall

    /// A struct literal expression.
    ///
    /// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. rest}`.
    | Struct of P<StructExpr>

    /// An array literal constructed from one repeated element.
    ///
    /// E.g., `[1; 5]`. The expression is the element to be
    /// repeated; the constant is the number of times to repeat it.
    | Repeat of P<Expr> * AnonConst

    /// No-op: used solely so we can pretty-print faithfully.
    | Paren of P<Expr>

    /// A try expression (`expr?`).
    | Try of P<Expr>

    /// A `yield`, with an optional value to be yielded.
    | Yield of Option<P<Expr>>

    /// Placeholder for an expression that wasn't syntactically well formed in some way.
    | Err

    /// Escape hatch to allow adding custom macros - This is *not* in the core rust AST - Use with caution!!!
    | EmitExpression of value: string * args: Vec<Expr>

/// The explicit `Self` type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated
/// item qualified with this `Self` type.
///
/// ```ignore (only-for-syntax-highlight)
/// <Vec<T> as a::b::Trait>::AssociatedItem
///  ^~~~~     ~~~~~~~~~~~~~~^
///  ty        position = 3
///
/// <Vec<T>>::AssociatedItem
///  ^~~~~    ^
///  ty       position = 0
/// ```
type QSelf =
    {
        ty: P<Ty>

        /// The span of `a::b::Trait` in a path like `<Vec<T> as
        /// a::b::Trait>::AssociatedItem`; in the case where `position ==
        /// 0`, this is an empty span.
        path_span: Span
        position: usize
    }

/// A capture clause used in closures and `async` blocks.
[<RequireQualifiedAccess>]
type CaptureBy =
    /// `move |x| y + x`.
    | Value
    /// `move` keyword was not specified.
    | Ref

/// The movability of a generator / closure literal:
/// whether a generator contains self-references, causing it to be `!Unpin`.
[<RequireQualifiedAccess>]
type Movability =
    /// May contain self-references, `!Unpin`.
    | Static
    /// Must not contain self-references, `Unpin`.
    | Movable

/// Represents a macro invocation. The `path` indicates which macro
/// is being invoked, and the `args` are arguments passed to it.
type MacCall =
    {
        path: Path
        args: P<MacArgs>
        prior_type_ascription: Option<(Span * bool)>
    }

/// Arguments passed to an attribute or a function-like macro.
[<RequireQualifiedAccess>]
type MacArgs =
    /// No arguments - `#[attr]`.
    | Empty
    /// Delimited arguments - `#[attr()/[]/{}]` or `mac!()/[]/{}`.
    | Delimited of token.DelimSpan * MacDelimiter * token.TokenStream
    /// Arguments of a key-value attribute - `#[attr = "value"]`.
    | Eq of
        /// Span of the `=` token.
        Span *
        /// "value" as a nonterminal token.
        token.Token

[<RequireQualifiedAccess>]
type MacDelimiter =
    | Parenthesis
    | Bracket
    | Brace

/// Represents a macro definition.
type MacroDef =
    {
        body: P<MacArgs>
        /// `true` if macro was defined with `macro_rules`.
        macro_rules: bool
    }

[<RequireQualifiedAccess>]
type StrStyle =
    /// A regular string, like `"foo"`.
    | Cooked
    /// A raw string, like `r##"foo"##`.
    ///
    /// The value is the number of `#` symbols used.
    | Raw of u16

/// An AST literal.
type Lit =
    {
        /// The original literal token as written in source code.
        token: token.Lit
        /// The "semantic" representation of the literal lowered from the original tokens.
        /// Strings are unescaped, hexadecimal forms are eliminated, etc.
        /// FIXME: Remove this and only create the semantic representation during lowering to HIR.
        kind: LitKind
        span: Span
    }

/// Same as `Lit`, but restricted to string literals.
type StrLit =
    {
        /// The original literal token as written in source code.
        style: StrStyle
        symbol: Symbol
        suffix: Option<Symbol>
        span: Span
        /// The unescaped "semantic" representation of the literal lowered from the original token.
        /// FIXME: Remove this and only create the semantic representation during lowering to HIR.
        symbol_unescaped: Symbol
    }

/// Type of the integer literal based on provided suffix.
[<RequireQualifiedAccess>]
type LitIntType =
    /// e.g. `42_i32`.
    | Signed of IntTy
    /// e.g. `42_u32`.
    | Unsigned of UintTy
    /// e.g. `42`.
    | Unsuffixed

/// Type of the float literal based on provided suffix.
[<RequireQualifiedAccess>]
type LitFloatType =
    /// A float literal with a suffix (`1f32` or `1E10f32`).
    | Suffixed of FloatTy
    /// A float literal without a suffix (`1.0 or 1.0E10`).
    | Unsuffixed

/// Literal kind.
///
/// E.g., `"foo"`, `42`, `12.34`, or `bool`.
[<RequireQualifiedAccess>]
type LitKind =
    /// A string literal (`"foo"`).
    | Str of Symbol * StrStyle
    /// A byte string (`b"foo"`).
    | ByteStr of Lrc<u8[]>
    /// A byte char (`b'f'`).
    | Byte of u8
    /// A character literal (`'a'`).
    | Char of char
    /// An integer literal (`1`).
    | Int of Symbol * LitIntType
    /// A float literal (`1f64` or `1E10f64`).
    | Float of Symbol * LitFloatType
    /// A boolean literal.
    | Bool of bool
    /// Placeholder for a literal that wasn't well-formed in some way.
    | Err of Symbol

// N.B., If you change this, you'll probably want to change the corresponding
// type structure in `middle/ty.rs` as well.
type MutTy =
    {
        ty: P<Ty>
        mutbl: Mutability
    }

/// Represents a function's signature in a trait declaration,
/// trait implementation, or free function.
type FnSig =
    {
        header: FnHeader
        decl: P<FnDecl>
        span: Span
    }

[<RequireQualifiedAccess>]
type FloatTy =
    | F32
    | F64

[<RequireQualifiedAccess>]
type IntTy =
    | Isize
    | I8
    | I16
    | I32
    | I64
    | I128

[<RequireQualifiedAccess>]
type UintTy =
    | Usize
    | U8
    | U16
    | U32
    | U64
    | U128

/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
type AssocTyConstraint =
    {
        id: NodeId
        ident: Ident
        gen_args: Option<GenericArgs>
        kind: AssocTyConstraintKind
        span: Span
    }

/// The kinds of an `AssocTyConstraint`.
[<RequireQualifiedAccess>]
type AssocTyConstraintKind =
    /// E.g., `A = Bar` in `Foo<A = Bar>`.
    | Equality of ty: P<Ty>
    /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
    | Bound of bounds: GenericBounds

type Ty =
    {
        id: NodeId
        kind: TyKind
        span: Span
        tokens: Option<LazyTokenStream>
    }

type BareFnTy =
    {
        unsafety: Unsafety
        ext: Extern
        generic_params: Vec<GenericParam>
        decl: P<FnDecl>
    }

/// The various kinds of type recognized by the compiler.
[<RequireQualifiedAccess>]
type TyKind =
    /// A variable-length slice (`[T]`).
    | Slice of P<Ty>
    /// A fixed length array (`[T; n]`).
    | Array of P<Ty> * AnonConst
    /// A raw pointer (`*const T` or `*mut T`).
    | Ptr of MutTy
    /// A reference (`&'a T` or `&'a mut T`).
    | Rptr of Option<Lifetime> * MutTy
    /// A bare function (e.g., `fn(usize) -> bool`).
    | BareFn of P<BareFnTy>
    /// The never type (`!`).
    | Never
    /// A tuple (`(A, B, C, D,...)`).
    | Tup of Vec<P<Ty>>
    /// A path (`module::module::...::Type`), optionally
    /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
    ///
    /// Type parameters are stored in the `Path` itself.
    | Path of Option<QSelf> * Path
    /// A trait object type `Bound1 + Bound2 + Bound3`
    /// where `Bound` is a trait or a lifetime.
    | TraitObject of GenericBounds * TraitObjectSyntax
    /// An `impl Bound1 + Bound2 + Bound3` type
    /// where `Bound` is a trait or a lifetime.
    ///
    /// The `NodeId` exists to prevent lowering from having to
    /// generate `NodeId`s on the fly, which would complicate
    /// the generation of opaque `type Foo = impl Trait` items significantly.
    | ImplTrait of NodeId * GenericBounds
    /// No-op; kept solely so that we can pretty-print faithfully.
    | Paren of P<Ty>
    /// Unused for now.
    | Typeof of AnonConst
    /// This means the type should be inferred instead of it having been
    /// specified. This can appear anywhere in a type.
    | Infer
    /// Inferred type of a `self` or `&self` argument in a method.
    | ImplicitSelf
    /// A macro in the type position.
    | MacCall of MacCall
    /// Placeholder for a kind that has failed to be defined.
    | Err
    /// Placeholder for a `va_list`.
    | CVarArgs
    /// Escape hatch to allow adding custom macros - This is not in the core rust AST - Use with caution!!!
    | EmitTypeExpression of value: string * args: Vec<Ty>


/// Syntax used to declare a trait object.
[<RequireQualifiedAccess>]
type TraitObjectSyntax =
    | Dyn
    | None

/// Inline assembly operand explicit register or register class.
///
/// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`.
[<RequireQualifiedAccess>]
type InlineAsmRegOrRegClass =
    | Reg of Symbol
    | RegClass of Symbol

[<RequireQualifiedAccess; System.Flags>]
type InlineAsmOptions =
    | NONE = 0uy
    | PURE = 1uy
    | NOMEM = 2uy
    | READONLY = 4uy
    | PRESERVES_FLAGS = 8uy
    | NORETURN = 16uy
    | NOSTACK = 32uy
    | ATT_SYNTAX = 64uy

[<RequireQualifiedAccess>]
type InlineAsmTemplatePiece =
    | String of String
    | Placeholder of operand_idx: usize * modifier: Option<char> * span: Span

/// Inline assembly operand.
///
/// E.g., `out("eax") result` as in `asm!("mov eax, 2", out("eax") result)`.
[<RequireQualifiedAccess>]
type InlineAsmOperand =
    | In of reg: InlineAsmRegOrRegClass * expr: P<Expr>
    | Out of reg: InlineAsmRegOrRegClass * late: bool * expr: Option<P<Expr>>
    | InOut of reg: InlineAsmRegOrRegClass * late: bool * expr: P<Expr>
    | SplitInOut of reg: InlineAsmRegOrRegClass * late: bool * in_expr: P<Expr> * out_expr: Option<P<Expr>>
    | Const of anon_const: AnonConst
    | Sym of expr: P<Expr>

/// Inline assembly.
///
/// E.g., `asm!("NOP");`.
type InlineAsm =
    {
        template: Vec<InlineAsmTemplatePiece>
        operands: Vec<InlineAsmOperand * Span>
        options: InlineAsmOptions
        line_spans: Vec<Span>
    }

/// Inline assembly dialect.
///
/// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
[<RequireQualifiedAccess>]
type LlvmAsmDialect =
    | Att
    | Intel

/// LLVM-style inline assembly.
///
/// E.g., `"={eax}"(result)` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
type LlvmInlineAsmOutput =
    {
        constraint_: Symbol
        expr: P<Expr>
        is_rw: bool
        is_indirect: bool
    }

/// LLVM-style inline assembly.
///
/// E.g., `llvm_asm!("NOP");`.
type LlvmInlineAsm =
    {
        asm: Symbol
        asm_str_style: StrStyle
        outputs: Vec<LlvmInlineAsmOutput>
        inputs: Vec<Symbol * P<Expr>>
        clobbers: Vec<Symbol>
        volatile: bool
        alignstack: bool
        dialect: LlvmAsmDialect
    }

/// A parameter in a function header.
///
/// E.g., `bar: usize` as in `fn foo(bar: usize)`.
type Param =
    {
        attrs: AttrVec
        ty: P<Ty>
        pat: P<Pat>
        id: NodeId
        span: Span
        is_placeholder: bool
    }

/// Alternative representation for `Arg`s describing `self` parameter of methods.
///
/// E.g., `&mut self` as in `fn foo(&mut self)`.
[<RequireQualifiedAccess>]
type SelfKind =
    /// `self`, `mut self`
    | Value of Mutability
    /// `&'lt self`, `&'lt mut self`
    | Region of Option<Lifetime> * Mutability
    /// `self: TYPE`, `mut self: TYPE`
    | Explicit of P<Ty> * Mutability

type ExplicitSelf = Spanned<SelfKind>

/// A signature (not the body) of a function declaration.
///
/// E.g., `fn foo(bar: baz)`.
///
/// Please note that it's different from `FnHeader` structure
/// which contains metadata about function safety, asyncness, constness and ABI.
type FnDecl =
    {
        inputs: Vec<Param>
        output: FnRetTy
    }

/// Is the trait definition an auto trait?
[<RequireQualifiedAccess>]
type IsAuto =
    | Yes
    | No

[<RequireQualifiedAccess>]
type Unsafety =
    | Yes of Span
    | No

[<RequireQualifiedAccess>]
type Asyncness =
    | Yes of span: Span * closure_id: NodeId * return_impl_trait_id: NodeId
    | No

[<RequireQualifiedAccess>]
type Constness =
    | Yes of Span
    | No

/// Item defaultness.
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
[<RequireQualifiedAccess>]
type Defaultness =
    | Default of Span
    | Final

[<RequireQualifiedAccess>]
type ImplPolarity =
    /// `impl Trait for Type`
    | Positive
    /// `impl !Trait for Type`
    | Negative of Span

[<RequireQualifiedAccess>]
type FnRetTy =
    /// Returns type is not specified.
    ///
    /// Functions default to `()` and closures default to inference.
    /// Span points to where return type would be inserted.
    | Default of Span
    /// Everything else.
    | Ty of P<Ty>

[<RequireQualifiedAccess>]
type Inline =
    | Yes
    | No

/// Module item kind.
[<RequireQualifiedAccess>]
type ModKind =
    /// Module with inlined definition `mod foo { ... }`
    /// or with definition outlined to a separate file `mod foo;` and already loaded from it.
    /// The inner span is from the first token past `{` to the last token until `}`
    /// or from the first to the last token in the loaded file.
    | Loaded of Vec<P<Item>> * Inline * Span
    /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
    | Unloaded

/// Foreign module declaration.
///
/// E.g., `extern { .. }` or `extern "C" { .. }`.
type ForeignMod =
    {
        /// `unsafe` keyword accepted syntactically for macro DSLs, but not
        /// semantically by Rust.
        unsafety: Unsafety
        abi: Option<StrLit>
        items: Vec<P<ForeignItem>>
    }

/// Global inline assembly.
///
/// Also known as "module-level assembly" or "file-scoped assembly".
type GlobalAsm = { asm: Symbol }

type EnumDef = { variants: Vec<Variant> }

/// Enum variant.
type Variant =
    {
        /// Attributes of the variant.
        attrs: Vec<Attribute>
        /// Id of the variant (not the constructor, see `VariantData::ctor_id()`).
        id: NodeId
        /// Span
        span: Span
        /// The visibility of the variant. Syntactically accepted but not semantically.
        vis: Visibility
        /// Name of the variant.
        ident: Ident

        /// Fields and constructor id of the variant.
        data: VariantData
        /// Explicit discriminant, e.g., `Foo = 1`.
        disr_expr: Option<AnonConst>
        /// Is a macro placeholder
        is_placeholder: bool
    }

/// Part of `use` item to the right of its prefix.
[<RequireQualifiedAccess>]
type UseTreeKind =
    /// `use prefix` or `use prefix as rename`
    ///
    /// The extra `NodeId`s are for HIR lowering, when additional statements are created for each
    /// namespace.
    | Simple of Option<Ident> * NodeId * NodeId
    /// `use prefix::{...}`
    | Nested of Vec<UseTree * NodeId>
    /// `use prefix::*`
    | Glob

/// A tree of paths sharing common prefixes.
/// Used in `use` items both at top-level and inside of braces in import groups.
type UseTree =
    {
        prefix: Path
        kind: UseTreeKind
        span: Span
    }

/// Distinguishes between `Attribute`s that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
[<RequireQualifiedAccess>]
type AttrStyle =
    | Outer
    | Inner

type AttrId = u32
// rustc_index::newtype_index! {
//     type AttrId = {
//         ENCODABLE = custom
//         DEBUG_FORMAT = "AttrId({})"
//     }

type AttrItem =
    {
        path: Path
        args: MacArgs
        tokens: Option<LazyTokenStream>
    }

/// A list of attributes.
type AttrVec = Vec<Attribute>

/// Metadata associated with an item.
type Attribute =
    {
        kind: AttrKind
        id: AttrId
        /// Denotes if the attribute decorates the following construct (outer)
        /// or the construct this attribute is contained within (inner).
        style: AttrStyle
        span: Span
    }

[<RequireQualifiedAccess>]
type AttrKind =
    /// A normal attribute.
    | Normal of AttrItem * Option<LazyTokenStream>

    /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
    /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
    /// variant (which is much less compact and thus more expensive).
    | DocComment of token.CommentKind * Symbol

/// `TraitRef`s appear in impls.
///
/// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all
/// that the `ref_id` is for. The `impl_id` maps to the "self type" of this impl.
/// If this impl is an `ItemKind::Impl`, the `impl_id` is redundant (it could be the
/// same as the impl's `NodeId`).
type TraitRef =
    {
        path: Path
        ref_id: NodeId
    }

type PolyTraitRef =
    {
        /// The `'a` in `<'a> Foo<&'a T>`.
        bound_generic_params: Vec<GenericParam>

        /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`.
        trait_ref: TraitRef

        span: Span
    }

[<RequireQualifiedAccess>]
type CrateSugar =
    /// Source is `pub(crate)`.
    | PubCrate

    /// Source is (just) `crate`.
    | JustCrate

type Visibility =
    {
        kind: VisibilityKind
        span: Span
        tokens: Option<LazyTokenStream>
    }

[<RequireQualifiedAccess>]
type VisibilityKind =
    | Public
    | Crate of CrateSugar
    | Restricted of path: P<Path> * id: NodeId
    | Inherited

/// Field definition in a struct, variant or union.
///
/// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
type FieldDef =
    {
        attrs: Vec<Attribute>
        id: NodeId
        span: Span
        vis: Visibility
        ident: Option<Ident>

        ty: P<Ty>
        is_placeholder: bool
    }

/// Fields and constructor ids of enum variants and structs.
[<RequireQualifiedAccess>]
type VariantData =
    /// Struct variant.
    ///
    /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
    | Struct of Vec<FieldDef> * bool
    /// Tuple variant.
    ///
    /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
    | Tuple of Vec<FieldDef> * NodeId
    /// Unit variant.
    ///
    /// E.g., `Bar = ..` as in `enum Foo { Bar = .. }`.
    | Unit of NodeId

/// An item definition.
type Item<'K> =
    { // when 'K: ItemKind
        attrs: Vec<Attribute>
        id: NodeId
        span: Span
        vis: Visibility
        /// The name of the item.
        /// It might be a dummy name in case of anonymous items.
        ident: Ident

        kind: 'K

        /// Original tokens this item was parsed from. This isn't necessarily
        /// available for all items, although over time more and more items should
        /// have this be `Some`. Right now this is primarily used for procedural
        /// macros, notably custom attributes.
        ///
        /// Note that the tokens here do not include the outer attributes, but will
        /// include inner attributes.
        tokens: Option<LazyTokenStream>
    }

type Item = Item<ItemKind>

/// `extern` qualifier on a function item or function type.
[<RequireQualifiedAccess>]
type Extern =
    | None
    | Implicit
    | Explicit of StrLit

/// A function header.
///
/// All the information between the visibility and the name of the function is
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
type FnHeader =
    {
        unsafety: Unsafety
        asyncness: Asyncness
        constness: Constness
        ext: Extern
    }

type TraitKind = IsAuto * Unsafety * Generics * GenericBounds * Vec<P<AssocItem>>

type TyAliasKind = Defaultness * Generics * GenericBounds * Option<P<Ty>>

type ImplKind =
    {
        unsafety: Unsafety
        polarity: ImplPolarity
        defaultness: Defaultness
        constness: Constness
        generics: Generics

        /// The trait being implemented, if any.
        of_trait: Option<TraitRef>

        self_ty: P<Ty>
        items: Vec<P<AssocItem>>
    }

type FnKind = Defaultness * FnSig * Generics * Option<P<Block>>

[<RequireQualifiedAccess>]
type ItemKind =
    /// An `extern crate` item, with the optional *original* crate name if the crate was renamed.
    ///
    /// E.g., `extern crate foo` or `extern crate foo_bar as foo`.
    | ExternCrate of Option<Symbol>
    /// A use declaration item (`use`).
    ///
    /// E.g., `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`.
    | Use of UseTree
    /// A static item (`static`).
    ///
    /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`.
    | Static of P<Ty> * Mutability * Option<P<Expr>>
    /// A constant item (`const`).
    ///
    /// E.g., `const FOO: i32 = 42;`.
    | Const of Defaultness * P<Ty> * Option<P<Expr>>
    /// A function declaration (`fn`).
    ///
    /// E.g., `fn foo(bar: usize) -> usize { .. }`.
    | Fn of Box<FnKind>
    /// A module declaration (`mod`).
    ///
    /// E.g., `mod foo;` or `mod foo { .. }`.
    /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not
    /// semantically by Rust.
    | Mod of Unsafety * ModKind
    /// An external module (`extern`).
    ///
    /// E.g., `extern {}` or `extern "C" {}`.
    | ForeignMod of ForeignMod
    /// Module-level inline assembly (from `global_asm!()`).
    | GlobalAsm of GlobalAsm
    /// A type alias (`type`).
    ///
    /// E.g., `type Foo = Bar<u8>;`.
    | TyAlias of Box<TyAliasKind>
    /// An enum definition (`enum`).
    ///
    /// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
    | Enum of EnumDef * Generics
    /// A struct definition (`struct`).
    ///
    /// E.g., `struct Foo<A> { x: A }`.
    | Struct of VariantData * Generics
    /// A union definition (`union`).
    ///
    /// E.g., `union Foo<A, B> { x: A, y: B }`.
    | Union of VariantData * Generics
    /// A trait declaration (`trait`).
    ///
    /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
    | Trait of Box<TraitKind>
    /// Trait alias
    ///
    /// E.g., `trait Foo = Bar + Quux;`.
    | TraitAlias of Generics * GenericBounds
    /// An implementation.
    ///
    /// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
    | Impl of Box<ImplKind>
    /// A macro invocation.
    ///
    /// E.g., `foo!(..)`.
    | MacCall of MacCall

    /// A macro definition.
    | MacroDef of MacroDef

/// Represents associated items.
/// These include items in `impl` and `trait` definitions.
type AssocItem = Item<AssocItemKind>

/// Represents associated item kinds.
///
/// The term "provided" in the variants below refers to the item having a default
/// definition / body. Meanwhile, a "required" item lacks a definition / body.
/// In an implementation, all items must be provided.
/// The `Option`s below denote the bodies, where `Some(_)`
/// means "provided" and conversely `None` means "required".
[<RequireQualifiedAccess>]
type AssocItemKind =
    /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
    /// If `def` is parsed, then the constant is provided, and otherwise required.
    | Const of Defaultness * P<Ty> * Option<P<Expr>>
    /// An associated function.
    | Fn of Box<FnKind>
    /// An associated type.
    | TyAlias of Box<TyAliasKind>
    /// A macro expanding to associated items.
    | MacCall of MacCall

/// An item in `extern` block.
[<RequireQualifiedAccess>]
type ForeignItemKind =
    /// A foreign static item (`static FOO: u8`).
    | Static of P<Ty> * Mutability * Option<P<Expr>>
    /// An foreign function.
    | Fn of Box<FnKind>
    /// An foreign type.
    | TyAlias of Box<TyAliasKind>
    /// A macro expanding to foreign items.
    | MacCall of MacCall

type ForeignItem = Item<ForeignItemKind>
