tinymist_analysis/syntax/
def.rs

1//! Definitions of syntax structures.
2
3use core::fmt;
4use std::{
5    collections::BTreeMap,
6    ops::{Deref, Range},
7    sync::Arc,
8};
9
10use rustc_hash::FxHashMap;
11use serde::{Deserialize, Serialize};
12use tinymist_derive::DeclEnum;
13use tinymist_std::DefId;
14use tinymist_world::package::PackageSpec;
15use typst::{
16    foundations::{Element, Func, Module, Type, Value},
17    syntax::{Span, SyntaxNode},
18    utils::LazyHash,
19};
20
21use crate::{
22    adt::interner::impl_internable,
23    docs::DocString,
24    prelude::*,
25    ty::{InsTy, Interned, SelectTy, Ty, TypeVar},
26};
27
28use super::{ExprDescriber, ExprPrinter};
29
30/// Information about expressions in a source file.
31///
32/// This structure wraps expression analysis data and provides access to
33/// expression resolution, documentation, and scoping information.
34#[derive(Debug, Clone, Hash)]
35pub struct ExprInfo(Arc<LazyHash<ExprInfoRepr>>);
36
37impl ExprInfo {
38    /// Creates a new [`ExprInfo`] instance from expression information
39    /// representation.
40    ///
41    /// Wraps the provided representation in an Arc and LazyHash for efficient
42    /// sharing and hashing.
43    pub fn new(repr: ExprInfoRepr) -> Self {
44        Self(Arc::new(LazyHash::new(repr)))
45    }
46}
47
48impl Deref for ExprInfo {
49    type Target = Arc<LazyHash<ExprInfoRepr>>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.0
53    }
54}
55
56/// Representation of [`ExprInfo`] for a specific file.
57///
58/// Contains all the analyzed information including resolution maps,
59/// documentation strings, imports, and exports.
60#[derive(Debug)]
61pub struct ExprInfoRepr {
62    /// The file ID this expression information belongs to.
63    pub fid: TypstFileId,
64    /// Revision number for tracking changes to the file.
65    pub revision: usize,
66    /// The source code content.
67    pub source: Source,
68    /// The root expression of the file.
69    pub root: Expr,
70    /// Documentation string for the module.
71    pub module_docstring: Arc<DocString>,
72    /// The lexical scope of exported symbols from this file.
73    pub exports: Arc<LazyHash<LexicalScope>>,
74    /// Map from file IDs to imported lexical scopes.
75    pub imports: FxHashMap<TypstFileId, Arc<LazyHash<LexicalScope>>>,
76    /// Map from spans to expressions for scope analysis.
77    pub exprs: FxHashMap<Span, Expr>,
78    /// Map from spans to resolved reference expressions.
79    pub resolves: FxHashMap<Span, Interned<RefExpr>>,
80    /// Map from declarations to their documentation strings.
81    pub docstrings: FxHashMap<DeclExpr, Arc<DocString>>,
82    /// Layout information for module import items in this file.
83    pub module_items: FxHashMap<Interned<Decl>, ModuleItemLayout>,
84}
85
86impl std::hash::Hash for ExprInfoRepr {
87    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
88        // already contained in the source.
89        // self.fid.hash(state);
90        self.revision.hash(state);
91        self.source.hash(state);
92        self.root.hash(state);
93        self.exports.hash(state);
94        let mut resolves = self.resolves.iter().collect::<Vec<_>>();
95        resolves.sort_by_key(|(fid, _)| fid.into_raw());
96        resolves.hash(state);
97        let mut imports = self.imports.iter().collect::<Vec<_>>();
98        imports.sort_by_key(|(fid, _)| *fid);
99        imports.hash(state);
100        let mut module_items = self.module_items.iter().collect::<Vec<_>>();
101        module_items.sort_by_key(|(decl, _)| decl.span().into_raw());
102        module_items.hash(state);
103    }
104}
105
106impl ExprInfoRepr {
107    /// Gets the definition expression for a given declaration.
108    pub fn get_def(&self, decl: &Interned<Decl>) -> Option<Expr> {
109        if decl.is_def() {
110            return Some(Expr::Decl(decl.clone()));
111        }
112        let resolved = self.resolves.get(&decl.span())?;
113        Some(Expr::Ref(resolved.clone()))
114    }
115
116    /// Gets all references to a given declaration.
117    pub fn get_refs(
118        &self,
119        decl: Interned<Decl>,
120    ) -> impl Iterator<Item = (&Span, &Interned<RefExpr>)> {
121        let of = Some(Expr::Decl(decl.clone()));
122        self.resolves
123            .iter()
124            .filter(move |(_, r)| match (decl.as_ref(), r.decl.as_ref()) {
125                (Decl::Label(..), Decl::Label(..)) => r.decl == decl,
126                (Decl::Label(..), Decl::ContentRef(..)) => r.decl.name() == decl.name(),
127                (Decl::Label(..), _) => false,
128                _ => r.decl == decl || r.root == of,
129            })
130    }
131
132    /// Checks if a declaration is exported from this module.
133    pub fn is_exported(&self, decl: &Interned<Decl>) -> bool {
134        let of = Expr::Decl(decl.clone());
135        self.exports
136            .get(decl.name())
137            .is_some_and(|export| match export {
138                Expr::Ref(ref_expr) => ref_expr.root == Some(of),
139                exprt => *exprt == of,
140            })
141    }
142
143    /// Shows the expression information.
144    #[allow(dead_code)]
145    fn show(&self) {
146        use std::io::Write;
147        let vpath = self
148            .fid
149            .vpath()
150            .resolve(Path::new("target/exprs/"))
151            .unwrap();
152        let root = vpath.with_extension("root.expr");
153        std::fs::create_dir_all(root.parent().unwrap()).unwrap();
154        std::fs::write(root, format!("{}", self.root)).unwrap();
155        let scopes = vpath.with_extension("scopes.expr");
156        std::fs::create_dir_all(scopes.parent().unwrap()).unwrap();
157        {
158            let mut scopes = std::fs::File::create(scopes).unwrap();
159            for (span, expr) in self.exprs.iter() {
160                writeln!(scopes, "{span:?} -> {expr}").unwrap();
161            }
162        }
163        let imports = vpath.with_extension("imports.expr");
164        std::fs::create_dir_all(imports.parent().unwrap()).unwrap();
165        std::fs::write(imports, format!("{:#?}", self.imports)).unwrap();
166        let exports = vpath.with_extension("exports.expr");
167        std::fs::create_dir_all(exports.parent().unwrap()).unwrap();
168        std::fs::write(exports, format!("{:#?}", self.exports)).unwrap();
169    }
170}
171
172/// Describes how an import item is laid out in the source text.
173#[derive(Debug, Clone, Hash)]
174pub struct ModuleItemLayout {
175    /// The module declaration that owns this item.
176    pub parent: Interned<Decl>,
177    /// The byte range covering the whole `foo as bar` clause.
178    pub item_range: Range<usize>,
179    /// The byte range covering the bound identifier (`bar` in `foo as bar`).
180    pub binding_range: Range<usize>,
181}
182
183/// Represents different kinds of expressions in the language.
184///
185/// This enum covers all possible expression types that can appear in Typst
186/// source code, from basic literals to complex control flow constructs.
187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
188pub enum Expr {
189    /// A sequence of expressions: `{ x; y; z }`
190    Block(Interned<Vec<Expr>>),
191    /// An array literal: `(1, 2, 3)`
192    Array(Interned<ArgsExpr>),
193    /// A dict literal: `(a: 1, b: 2)`
194    Dict(Interned<ArgsExpr>),
195    /// An args literal: `(1, 2, 3)`
196    Args(Interned<ArgsExpr>),
197    /// A pattern: `(x, y, ..z)`
198    Pattern(Interned<Pattern>),
199    /// An element literal: `[*Hi* there!]`
200    Element(Interned<ElementExpr>),
201    /// An unary operation: `-x`
202    Unary(Interned<UnExpr>),
203    /// A binary operation: `x + y`
204    Binary(Interned<BinExpr>),
205    /// A function call: `f(x, y)`
206    Apply(Interned<ApplyExpr>),
207    /// A function: `(x, y) => x + y`
208    Func(Interned<FuncExpr>),
209    /// A let: `let x = 1`
210    Let(Interned<LetExpr>),
211    /// A show: `show heading: it => emph(it.body)`
212    Show(Interned<ShowExpr>),
213    /// A set: `set text(...)`
214    Set(Interned<SetExpr>),
215    /// A reference: `#x`
216    Ref(Interned<RefExpr>),
217    /// A content reference: `@x`
218    ContentRef(Interned<ContentRefExpr>),
219    /// A select: `x.y`
220    Select(Interned<SelectExpr>),
221    /// An import expression: `import "path.typ": x`
222    Import(Interned<ImportExpr>),
223    /// An include expression: `include "path.typ"`
224    Include(Interned<IncludeExpr>),
225    /// A contextual expression: `context text.lang`
226    Contextual(Interned<Expr>),
227    /// A conditional expression: `if x { y } else { z }`
228    Conditional(Interned<IfExpr>),
229    /// A while loop: `while x { y }`
230    WhileLoop(Interned<WhileExpr>),
231    /// A for loop: `for x in y { z }`
232    ForLoop(Interned<ForExpr>),
233    /// A type: `str`
234    Type(Ty),
235    /// A declaration: `x`
236    Decl(DeclExpr),
237    /// A star import: `*`
238    Star,
239}
240
241impl Expr {
242    /// Returns a string representation of the expression.
243    pub fn repr(&self) -> EcoString {
244        let mut s = EcoString::new();
245        let _ = ExprDescriber::new(&mut s).write_expr(self);
246        s
247    }
248
249    /// Returns the span location of the expression.
250    pub fn span(&self) -> Span {
251        match self {
252            Expr::Decl(decl) => decl.span(),
253            Expr::Select(select) => select.span,
254            Expr::Apply(apply) => apply.span,
255            _ => Span::detached(),
256        }
257    }
258
259    /// Returns the file ID associated with this expression, if any.
260    pub fn file_id(&self) -> Option<TypstFileId> {
261        match self {
262            Expr::Decl(decl) => decl.file_id(),
263            _ => self.span().id(),
264        }
265    }
266
267    /// Returns whether the expression is definitely defined.
268    pub fn is_defined(&self) -> bool {
269        match self {
270            Expr::Ref(refs) => refs.root.is_some() || refs.term.is_some(),
271            Expr::Decl(decl) => decl.is_def(),
272            // There are unsure cases, like `x.y`, which may be defined or not.
273            _ => false,
274        }
275    }
276}
277
278impl fmt::Display for Expr {
279    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280        ExprPrinter::new(f).write_expr(self)
281    }
282}
283
284/// Type alias for lexical scopes.
285///
286/// Represents a lexical scope as a persistent map from names to expressions.
287pub type LexicalScope = rpds::RedBlackTreeMapSync<Interned<str>, Expr>;
288
289/// Different types of scopes for expression evaluation.
290///
291/// Represents the various kinds of scopes that can contain variable bindings,
292/// including lexical scopes, modules, functions, and types.
293#[derive(Debug, Clone)]
294pub enum ExprScope {
295    /// A lexical scope extracted from a source file.
296    Lexical(LexicalScope),
297    /// A module instance which is either built-in or evaluated during analysis.
298    Module(Module),
299    /// A scope bound to a function.
300    Func(Func),
301    /// A scope bound to a type.
302    Type(Type),
303}
304
305impl ExprScope {
306    /// Creates an empty lexical scope.
307    pub fn empty() -> Self {
308        ExprScope::Lexical(LexicalScope::default())
309    }
310
311    /// Checks if the scope contains no bindings.
312    pub fn is_empty(&self) -> bool {
313        match self {
314            ExprScope::Lexical(scope) => scope.is_empty(),
315            ExprScope::Module(module) => is_empty_scope(module.scope()),
316            ExprScope::Func(func) => func.scope().is_none_or(is_empty_scope),
317            ExprScope::Type(ty) => is_empty_scope(ty.scope()),
318        }
319    }
320
321    /// Looks up a name in the scope and returns both expression and type
322    /// information.
323    pub fn get(&self, name: &Interned<str>) -> (Option<Expr>, Option<Ty>) {
324        let (of, val) = match self {
325            ExprScope::Lexical(scope) => {
326                crate::log_debug_ct!("evaluating: {name:?} in {scope:?}");
327                (scope.get(name).cloned(), None)
328            }
329            ExprScope::Module(module) => {
330                let v = module.scope().get(name);
331                // let decl =
332                //     v.and_then(|_| Some(Decl::external(module.file_id()?,
333                // name.clone()).into()));
334                (None, v)
335            }
336            ExprScope::Func(func) => (None, func.scope().unwrap().get(name)),
337            ExprScope::Type(ty) => (None, ty.scope().get(name)),
338        };
339
340        // ref_expr.of = of.clone();
341        // ref_expr.val = val.map(|v| Ty::Value(InsTy::new(v.clone())));
342        // return ref_expr;
343        (
344            of,
345            val.cloned()
346                .map(|val| Ty::Value(InsTy::new(val.read().to_owned()))),
347        )
348    }
349
350    /// Merges all bindings from this scope into the provided export map.
351    pub fn merge_into(&self, exports: &mut LexicalScope) {
352        match self {
353            ExprScope::Lexical(scope) => {
354                for (name, expr) in scope.iter() {
355                    exports.insert_mut(name.clone(), expr.clone());
356                }
357            }
358            ExprScope::Module(module) => {
359                crate::log_debug_ct!("imported: {module:?}");
360                let v = Interned::new(Ty::Value(InsTy::new(Value::Module(module.clone()))));
361                for (name, _) in module.scope().iter() {
362                    let name: Interned<str> = name.into();
363                    exports.insert_mut(name.clone(), select_of(v.clone(), name));
364                }
365            }
366            ExprScope::Func(func) => {
367                if let Some(scope) = func.scope() {
368                    let v = Interned::new(Ty::Value(InsTy::new(Value::Func(func.clone()))));
369                    for (name, _) in scope.iter() {
370                        let name: Interned<str> = name.into();
371                        exports.insert_mut(name.clone(), select_of(v.clone(), name));
372                    }
373                }
374            }
375            ExprScope::Type(ty) => {
376                let v = Interned::new(Ty::Value(InsTy::new(Value::Type(*ty))));
377                for (name, _) in ty.scope().iter() {
378                    let name: Interned<str> = name.into();
379                    exports.insert_mut(name.clone(), select_of(v.clone(), name));
380                }
381            }
382        }
383    }
384}
385
386fn select_of(source: Interned<Ty>, name: Interned<str>) -> Expr {
387    Expr::Type(Ty::Select(SelectTy::new(source, name)))
388}
389
390/// Kind of a definition.
391#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
392#[serde(rename_all = "camelCase")]
393pub enum DefKind {
394    /// A definition for some constant: `let x = 1`
395    #[default]
396    Constant,
397    /// A definition for some function: `(x, y) => x + y`
398    Function,
399    /// A definition for some variable: `let x = (x, y) => x + y`
400    Variable,
401    /// A definition for some module.
402    Module,
403    /// A definition for some struct (type).
404    Struct,
405    /// A definition for some reference: `<label>`
406    Reference,
407}
408
409impl fmt::Display for DefKind {
410    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411        match self {
412            Self::Constant => write!(f, "constant"),
413            Self::Function => write!(f, "function"),
414            Self::Variable => write!(f, "variable"),
415            Self::Module => write!(f, "module"),
416            Self::Struct => write!(f, "struct"),
417            Self::Reference => write!(f, "reference"),
418        }
419    }
420}
421
422/// Type alias for declaration expressions.
423pub type DeclExpr = Interned<Decl>;
424
425/// Represents different kinds of declarations in the language.
426#[derive(Clone, PartialEq, Eq, Hash, DeclEnum)]
427pub enum Decl {
428    /// A function declaration: `(x, y) => x + y`
429    Func(SpannedDecl),
430    /// An import alias declaration: `import "path.typ": x`
431    ImportAlias(SpannedDecl),
432    /// A variable declaration: `let x = 1`
433    Var(SpannedDecl),
434    /// An identifier reference declaration: `x`
435    IdentRef(SpannedDecl),
436    /// A module declaration: `import calc`
437    Module(ModuleDecl),
438    /// A module alias declaration: `import "path.typ" as x`
439    ModuleAlias(SpannedDecl),
440    /// A path stem declaration: `path.typ`
441    PathStem(SpannedDecl),
442    /// An import path declaration: `import "path.typ"`
443    ImportPath(SpannedDecl),
444    /// An include path declaration: `include "path.typ"`
445    IncludePath(SpannedDecl),
446    /// An import declaration: `import "path.typ"`
447    Import(SpannedDecl),
448    /// A content reference declaration: `@x`
449    ContentRef(SpannedDecl),
450    /// A label declaration: `label`
451    Label(SpannedDecl),
452    /// A string name declaration: `"x"`
453    StrName(SpannedDecl),
454    /// A module import declaration: `import "path.typ": *`
455    ModuleImport(SpanDecl),
456    /// A closure declaration: `(x, y) => x + y`
457    Closure(SpanDecl),
458    /// A pattern declaration: `let (x, y, ..z) = 1`
459    Pattern(SpanDecl),
460    /// A spread declaration: `..z`
461    Spread(SpanDecl),
462    /// A content declaration: `#[text]`
463    Content(SpanDecl),
464    /// A constant declaration: `let x = 1`
465    Constant(SpanDecl),
466    /// A bib entry declaration: `@entry`
467    BibEntry(NameRangeDecl),
468    /// A docs declaration created by the compiler.
469    Docs(DocsDecl),
470    /// A generated declaration created by the compiler.
471    Generated(GeneratedDecl),
472}
473
474impl Decl {
475    /// Creates a function declaration from an identifier.
476    pub fn func(ident: ast::Ident) -> Self {
477        Self::Func(SpannedDecl {
478            name: ident.get().into(),
479            at: ident.span(),
480        })
481    }
482
483    /// Creates a variable declaration from a string literal.
484    pub fn lit(name: &str) -> Self {
485        Self::Var(SpannedDecl {
486            name: name.into(),
487            at: Span::detached(),
488        })
489    }
490
491    /// Creates a variable declaration from an interned string.
492    pub fn lit_(name: Interned<str>) -> Self {
493        Self::Var(SpannedDecl {
494            name,
495            at: Span::detached(),
496        })
497    }
498
499    /// Creates a variable declaration from an identifier.
500    pub fn var(ident: ast::Ident) -> Self {
501        Self::Var(SpannedDecl {
502            name: ident.get().into(),
503            at: ident.span(),
504        })
505    }
506
507    /// Creates an import alias declaration from an identifier.
508    pub fn import_alias(ident: ast::Ident) -> Self {
509        Self::ImportAlias(SpannedDecl {
510            name: ident.get().into(),
511            at: ident.span(),
512        })
513    }
514
515    /// Creates an identifier reference declaration from an identifier.
516    pub fn ident_ref(ident: ast::Ident) -> Self {
517        Self::IdentRef(SpannedDecl {
518            name: ident.get().into(),
519            at: ident.span(),
520        })
521    }
522
523    /// Creates an identifier reference declaration from a math identifier.
524    pub fn math_ident_ref(ident: ast::MathIdent) -> Self {
525        Self::IdentRef(SpannedDecl {
526            name: ident.get().into(),
527            at: ident.span(),
528        })
529    }
530
531    /// Creates a module declaration with a file ID.
532    pub fn module(fid: TypstFileId) -> Self {
533        let name = {
534            let stem = fid.vpath().as_rooted_path().file_stem();
535            stem.and_then(|s| Some(Interned::new_str(s.to_str()?)))
536                .unwrap_or_default()
537        };
538        Self::Module(ModuleDecl { name, fid })
539    }
540
541    /// Creates a module declaration with a name and a file ID.
542    pub fn module_with_name(name: Interned<str>, fid: TypstFileId) -> Self {
543        Self::Module(ModuleDecl { name, fid })
544    }
545
546    /// Creates a module alias declaration from an identifier.
547    pub fn module_alias(ident: ast::Ident) -> Self {
548        Self::ModuleAlias(SpannedDecl {
549            name: ident.get().into(),
550            at: ident.span(),
551        })
552    }
553
554    /// Creates an import declaration from an identifier.
555    pub fn import(ident: ast::Ident) -> Self {
556        Self::Import(SpannedDecl {
557            name: ident.get().into(),
558            at: ident.span(),
559        })
560    }
561
562    /// Creates a label declaration with a name and span.
563    pub fn label(name: &str, at: Span) -> Self {
564        Self::Label(SpannedDecl {
565            name: name.into(),
566            at,
567        })
568    }
569
570    /// Creates a content reference declaration from a reference AST node.
571    pub fn ref_(ident: ast::Ref) -> Self {
572        Self::ContentRef(SpannedDecl {
573            name: ident.target().into(),
574            at: ident.span(),
575        })
576    }
577
578    /// Creates a string name declaration from a syntax node and name.
579    pub fn str_name(s: SyntaxNode, name: &str) -> Decl {
580        Self::StrName(SpannedDecl {
581            name: name.into(),
582            at: s.span(),
583        })
584    }
585
586    /// Calculates the path stem from a string path or package specification.
587    ///
588    /// For package specs (starting with '@'), extracts the package name.
589    /// For file paths, extracts the file stem. Returns empty string if
590    /// extraction fails.
591    pub fn calc_path_stem(s: &str) -> Interned<str> {
592        use std::str::FromStr;
593        let name = if s.starts_with('@') {
594            let spec = PackageSpec::from_str(s).ok();
595            spec.map(|spec| Interned::new_str(spec.name.as_str()))
596        } else {
597            let stem = Path::new(s).file_stem();
598            stem.and_then(|stem| Some(Interned::new_str(stem.to_str()?)))
599        };
600        name.unwrap_or_default()
601    }
602
603    /// Creates a path stem declaration from a syntax node and name.
604    pub fn path_stem(s: SyntaxNode, name: Interned<str>) -> Self {
605        Self::PathStem(SpannedDecl { name, at: s.span() })
606    }
607
608    /// Creates an import path declaration with a span and name.
609    pub fn import_path(s: Span, name: Interned<str>) -> Self {
610        Self::ImportPath(SpannedDecl { name, at: s })
611    }
612
613    /// Creates an include path declaration with a span and name.
614    pub fn include_path(s: Span, name: Interned<str>) -> Self {
615        Self::IncludePath(SpannedDecl { name, at: s })
616    }
617
618    /// Creates a module import declaration with just a span.
619    pub fn module_import(s: Span) -> Self {
620        Self::ModuleImport(SpanDecl(s))
621    }
622
623    /// Creates a closure declaration with just a span.
624    pub fn closure(s: Span) -> Self {
625        Self::Closure(SpanDecl(s))
626    }
627
628    /// Creates a pattern declaration with just a span.
629    pub fn pattern(s: Span) -> Self {
630        Self::Pattern(SpanDecl(s))
631    }
632
633    /// Creates a spread declaration with just a span.
634    pub fn spread(s: Span) -> Self {
635        Self::Spread(SpanDecl(s))
636    }
637
638    /// Creates a content declaration with just a span.
639    pub fn content(s: Span) -> Self {
640        Self::Content(SpanDecl(s))
641    }
642
643    /// Creates a constant declaration with just a span.
644    pub fn constant(s: Span) -> Self {
645        Self::Constant(SpanDecl(s))
646    }
647
648    /// Creates a documentation declaration linking a base declaration with a
649    /// type variable.
650    pub fn docs(base: Interned<Decl>, var: Interned<TypeVar>) -> Self {
651        Self::Docs(DocsDecl { base, var })
652    }
653
654    /// Creates a generated declaration with a definition ID.
655    pub fn generated(def_id: DefId) -> Self {
656        Self::Generated(GeneratedDecl(def_id))
657    }
658
659    /// Creates a bibliography entry declaration.
660    pub fn bib_entry(
661        name: Interned<str>,
662        fid: TypstFileId,
663        name_range: Range<usize>,
664        range: Option<Range<usize>>,
665    ) -> Self {
666        Self::BibEntry(NameRangeDecl {
667            name,
668            at: Box::new((fid, name_range, range)),
669        })
670    }
671
672    /// Checks if this declaration represents a definition rather than a
673    /// reference (usage of a definition).
674    pub fn is_def(&self) -> bool {
675        matches!(
676            self,
677            Self::Func(..)
678                | Self::BibEntry(..)
679                | Self::Closure(..)
680                | Self::Var(..)
681                | Self::Label(..)
682                | Self::StrName(..)
683                | Self::Module(..)
684                | Self::ModuleImport(..)
685                | Self::PathStem(..)
686                | Self::ImportPath(..)
687                | Self::IncludePath(..)
688                | Self::Spread(..)
689                | Self::Generated(..)
690        )
691    }
692
693    /// Returns the kind of definition this declaration represents.
694    pub fn kind(&self) -> DefKind {
695        use Decl::*;
696        match self {
697            ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
698                DefKind::Module
699            }
700            // Type(_) => DocStringKind::Struct,
701            Func(..) | Closure(..) => DefKind::Function,
702            Label(..) | BibEntry(..) | ContentRef(..) => DefKind::Reference,
703            IdentRef(..) | ImportAlias(..) | Import(..) | Var(..) => DefKind::Variable,
704            Pattern(..) | Docs(..) | Generated(..) | Constant(..) | StrName(..)
705            | ModuleImport(..) | Content(..) | Spread(..) => DefKind::Constant,
706        }
707    }
708
709    /// Gets file location of the declaration.
710    pub fn file_id(&self) -> Option<TypstFileId> {
711        match self {
712            Self::Module(ModuleDecl { fid, .. }) => Some(*fid),
713            Self::BibEntry(NameRangeDecl { at, .. }) => Some(at.0),
714            that => that.span().id(),
715        }
716    }
717
718    /// Gets full range of the declaration.
719    pub fn full_range(&self) -> Option<Range<usize>> {
720        if let Decl::BibEntry(decl) = self {
721            return decl.at.2.clone();
722        }
723
724        None
725    }
726
727    /// Creates a reference expression that points to this declaration.
728    pub fn as_def(this: &Interned<Self>, val: Option<Ty>) -> Interned<RefExpr> {
729        let def: Expr = this.clone().into();
730        Interned::new(RefExpr {
731            decl: this.clone(),
732            step: Some(def.clone()),
733            root: Some(def),
734            term: val,
735        })
736    }
737}
738
739impl Ord for Decl {
740    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
741        let base = match (self, other) {
742            (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
743            (Self::Module(l), Self::Module(r)) => l.fid.cmp(&r.fid),
744            (Self::Docs(l), Self::Docs(r)) => l.var.cmp(&r.var).then_with(|| l.base.cmp(&r.base)),
745            _ => self.span().into_raw().cmp(&other.span().into_raw()),
746        };
747
748        base.then_with(|| self.name().cmp(other.name()))
749    }
750}
751
752trait StrictCmp {
753    /// Low-performance comparison but it is free from the concurrency issue.
754    /// This is only used for making stable test snapshots.
755    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering;
756}
757
758impl Decl {
759    /// Low-performance comparison that is free from concurrency issues.
760    pub fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
761        let base = match (self, other) {
762            (Self::Generated(l), Self::Generated(r)) => l.0.0.cmp(&r.0.0),
763            (Self::Module(l), Self::Module(r)) => l.fid.strict_cmp(&r.fid),
764            (Self::Docs(l), Self::Docs(r)) => l
765                .var
766                .strict_cmp(&r.var)
767                .then_with(|| l.base.strict_cmp(&r.base)),
768            _ => self.span().strict_cmp(&other.span()),
769        };
770
771        base.then_with(|| self.name().cmp(other.name()))
772    }
773}
774
775impl StrictCmp for TypstFileId {
776    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
777        self.package()
778            .map(ToString::to_string)
779            .cmp(&other.package().map(ToString::to_string))
780            .then_with(|| self.vpath().cmp(other.vpath()))
781    }
782}
783impl<T: StrictCmp> StrictCmp for Option<T> {
784    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
785        match (self, other) {
786            (Some(l), Some(r)) => l.strict_cmp(r),
787            (Some(_), None) => std::cmp::Ordering::Greater,
788            (None, Some(_)) => std::cmp::Ordering::Less,
789            (None, None) => std::cmp::Ordering::Equal,
790        }
791    }
792}
793
794impl StrictCmp for Span {
795    fn strict_cmp(&self, other: &Self) -> std::cmp::Ordering {
796        self.id()
797            .strict_cmp(&other.id())
798            .then_with(|| self.into_raw().cmp(&other.into_raw()))
799    }
800}
801
802impl PartialOrd for Decl {
803    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
804        Some(self.cmp(other))
805    }
806}
807
808impl From<Decl> for Expr {
809    fn from(decl: Decl) -> Self {
810        Expr::Decl(decl.into())
811    }
812}
813
814impl From<DeclExpr> for Expr {
815    fn from(decl: DeclExpr) -> Self {
816        Expr::Decl(decl)
817    }
818}
819
820/// A declaration with an associated name and span location.
821#[derive(Clone, PartialEq, Eq, Hash)]
822pub struct SpannedDecl {
823    /// The name of the declaration.
824    name: Interned<str>,
825    /// The span location of the declaration.
826    at: Span,
827}
828
829impl SpannedDecl {
830    /// Gets the name of the declaration.
831    fn name(&self) -> &Interned<str> {
832        &self.name
833    }
834
835    /// Gets the span location of the declaration.
836    fn span(&self) -> Span {
837        self.at
838    }
839}
840
841impl fmt::Debug for SpannedDecl {
842    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
843        f.write_str(self.name.as_ref())
844    }
845}
846
847/// A declaration with a name and range information.
848#[derive(Clone, PartialEq, Eq, Hash)]
849pub struct NameRangeDecl {
850    /// The name of the declaration.
851    pub name: Interned<str>,
852    /// Boxed tuple containing (file_id, name_range, full_range).
853    pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
854}
855
856impl NameRangeDecl {
857    /// Gets the name of the declaration.
858    fn name(&self) -> &Interned<str> {
859        &self.name
860    }
861
862    /// Gets the span location of the declaration.
863    fn span(&self) -> Span {
864        Span::detached()
865    }
866}
867
868impl fmt::Debug for NameRangeDecl {
869    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
870        f.write_str(self.name.as_ref())
871    }
872}
873
874/// A module declaration with name and file ID.
875#[derive(Clone, PartialEq, Eq, Hash)]
876pub struct ModuleDecl {
877    /// The name of the module.
878    pub name: Interned<str>,
879    /// The file ID where the module is defined.
880    pub fid: TypstFileId,
881}
882
883impl ModuleDecl {
884    /// Gets the name of the declaration.
885    fn name(&self) -> &Interned<str> {
886        &self.name
887    }
888
889    /// Gets the span location of the declaration.
890    fn span(&self) -> Span {
891        Span::detached()
892    }
893}
894
895impl fmt::Debug for ModuleDecl {
896    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
897        f.write_str(self.name.as_ref())
898    }
899}
900
901/// A documentation declaration linking a base declaration with type variables.
902#[derive(Clone, PartialEq, Eq, Hash)]
903pub struct DocsDecl {
904    base: Interned<Decl>,
905    var: Interned<TypeVar>,
906}
907
908impl DocsDecl {
909    /// Gets the name of the declaration.
910    fn name(&self) -> &Interned<str> {
911        Interned::empty()
912    }
913
914    /// Gets the span location of the declaration.
915    fn span(&self) -> Span {
916        Span::detached()
917    }
918}
919
920impl fmt::Debug for DocsDecl {
921    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
922        write!(f, "{:?}, {:?}", self.base, self.var)
923    }
924}
925
926/// A span-only declaration for anonymous constructs.
927#[derive(Clone, PartialEq, Eq, Hash)]
928pub struct SpanDecl(Span);
929
930impl SpanDecl {
931    /// Gets the name of the declaration.
932    fn name(&self) -> &Interned<str> {
933        Interned::empty()
934    }
935
936    /// Gets the span location of the declaration.
937    fn span(&self) -> Span {
938        self.0
939    }
940}
941
942impl fmt::Debug for SpanDecl {
943    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
944        write!(f, "..")
945    }
946}
947
948/// A generated declaration with a unique definition ID.
949#[derive(Clone, PartialEq, Eq, Hash)]
950pub struct GeneratedDecl(DefId);
951
952impl GeneratedDecl {
953    /// Gets the name of the declaration.
954    fn name(&self) -> &Interned<str> {
955        Interned::empty()
956    }
957
958    /// Gets the span location of the declaration.
959    fn span(&self) -> Span {
960        Span::detached()
961    }
962}
963
964impl fmt::Debug for GeneratedDecl {
965    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
966        self.0.fmt(f)
967    }
968}
969
970/// Type alias for unary expressions.
971pub type UnExpr = UnInst<Expr>;
972/// Type alias for binary expressions.
973pub type BinExpr = BinInst<Expr>;
974
975/// Type alias for export maps.
976///
977/// Maps exported names to their corresponding expressions.
978pub type ExportMap = BTreeMap<Interned<str>, Expr>;
979
980/// Represents different kinds of function arguments.
981///
982/// Covers positional arguments, named arguments, and spread arguments.
983#[derive(Debug, Clone, PartialEq, Eq, Hash)]
984pub enum ArgExpr {
985    /// A positional argument: `x`
986    Pos(Expr),
987    /// A named argument: `a: x`
988    Named(Box<(DeclExpr, Expr)>),
989    /// A named argument with a default value: `((a): x)`
990    NamedRt(Box<(Expr, Expr)>),
991    /// A spread argument: `..x`
992    Spread(Expr),
993}
994
995/// Represents different kinds of patterns for destructuring.
996#[derive(Debug, Clone, PartialEq, Eq, Hash)]
997pub enum Pattern {
998    /// A general pattern expression can occur in right-hand side of a
999    /// function signature.
1000    Expr(Expr),
1001    /// A simple pattern: `x`
1002    Simple(Interned<Decl>),
1003    /// A pattern signature: `(x, y: val, ..z)`
1004    Sig(Box<PatternSig>),
1005}
1006
1007impl fmt::Display for Pattern {
1008    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1009        ExprPrinter::new(f).write_pattern(self)
1010    }
1011}
1012
1013impl Pattern {
1014    /// Returns a string representation of the pattern.
1015    pub fn repr(&self) -> EcoString {
1016        let mut s = EcoString::new();
1017        let _ = ExprDescriber::new(&mut s).write_pattern(self);
1018        s
1019    }
1020}
1021
1022/// Signature pattern for function parameters.
1023///
1024/// Describes the structure of function parameters including positional,
1025/// named, and spread parameters.
1026#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1027pub struct PatternSig {
1028    /// Positional parameters in order.
1029    pub pos: EcoVec<Interned<Pattern>>,
1030    /// Named parameters with their default patterns.
1031    pub named: EcoVec<(DeclExpr, Interned<Pattern>)>,
1032    /// Left spread parameter (collects extra positional arguments).
1033    pub spread_left: Option<(DeclExpr, Interned<Pattern>)>,
1034    /// Right spread parameter (collects remaining arguments).
1035    pub spread_right: Option<(DeclExpr, Interned<Pattern>)>,
1036}
1037
1038impl Pattern {}
1039
1040impl_internable!(Decl,);
1041
1042/// Represents a content sequence expression.
1043///
1044/// Used for sequences of content elements with associated type information.
1045#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1046pub struct ContentSeqExpr {
1047    /// The type of the content sequence
1048    pub ty: Ty,
1049}
1050
1051/// Represents a reference expression.
1052///
1053/// A reference expression tracks how an identifier resolves through the lexical
1054/// scope, imports, and field accesses. It maintains a chain of resolution steps
1055/// to support features like go-to-definition, go-to-reference, and type
1056/// inference.
1057///
1058/// # Resolution Chain
1059///
1060/// The fields form a resolution chain: `root` -> `step` -> `decl`, where:
1061/// - `root` is the original source of the value
1062/// - `step` is any intermediate transformation
1063/// - `decl` is the final identifier being referenced
1064/// - `term` is the resolved type (if known)
1065///   - Hint: A value `1`'s typst type is `int`, but here we keep the type as
1066///     `1` to improve the type inference.
1067///
1068/// # Examples
1069///
1070/// ## Simple identifier reference
1071/// ```rust,ignore
1072/// // For: let x = value; let y = x;
1073/// RefExpr {
1074///     decl: y,           // The identifier 'y'
1075///     root: Some(x),     // Points back to 'x'
1076///     step: Some(x),     // Same as root for simple refs
1077///     term: None,        // Type may not be known yet
1078/// }
1079/// ```
1080///
1081/// ## Import with rename
1082/// ```rust,ignore
1083/// // For: import "mod.typ": old as new
1084/// // First creates ref for 'old':
1085/// RefExpr { decl: old, root: Some(mod.old), step: Some(field), term: Some(Func(() -> dict)) }
1086/// // Then creates ref for 'new':
1087/// RefExpr { decl: new, root: Some(mod.old), step: Some(old), term: Some(Func(() -> dict)) }
1088/// ```
1089///
1090/// ## Builtin definitions
1091/// ```rust,ignore
1092/// // For: std.length
1093/// RefExpr { decl: length, root: None, step: None, term: Some(Type(length)) }
1094/// ```
1095#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1096pub struct RefExpr {
1097    /// The declaration being referenced (the final identifier in the chain).
1098    ///
1099    /// This is always set and represents the identifier at the current point
1100    /// of reference (e.g., the variable name, import alias, or field name).
1101    pub decl: DeclExpr,
1102
1103    /// The intermediate expression in the resolution chain.
1104    ///
1105    /// Set in the following cases:
1106    /// - **Import/include**: The module expression being imported
1107    /// - **Field access**: The selected field's expression
1108    /// - **Scope resolution**: The scope expression being resolved
1109    /// - **Renamed imports**: The original name before renaming
1110    ///
1111    /// `None` when the identifier is an undefined reference.
1112    pub step: Option<Expr>,
1113
1114    /// The root expression at the start of the reference chain.
1115    ///
1116    /// A root definition never references another root definition.
1117    pub root: Option<Expr>,
1118
1119    /// The final resolved type of the referenced value.
1120    ///
1121    /// Set whenever a type is known for the referenced value.
1122    ///
1123    /// Some reference doesn't have a root definition, but has a term. For
1124    /// example, `std.length` is termed as `Type(length)` while has no a
1125    /// definition.
1126    pub term: Option<Ty>,
1127}
1128
1129/// Represents a content reference expression.
1130#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1131pub struct ContentRefExpr {
1132    /// The identifier being referenced.
1133    pub ident: DeclExpr,
1134    /// The declaration this reference points to (if resolved).
1135    pub of: Option<DeclExpr>,
1136    /// The body content associated with the reference.
1137    pub body: Option<Expr>,
1138}
1139
1140/// Represents a field selection expression.
1141#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1142pub struct SelectExpr {
1143    /// The left-hand side expression being selected from.
1144    pub lhs: Expr,
1145    /// The key or field name being selected.
1146    pub key: DeclExpr,
1147    /// The span location of this selection.
1148    pub span: Span,
1149}
1150
1151impl SelectExpr {
1152    /// Creates a new SelectExpr with the given key and left-hand side.
1153    pub fn new(key: DeclExpr, lhs: Expr) -> Interned<Self> {
1154        Interned::new(Self {
1155            key,
1156            lhs,
1157            span: Span::detached(),
1158        })
1159    }
1160}
1161
1162/// Represents an arguments expression.
1163#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1164pub struct ArgsExpr {
1165    /// The list of arguments.
1166    pub args: Vec<ArgExpr>,
1167    /// The span location of the argument list.
1168    pub span: Span,
1169}
1170
1171impl ArgsExpr {
1172    /// Creates a new ArgsExpr with the given span and arguments.
1173    pub fn new(span: Span, args: Vec<ArgExpr>) -> Interned<Self> {
1174        Interned::new(Self { args, span })
1175    }
1176}
1177
1178/// Represents an element expression.
1179#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1180pub struct ElementExpr {
1181    /// The Typst element type.
1182    pub elem: Element,
1183    /// The content expressions within this element.
1184    pub content: EcoVec<Expr>,
1185}
1186
1187/// Represents a function application expression.
1188#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1189pub struct ApplyExpr {
1190    /// The function expression being called.
1191    pub callee: Expr,
1192    /// The arguments passed to the function.
1193    pub args: Expr,
1194    /// The span location of the function call.
1195    pub span: Span,
1196}
1197
1198/// Represents a function expression.
1199#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1200pub struct FuncExpr {
1201    /// The declaration for this function.
1202    pub decl: DeclExpr,
1203    /// The parameter signature defining function inputs.
1204    pub params: PatternSig,
1205    /// The function body expression.
1206    pub body: Expr,
1207}
1208
1209/// Represents a let binding expression.
1210#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1211pub struct LetExpr {
1212    /// Span of the pattern.
1213    pub span: Span,
1214    /// The pattern being bound (left side of assignment).
1215    pub pattern: Interned<Pattern>,
1216    /// The optional body expression (right side of assignment).
1217    pub body: Option<Expr>,
1218}
1219
1220/// Represents a show rule expression.
1221#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1222pub struct ShowExpr {
1223    /// Optional selector expression to determine what to show.
1224    pub selector: Option<Expr>,
1225    /// The edit function to apply to selected elements.
1226    pub edit: Expr,
1227}
1228
1229/// Represents a set rule expression.
1230#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1231pub struct SetExpr {
1232    /// The target element or function to set.
1233    pub target: Expr,
1234    /// The arguments to apply to the target.
1235    pub args: Expr,
1236    /// Optional condition for when to apply the set rule.
1237    pub cond: Option<Expr>,
1238}
1239
1240/// Represents an import expression.
1241#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1242pub struct ImportExpr {
1243    /// The reference expression for what is being imported.
1244    pub decl: Interned<RefExpr>,
1245}
1246
1247/// Represents an include expression.
1248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1249pub struct IncludeExpr {
1250    /// The source expression indicating what file or content to include.
1251    pub source: Expr,
1252}
1253
1254/// Represents a conditional (if) expression.
1255#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1256pub struct IfExpr {
1257    /// The condition expression to evaluate.
1258    pub cond: Expr,
1259    /// The expression to evaluate if condition is true.
1260    pub then: Expr,
1261    /// The expression to evaluate if condition is false.
1262    pub else_: Expr,
1263}
1264
1265/// Represents a while loop expression.
1266#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1267pub struct WhileExpr {
1268    /// The condition expression evaluated each iteration.
1269    pub cond: Expr,
1270    /// The body expression executed while condition is true.
1271    pub body: Expr,
1272}
1273
1274/// Represents a for loop expression.
1275#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1276pub struct ForExpr {
1277    /// The pattern to match each iteration value against.
1278    pub pattern: Interned<Pattern>,
1279    /// The expression that produces values to iterate over.
1280    pub iter: Expr,
1281    /// The body expression executed for each iteration.
1282    pub body: Expr,
1283}
1284
1285/// The kind of unary operation.
1286#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
1287pub enum UnaryOp {
1288    /// The (arithmetic) positive operation.
1289    /// `+t`
1290    Pos,
1291    /// The (arithmetic) negate operation.
1292    /// `-t`
1293    Neg,
1294    /// The (logical) not operation.
1295    /// `not t`
1296    Not,
1297    /// The return operation.
1298    /// `return t`
1299    Return,
1300    /// The typst context operation.
1301    /// `context t`
1302    Context,
1303    /// The spreading operation.
1304    /// `..t`
1305    Spread,
1306    /// The not element of operation.
1307    /// `not in t`
1308    NotElementOf,
1309    /// The element of operation.
1310    /// `in t`
1311    ElementOf,
1312    /// The type of operation.
1313    /// `type(t)`
1314    TypeOf,
1315}
1316
1317/// A unary operation type.
1318#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1319pub struct UnInst<T> {
1320    /// The operand of the unary operation.
1321    pub lhs: T,
1322    /// The kind of the unary operation.
1323    pub op: UnaryOp,
1324}
1325
1326impl<T: Ord> PartialOrd for UnInst<T> {
1327    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1328        Some(self.cmp(other))
1329    }
1330}
1331
1332impl<T: Ord> Ord for UnInst<T> {
1333    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1334        let op_as_int = self.op as u8;
1335        let other_op_as_int = other.op as u8;
1336        op_as_int
1337            .cmp(&other_op_as_int)
1338            .then_with(|| self.lhs.cmp(&other.lhs))
1339    }
1340}
1341
1342impl UnInst<Expr> {
1343    /// Creates a unary operation type with the given operator and operand.
1344    pub fn new(op: UnaryOp, lhs: Expr) -> Interned<Self> {
1345        Interned::new(Self { lhs, op })
1346    }
1347}
1348
1349impl<T> UnInst<T> {
1350    /// Gets the operands of the unary operation.
1351    pub fn operands(&self) -> [&T; 1] {
1352        [&self.lhs]
1353    }
1354}
1355
1356/// Type alias for binary operation types.
1357pub type BinaryOp = ast::BinOp;
1358
1359/// A binary operation type.
1360#[derive(Debug, Hash, Clone, PartialEq, Eq)]
1361pub struct BinInst<T> {
1362    /// The operands of the binary operation (left, right).
1363    pub operands: (T, T),
1364    /// The kind of the binary operation.
1365    pub op: BinaryOp,
1366}
1367
1368impl<T: Ord> PartialOrd for BinInst<T> {
1369    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1370        Some(self.cmp(other))
1371    }
1372}
1373
1374impl<T: Ord> Ord for BinInst<T> {
1375    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1376        let op_as_int = self.op as u8;
1377        let other_op_as_int = other.op as u8;
1378        op_as_int
1379            .cmp(&other_op_as_int)
1380            .then_with(|| self.operands.cmp(&other.operands))
1381    }
1382}
1383
1384impl BinInst<Expr> {
1385    /// Creates a binary operation type with the given operator and operands.
1386    pub fn new(op: BinaryOp, lhs: Expr, rhs: Expr) -> Interned<Self> {
1387        Interned::new(Self {
1388            operands: (lhs, rhs),
1389            op,
1390        })
1391    }
1392}
1393
1394impl<T> BinInst<T> {
1395    /// Gets the operands of the binary operation.
1396    pub fn operands(&self) -> [&T; 2] {
1397        [&self.operands.0, &self.operands.1]
1398    }
1399}
1400
1401/// Checks if a scope is empty.
1402fn is_empty_scope(scope: &typst::foundations::Scope) -> bool {
1403    scope.iter().next().is_none()
1404}
1405
1406impl_internable!(
1407    Expr,
1408    ArgsExpr,
1409    ElementExpr,
1410    ContentSeqExpr,
1411    RefExpr,
1412    ContentRefExpr,
1413    SelectExpr,
1414    ImportExpr,
1415    IncludeExpr,
1416    IfExpr,
1417    WhileExpr,
1418    ForExpr,
1419    FuncExpr,
1420    LetExpr,
1421    ShowExpr,
1422    SetExpr,
1423    Pattern,
1424    EcoVec<(Decl, Expr)>,
1425    Vec<ArgExpr>,
1426    Vec<Expr>,
1427    UnInst<Expr>,
1428    BinInst<Expr>,
1429    ApplyExpr,
1430);