Skip to main content

rustc_middle/query/
stack.rs

1use std::fmt::Debug;
2use std::marker::PhantomData;
3use std::mem::transmute;
4use std::sync::Arc;
5
6use rustc_data_structures::sync::{DynSend, DynSync};
7use rustc_hashes::Hash64;
8use rustc_hir::def::DefKind;
9use rustc_span::Span;
10use rustc_span::def_id::DefId;
11
12use crate::dep_graph::DepKind;
13
14/// Description of a frame in the query stack.
15///
16/// This is mostly used in case of cycles for error reporting.
17#[derive(#[automatically_derived]
impl<I: ::core::clone::Clone> ::core::clone::Clone for QueryStackFrame<I> {
    #[inline]
    fn clone(&self) -> QueryStackFrame<I> {
        QueryStackFrame {
            info: ::core::clone::Clone::clone(&self.info),
            dep_kind: ::core::clone::Clone::clone(&self.dep_kind),
            hash: ::core::clone::Clone::clone(&self.hash),
            def_id: ::core::clone::Clone::clone(&self.def_id),
            def_id_for_ty_in_cycle: ::core::clone::Clone::clone(&self.def_id_for_ty_in_cycle),
        }
    }
}Clone, #[automatically_derived]
impl<I: ::core::fmt::Debug> ::core::fmt::Debug for QueryStackFrame<I> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field5_finish(f,
            "QueryStackFrame", "info", &self.info, "dep_kind", &self.dep_kind,
            "hash", &self.hash, "def_id", &self.def_id,
            "def_id_for_ty_in_cycle", &&self.def_id_for_ty_in_cycle)
    }
}Debug)]
18pub struct QueryStackFrame<I> {
19    /// This field initially stores a `QueryStackDeferred` during collection,
20    /// but can later be changed to `QueryStackFrameExtra` containing concrete information
21    /// by calling `lift`. This is done so that collecting query does not need to invoke
22    /// queries, instead `lift` will call queries in a more appropriate location.
23    pub info: I,
24
25    pub dep_kind: DepKind,
26    /// This hash is used to deterministically pick
27    /// a query to remove cycles in the parallel compiler.
28    pub hash: Hash64,
29    pub def_id: Option<DefId>,
30    /// A def-id that is extracted from a `Ty` in a query key
31    pub def_id_for_ty_in_cycle: Option<DefId>,
32}
33
34impl<'tcx> QueryStackFrame<QueryStackDeferred<'tcx>> {
35    #[inline]
36    pub fn new(
37        info: QueryStackDeferred<'tcx>,
38        dep_kind: DepKind,
39        hash: Hash64,
40        def_id: Option<DefId>,
41        def_id_for_ty_in_cycle: Option<DefId>,
42    ) -> Self {
43        Self { info, def_id, dep_kind, hash, def_id_for_ty_in_cycle }
44    }
45
46    pub fn lift(&self) -> QueryStackFrame<QueryStackFrameExtra> {
47        QueryStackFrame {
48            info: self.info.extract(),
49            dep_kind: self.dep_kind,
50            hash: self.hash,
51            def_id: self.def_id,
52            def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle,
53        }
54    }
55}
56
57#[derive(#[automatically_derived]
impl ::core::clone::Clone for QueryStackFrameExtra {
    #[inline]
    fn clone(&self) -> QueryStackFrameExtra {
        QueryStackFrameExtra {
            description: ::core::clone::Clone::clone(&self.description),
            span: ::core::clone::Clone::clone(&self.span),
            def_kind: ::core::clone::Clone::clone(&self.def_kind),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for QueryStackFrameExtra {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "QueryStackFrameExtra", "description", &self.description, "span",
            &self.span, "def_kind", &&self.def_kind)
    }
}Debug)]
58pub struct QueryStackFrameExtra {
59    pub description: String,
60    pub span: Option<Span>,
61    pub def_kind: Option<DefKind>,
62}
63
64impl QueryStackFrameExtra {
65    #[inline]
66    pub fn new(description: String, span: Option<Span>, def_kind: Option<DefKind>) -> Self {
67        Self { description, span, def_kind }
68    }
69
70    // FIXME(eddyb) Get more valid `Span`s on queries.
71    #[inline]
72    pub fn default_span(&self, span: Span) -> Span {
73        if !span.is_dummy() {
74            return span;
75        }
76        self.span.unwrap_or(span)
77    }
78}
79
80/// Track a 'side effect' for a particular query.
81/// This is used to hold a closure which can create `QueryStackFrameExtra`.
82#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for QueryStackDeferred<'tcx> {
    #[inline]
    fn clone(&self) -> QueryStackDeferred<'tcx> {
        QueryStackDeferred {
            _dummy: ::core::clone::Clone::clone(&self._dummy),
            extract: ::core::clone::Clone::clone(&self.extract),
        }
    }
}Clone)]
83pub struct QueryStackDeferred<'tcx> {
84    _dummy: PhantomData<&'tcx ()>,
85
86    // `extract` may contain references to 'tcx, but we can't tell drop checking that it won't
87    // access it in the destructor.
88    extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend>,
89}
90
91impl<'tcx> QueryStackDeferred<'tcx> {
92    pub fn new<C: Copy + DynSync + DynSend + 'tcx>(
93        context: C,
94        extract: fn(C) -> QueryStackFrameExtra,
95    ) -> Self {
96        let extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend + 'tcx> =
97            Arc::new(move || extract(context));
98        // SAFETY: The `extract` closure does not access 'tcx in its destructor as the only
99        // captured variable is `context` which is Copy and cannot have a destructor.
100        Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } }
101    }
102
103    pub fn extract(&self) -> QueryStackFrameExtra {
104        (self.extract)()
105    }
106}
107
108impl<'tcx> Debug for QueryStackDeferred<'tcx> {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        f.write_str("QueryStackDeferred")
111    }
112}