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