rune/query/
mod.rs

1//! Lazy query system, used to compile and build items on demand and keep track
2//! of what's being used and not.
3
4mod query;
5
6use core::fmt;
7use core::mem::take;
8use core::num::NonZeroUsize;
9
10use rust_alloc::rc::Rc;
11
12pub(crate) use self::query::{Query, QueryInner, QuerySource};
13
14use crate as rune;
15use crate::alloc::path::PathBuf;
16use crate::alloc::prelude::*;
17use crate::ast::{self, OptionSpanned, Span, Spanned};
18use crate::compile::{ir, Doc, Error, ItemId, ItemMeta, Location, ModId, Result};
19use crate::grammar::{Ignore, Node, NodeAt, NodeId, Tree};
20use crate::hash::Hash;
21use crate::hir;
22use crate::indexing;
23use crate::parse::NonZeroId;
24use crate::runtime::format;
25use crate::runtime::Call;
26
27/// Indication whether a value is being evaluated because it's being used or not.
28#[derive(Default, Debug, TryClone, Clone, Copy)]
29#[try_clone(copy)]
30pub(crate) enum Used {
31    /// The value is not being used.
32    Unused,
33    /// The value is being used.
34    #[default]
35    Used,
36}
37
38impl Used {
39    /// Test if this used indicates unuse.
40    pub(crate) fn is_unused(self) -> bool {
41        matches!(self, Self::Unused)
42    }
43}
44
45/// The result of calling [Query::convert_path].
46pub(crate) struct Named<'ast> {
47    /// Module named item belongs to.
48    pub(crate) module: ModId,
49    /// The path resolved to the given item.
50    pub(crate) item: ItemId,
51    /// Trailing parameters.
52    pub(crate) trailing: usize,
53    /// Type parameters if any.
54    pub(crate) parameters: [Option<(
55        &'ast dyn Spanned,
56        &'ast ast::AngleBracketed<ast::PathSegmentExpr, T![,]>,
57    )>; 2],
58}
59
60impl fmt::Display for Named<'_> {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        fmt::Display::fmt(&self.item, f)
63    }
64}
65
66pub(crate) enum Named2Kind {
67    /// A full path.
68    Full,
69    /// An identifier.
70    Ident(ast::Ident),
71    /// Self value.
72    SelfValue(#[allow(unused)] ast::SelfValue),
73}
74
75/// The result of calling [Query::convert_path2].
76pub(crate) struct Named2<'a> {
77    /// Module named item belongs to.
78    pub(crate) module: ModId,
79    /// The kind of named item.
80    pub(crate) kind: Named2Kind,
81    /// The path resolved to the given item.
82    pub(crate) item: ItemId,
83    /// Trailing parameters.
84    pub(crate) trailing: usize,
85    /// Type parameters if any.
86    pub(crate) parameters: [Option<Node<'a>>; 2],
87}
88
89impl fmt::Display for Named2<'_> {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        fmt::Display::fmt(&self.item, f)
92    }
93}
94
95/// An internally resolved macro.
96#[allow(clippy::large_enum_variant)]
97pub(crate) enum BuiltInMacro {
98    Template(BuiltInTemplate),
99    Format(BuiltInFormat),
100    File(BuiltInFile),
101    Line(BuiltInLine),
102}
103
104pub(crate) enum BuiltInMacro2 {
105    File(ast::LitStr),
106    Line(usize),
107    Template(Rc<Tree>, BuiltInLiteral),
108    Format(Rc<Tree>),
109}
110
111/// An internally resolved template.
112#[derive(Spanned)]
113pub(crate) struct BuiltInTemplate {
114    /// The span of the built-in template.
115    #[rune(span)]
116    pub(crate) span: Span,
117    /// Indicate if template originated from literal.
118    pub(crate) from_literal: bool,
119    /// Expressions being concatenated as a template.
120    pub(crate) exprs: Vec<ast::Expr>,
121}
122
123/// An internal format specification.
124#[derive(Spanned)]
125pub(crate) struct BuiltInFormat {
126    #[rune(span)]
127    pub(crate) span: Span,
128    /// The fill character to use.
129    pub(crate) fill: Option<char>,
130    /// Alignment specification.
131    pub(crate) align: Option<format::Alignment>,
132    /// Width to fill.
133    pub(crate) width: Option<NonZeroUsize>,
134    /// Precision to fill.
135    pub(crate) precision: Option<NonZeroUsize>,
136    /// A specification of flags.
137    pub(crate) flags: Option<format::Flags>,
138    /// The format specification type.
139    pub(crate) format_type: Option<format::Type>,
140    /// The value being formatted.
141    pub(crate) value: ast::Expr,
142}
143
144/// Macro data for `file!()`
145#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)]
146#[try_clone(copy)]
147pub(crate) struct BuiltInFile {
148    /// Path value to use
149    pub(crate) value: ast::Lit,
150}
151
152/// Macro data for `line!()`
153#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)]
154#[try_clone(copy)]
155pub(crate) struct BuiltInLine {
156    /// The line number
157    pub(crate) value: ast::Lit,
158}
159
160#[derive(Debug, TryClone)]
161pub(crate) struct Closure<'hir> {
162    /// Ast for closure.
163    pub(crate) hir: &'hir hir::ExprClosure<'hir>,
164    /// Calling convention used for closure.
165    pub(crate) call: Call,
166}
167
168#[derive(Debug, TryClone)]
169pub(crate) struct AsyncBlock<'hir> {
170    /// Ast for block.
171    pub(crate) hir: &'hir hir::AsyncBlock<'hir>,
172    /// Calling convention used for async block.
173    pub(crate) call: Call,
174}
175
176/// An entry in the build queue.
177#[derive(Debug, TryClone)]
178pub(crate) enum SecondaryBuild<'hir> {
179    Closure(Closure<'hir>),
180    AsyncBlock(AsyncBlock<'hir>),
181}
182
183/// An entry in the build queue.
184#[derive(Debug, TryClone)]
185pub(crate) struct SecondaryBuildEntry<'hir> {
186    /// The item of the build entry.
187    pub(crate) item_meta: ItemMeta,
188    /// The build entry.
189    pub(crate) build: SecondaryBuild<'hir>,
190}
191
192/// An entry in the build queue.
193#[derive(Debug, TryClone)]
194pub(crate) enum Build {
195    Function(indexing::Function),
196    Unused,
197    Import(indexing::Import),
198    /// A public re-export.
199    ReExport,
200    /// A build which simply queries for the item.
201    Query,
202}
203
204/// An entry in the build queue.
205#[derive(Debug, TryClone)]
206pub(crate) struct BuildEntry {
207    /// The item of the build entry.
208    pub(crate) item_meta: ItemMeta,
209    /// The build entry.
210    pub(crate) build: Build,
211}
212
213/// The kind of item being implemented.
214pub(crate) enum ImplItemKind {
215    Ast {
216        /// Non-expanded ast of the path.
217        path: Box<ast::Path>,
218        /// Functions in the impl block.
219        functions: Vec<ast::ItemFn>,
220    },
221    Node {
222        /// The path being implemented.
223        path: NodeAt,
224        /// Functions being added.
225        functions: Vec<(NodeId, Attrs)>,
226    },
227}
228
229#[must_use = "must be consumed"]
230#[derive(Default, Debug)]
231pub(crate) struct Attrs {
232    pub(crate) test: Option<Span>,
233    pub(crate) bench: Option<Span>,
234    pub(crate) docs: Vec<Doc>,
235    pub(crate) builtin: Option<(Span, BuiltInLiteral)>,
236}
237
238impl Attrs {
239    pub(crate) fn deny_non_docs(self, cx: &mut dyn Ignore<'_>) -> Result<()> {
240        if let Some(span) = self.test {
241            cx.error(Error::msg(span, "unsupported #[test] attribute"))?;
242        }
243
244        if let Some(span) = self.bench {
245            cx.error(Error::msg(span, "unsupported #[bench] attribute"))?;
246        }
247
248        if let Some((span, _)) = self.builtin {
249            cx.error(Error::msg(span, "unsupported #[builtin] attribute"))?;
250        }
251
252        Ok(())
253    }
254
255    pub(crate) fn deny_any(self, cx: &mut dyn Ignore<'_>) -> Result<()> {
256        if let Some(span) = self.docs.option_span() {
257            cx.error(Error::msg(span, "unsupported documentation"))?;
258        }
259
260        self.deny_non_docs(cx)?;
261        Ok(())
262    }
263}
264
265/// The implementation item.
266pub(crate) struct ImplItem {
267    /// The kind of item being implemented.
268    pub(crate) kind: ImplItemKind,
269    /// Location where the item impl is defined and is being expanded.
270    pub(crate) location: Location,
271    ///See [Indexer][crate::indexing::Indexer].
272    pub(crate) root: Option<PathBuf>,
273    ///See [Indexer][crate::indexing::Indexer].
274    pub(crate) nested_item: Option<Span>,
275    /// See [Indexer][crate::indexing::Indexer].
276    pub(crate) macro_depth: usize,
277}
278
279/// Expand the given macro.
280#[must_use = "Must be used to report errors"]
281pub(crate) struct ExpandMacroBuiltin {
282    /// The identifier of the macro being expanded.
283    pub(crate) id: NonZeroId,
284    /// The macro being expanded.
285    pub(crate) node: NodeAt,
286    /// Location where the item impl is defined and is being expanded.
287    pub(crate) location: Location,
288    ///See [Indexer][crate::indexing::Indexer].
289    pub(crate) root: Option<PathBuf>,
290    /// See [Indexer][crate::indexing::Indexer].
291    pub(crate) macro_depth: usize,
292    /// Indexing item at macro expansion position.
293    pub(crate) item: indexing::IndexItem,
294    /// The literal option.
295    pub(crate) literal: BuiltInLiteral,
296}
297
298impl ExpandMacroBuiltin {
299    /// Deny any unused options.
300    pub(crate) fn finish(self) -> Result<NonZeroId> {
301        if let BuiltInLiteral::Yes(span) = self.literal {
302            return Err(Error::msg(
303                span,
304                "#[builtin(literal)] option is not allowed",
305            ));
306        }
307
308        Ok(self.id)
309    }
310}
311
312/// Whether the literal option is set.
313#[derive(Default, Debug)]
314pub(crate) enum BuiltInLiteral {
315    Yes(Span),
316    #[default]
317    No,
318}
319
320impl BuiltInLiteral {
321    /// Take the literal option.
322    pub(crate) fn take(&mut self) -> Self {
323        take(self)
324    }
325
326    /// Test if the literal option is set.
327    pub(crate) fn is_yes(&self) -> bool {
328        matches!(self, Self::Yes(_))
329    }
330}
331
332/// A deferred build entry.
333pub(crate) enum DeferEntry {
334    ImplItem(ImplItem),
335    ExpandMacroBuiltin(ExpandMacroBuiltin),
336    ExpandMacroCall(ExpandMacroBuiltin),
337}
338
339/// A compiled constant function.
340pub(crate) struct ConstFn<'hir> {
341    /// The item of the const fn.
342    pub(crate) item_meta: ItemMeta,
343    /// The soon-to-be deprecated IR function.
344    pub(crate) ir_fn: ir::IrFn,
345    /// HIR function associated with this constant function.
346    #[allow(unused)]
347    pub(crate) hir: hir::ItemFn<'hir>,
348}
349
350/// The data of a macro call.
351pub(crate) enum ExpandedMacro {
352    /// A built-in expanded macro.
353    Builtin(BuiltInMacro2),
354    /// The expanded body of a macro.
355    Tree(Rc<Tree>),
356}
357
358/// Generic parameters.
359#[derive(Default)]
360pub(crate) struct GenericsParameters {
361    pub(crate) trailing: usize,
362    pub(crate) parameters: [Option<Hash>; 2],
363}
364
365impl GenericsParameters {
366    pub(crate) fn is_empty(&self) -> bool {
367        self.parameters.iter().all(|p| p.is_none())
368    }
369}
370
371impl fmt::Debug for GenericsParameters {
372    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373        let mut f = f.debug_list();
374
375        for p in &self.parameters[2 - self.trailing..] {
376            f.entry(p);
377        }
378
379        f.finish()
380    }
381}
382
383impl AsRef<GenericsParameters> for GenericsParameters {
384    #[inline]
385    fn as_ref(&self) -> &GenericsParameters {
386        self
387    }
388}