frontend 0.4.0

rustc's frontend with no LLVM and no std: parsing through MIR, as a library
// `#![no_std]`: these arrive with the standard prelude and name no path, so a `std::`
// search cannot see them - and a `#[derive]` can use them without the name appearing
// in this file at all, which is why they are not trimmed by inspection.
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;

use tracing::instrument;

pub use self::dep_node::{DepKind, DepKindVTable, DepNode, WorkProductId, dep_kind_from_label};
pub use self::dep_node_key::DepNodeKey;
pub use self::graph::{
    DepGraph, DepGraphData, DepNodeIndex, QuerySideEffect, TaskDepsRef, WorkProduct,
    WorkProductMap, hash_result,
};
use self::graph::{MarkFrame, print_markframe_trace};
pub use self::retained::RetainedDepGraph;
pub use self::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
pub use crate::rustc_middle::dep_graph::debug::{DepNodeFilter, EdgeFilter};
pub use crate::rustc_middle::ty::print::with_reduced_queries;
use crate::rustc_middle::ty::{self, TyCtxt};

mod debug;
pub(crate) mod dep_node;
mod dep_node_key;
mod edges;
mod graph;
mod retained;
mod serialized;

/// Describes the contents of the fingerprint generated by a given query.
///
/// This is mainly for determining whether and how we can reconstruct a key
/// from the fingerprint.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum KeyFingerprintStyle {
    /// The fingerprint is actually a DefPathHash.
    DefPathHash,
    /// The fingerprint is actually a HirId.
    HirId,
    /// Query key was `()` or equivalent, so fingerprint is just zero.
    Unit,
    /// The fingerprint is an opaque hash, and a key cannot be reconstructed from it.
    Opaque,
}

impl KeyFingerprintStyle {
    /// True if a key can _potentially_ be recovered from a key fingerprint
    /// with this style.
    ///
    /// For some key types, recovery is possible but not guaranteed.
    #[inline]
    pub const fn is_maybe_recoverable(self) -> bool {
        match self {
            KeyFingerprintStyle::DefPathHash
            | KeyFingerprintStyle::Unit
            | KeyFingerprintStyle::HirId => true,
            KeyFingerprintStyle::Opaque => false,
        }
    }
}

/// Execute the operation with provided dependencies.
fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
where
    OP: FnOnce() -> R,
{
    ty::tls::with_context(|icx| {
        let icx = ty::tls::ImplicitCtxt { task_deps, ..*icx };
        ty::tls::enter_context(&icx, op)
    })
}

/// Access dependencies from current implicit context.
fn read_deps<OP>(op: OP)
where
    OP: for<'a> FnOnce(TaskDepsRef<'a>),
{
    ty::tls::with_context_opt(|icx| {
        let Some(icx) = icx else { return };
        op(icx.task_deps)
    })
}

impl<'tcx> TyCtxt<'tcx> {
    #[inline]
    pub fn dep_kind_vtable(self, dk: DepKind) -> &'tcx DepKindVTable<'tcx> {
        &self.query_system.dep_kind_vtables[dk.as_usize()]
    }

    #[inline(always)]
    pub fn key_fingerprint_style(self, kind: DepKind) -> KeyFingerprintStyle {
        self.dep_kind_vtable(kind).key_fingerprint_style
    }

    /// Try to force a dep node to execute and see if it's green.
    ///
    /// Returns true if the query has actually been forced. It is valid that a query
    /// fails to be forced, e.g. when the query key cannot be reconstructed from the
    /// dep-node or when the query kind outright does not support it.
    #[inline]
    #[instrument(skip(self, frame), level = "debug")]
    fn try_force_from_dep_node(
        self,
        dep_node: DepNode,
        prev_index: SerializedDepNodeIndex,
        frame: &MarkFrame<'_>,
    ) -> bool {
        if let Some(force_fn) = self.dep_kind_vtable(dep_node.kind).force_from_dep_node_fn {
            // Panic containment was dropped with `panic = "abort"`: a panic inside `force_fn`
            // now aborts the process, so nothing can be caught and the `Err` arm below is
            // unreachable. The arm is kept rather than deleted so the mark-frame trace it
            // prints can be found again when a panic runtime is restored.
            let forced: Result<bool, Box<dyn core::any::Any + Send>> =
                Ok(force_fn(self, dep_node, prev_index));
            match forced {
                Err(value) => {
                    if !value.is::<crate::rustc_errors::FatalErrorMarker>() {
                        print_markframe_trace(&self.dep_graph, frame);
                    }
                    // Was `resume_unwind(value)`; with `panic = "abort"` a re-raise is just an
                    // abort, and this line is unreachable regardless.
                    panic!("dep node force panicked")
                }
                Ok(query_has_been_forced) => query_has_been_forced,
            }
        } else {
            false
        }
    }
}