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