1use std::ops::DerefMut;
2
3use parking_lot::Mutex;
4use rpds::RedBlackTreeMapSync;
5use rustc_hash::FxHashMap;
6use std::ops::Deref;
7use tinymist_analysis::adt::interner::Interned;
8use tinymist_std::hash::hash128;
9use typst::{
10 foundations::{Element, NativeElement, Str, Type, Value},
11 model::{EmphElem, EnumElem, HeadingElem, ListElem, ParbreakElem, StrongElem, TermsElem},
12 syntax::{Span, SyntaxNode, ast::MathTextKind},
13 text::LinebreakElem,
14 utils::LazyHash,
15};
16
17use crate::{
18 analysis::{QueryStatGuard, SharedContext},
19 docs::DocString,
20 prelude::*,
21 syntax::{DefKind, find_module_level_docs, resolve_id_by_path},
22 ty::{BuiltinTy, InsTy, Ty},
23};
24
25use super::{DocCommentMatcher, InterpretMode, def::*};
26
27pub type ExprRoute = FxHashMap<TypstFileId, Option<Arc<LazyHash<LexicalScope>>>>;
30
31#[typst_macros::time(span = source.root().span())]
45pub(crate) fn expr_of(
46 ctx: Arc<SharedContext>,
47 source: Source,
48 route: &mut ExprRoute,
49 guard: QueryStatGuard,
50 prev: Option<ExprInfo>,
51) -> ExprInfo {
52 crate::log_debug_ct!("expr_of: {:?}", source.id());
53
54 route.insert(source.id(), None);
55
56 let cache_hit = prev.and_then(|prev| {
57 if prev.source.lines().len_bytes() != source.lines().len_bytes()
58 || hash128(&prev.source) != hash128(&source)
59 {
60 return None;
61 }
62 for (fid, prev_exports) in &prev.imports {
63 let ei = ctx.exports_of(&ctx.source_by_id(*fid).ok()?, route);
64
65 if let Some(exports) = ei
68 && (prev_exports.size() != exports.size()
69 || hash128(&prev_exports) != hash128(&exports))
70 {
71 return None;
72 }
73 }
74
75 Some(prev)
76 });
77
78 if let Some(prev) = cache_hit {
79 route.remove(&source.id());
80 return prev;
81 }
82 guard.miss();
83
84 let revision = ctx.revision();
85
86 let resolves_base = Arc::new(Mutex::new(vec![]));
87 let resolves = resolves_base.clone();
88
89 let docstrings_base = Arc::new(Mutex::new(FxHashMap::default()));
91 let docstrings = docstrings_base.clone();
92
93 let exprs_base = Arc::new(Mutex::new(FxHashMap::default()));
94 let exprs = exprs_base.clone();
95
96 let imports_base = Arc::new(Mutex::new(FxHashMap::default()));
97 let imports = imports_base.clone();
98
99 let module_docstring = find_module_level_docs(&source)
100 .and_then(|docs| ctx.compute_docstring(source.id(), docs, DefKind::Module))
101 .unwrap_or_default();
102
103 let mut worker = ExprWorker {
104 fid: source.id(),
105 source: source.clone(),
106 ctx,
107 imports,
108 docstrings,
109 exprs,
110 import_buffer: Vec::new(),
111 lexical: LexicalContext::default(),
112 resolves,
113 buffer: vec![],
114 module_items: FxHashMap::default(),
115 init_stage: true,
116 comment_matcher: DocCommentMatcher::default(),
117 route,
118 };
119
120 let root_markup = source.root().cast::<ast::Markup>().unwrap();
121 worker.check_root_scope(root_markup.to_untyped().children());
122 let first_scope = Arc::new(LazyHash::new(worker.summarize_scope()));
123 worker.route.insert(worker.fid, Some(first_scope.clone()));
124
125 worker.lexical = LexicalContext::default();
126 worker.comment_matcher.reset();
127 worker.buffer.clear();
128 worker.import_buffer.clear();
129 worker.module_items.clear();
130 let root = worker.check_in_mode(root_markup.to_untyped().children(), InterpretMode::Markup);
131 let exports = Arc::new(LazyHash::new(worker.summarize_scope()));
132
133 worker.collect_buffer();
134 let module_items = std::mem::take(&mut worker.module_items);
135
136 let info = ExprInfoRepr {
137 fid: source.id(),
138 revision,
139 source: source.clone(),
140 resolves: HashMap::from_iter(std::mem::take(resolves_base.lock().deref_mut())),
141 module_docstring,
142 docstrings: std::mem::take(docstrings_base.lock().deref_mut()),
143 imports: HashMap::from_iter(std::mem::take(imports_base.lock().deref_mut())),
144 exports,
145 exprs: std::mem::take(exprs_base.lock().deref_mut()),
146 root,
147 module_items,
148 };
149 crate::log_debug_ct!("expr_of end {:?}", source.id());
150
151 route.remove(&info.fid);
152 ExprInfo::new(info)
153}
154
155type ConcolicExpr = (Option<Expr>, Option<Ty>);
156type ResolveVec = Vec<(Span, Interned<RefExpr>)>;
157type SyntaxNodeChildren<'a> = std::slice::Iter<'a, SyntaxNode>;
158
159#[derive(Debug, Clone)]
160struct LexicalContext {
161 mode: InterpretMode,
162 scopes: EcoVec<ExprScope>,
163 last: ExprScope,
164}
165
166impl Default for LexicalContext {
167 fn default() -> Self {
168 LexicalContext {
169 mode: InterpretMode::Markup,
170 scopes: eco_vec![],
171 last: ExprScope::Lexical(RedBlackTreeMapSync::default()),
172 }
173 }
174}
175
176pub(crate) struct ExprWorker<'a> {
178 fid: TypstFileId,
179 source: Source,
180 ctx: Arc<SharedContext>,
181 imports: Arc<Mutex<FxHashMap<TypstFileId, Arc<LazyHash<LexicalScope>>>>>,
182 import_buffer: Vec<(TypstFileId, Arc<LazyHash<LexicalScope>>)>,
183 docstrings: Arc<Mutex<FxHashMap<DeclExpr, Arc<DocString>>>>,
184 exprs: Arc<Mutex<FxHashMap<Span, Expr>>>,
185 resolves: Arc<Mutex<ResolveVec>>,
186 buffer: ResolveVec,
187 lexical: LexicalContext,
188 module_items: FxHashMap<DeclExpr, ModuleItemLayout>,
189 init_stage: bool,
190
191 route: &'a mut ExprRoute,
192 comment_matcher: DocCommentMatcher,
193}
194
195impl ExprWorker<'_> {
196 fn with_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
197 self.lexical.scopes.push(std::mem::replace(
198 &mut self.lexical.last,
199 ExprScope::empty(),
200 ));
201 let len = self.lexical.scopes.len();
202 let result = f(self);
203 self.lexical.scopes.truncate(len);
204 self.lexical.last = self.lexical.scopes.pop().unwrap();
205 result
206 }
207
208 fn push_scope(&mut self, scope: ExprScope) {
209 let last = std::mem::replace(&mut self.lexical.last, scope);
210 if !last.is_empty() {
211 self.lexical.scopes.push(last);
212 }
213 }
214
215 #[must_use]
216 fn scope_mut(&mut self) -> &mut LexicalScope {
217 if matches!(self.lexical.last, ExprScope::Lexical(_)) {
218 return self.lexical_scope_unchecked();
219 }
220 self.lexical.scopes.push(std::mem::replace(
221 &mut self.lexical.last,
222 ExprScope::empty(),
223 ));
224 self.lexical_scope_unchecked()
225 }
226
227 fn lexical_scope_unchecked(&mut self) -> &mut LexicalScope {
228 let scope = &mut self.lexical.last;
229 if let ExprScope::Lexical(scope) = scope {
230 scope
231 } else {
232 unreachable!()
233 }
234 }
235
236 fn check_docstring(&mut self, decl: &DeclExpr, docs: Option<String>, kind: DefKind) {
237 if let Some(docs) = docs {
238 let docstring = self.ctx.compute_docstring(self.fid, docs, kind);
239 if let Some(docstring) = docstring {
240 self.docstrings.lock().insert(decl.clone(), docstring);
241 }
242 }
243 }
244
245 fn summarize_scope(&self) -> LexicalScope {
246 let mut exports = LexicalScope::default();
247 for scope in self
248 .lexical
249 .scopes
250 .iter()
251 .chain(std::iter::once(&self.lexical.last))
252 {
253 scope.merge_into(&mut exports);
254 }
255 exports
256 }
257
258 fn check(&mut self, m: ast::Expr) -> Expr {
259 let s = m.span();
260 let ret = self.do_check(m);
261 self.exprs.lock().insert(s, ret.clone());
262 ret
263 }
264
265 fn do_check(&mut self, m: ast::Expr) -> Expr {
266 use ast::Expr::*;
267 match m {
268 None(_) => Expr::Type(Ty::Builtin(BuiltinTy::None)),
269 Auto(..) => Expr::Type(Ty::Builtin(BuiltinTy::Auto)),
270 Bool(bool) => Expr::Type(Ty::Value(InsTy::new(Value::Bool(bool.get())))),
271 Int(int) => Expr::Type(Ty::Value(InsTy::new(Value::Int(int.get())))),
272 Float(float) => Expr::Type(Ty::Value(InsTy::new(Value::Float(float.get())))),
273 Numeric(numeric) => Expr::Type(Ty::Value(InsTy::new(Value::numeric(numeric.get())))),
274 Str(s) => Expr::Type(Ty::Value(InsTy::new(Value::Str(s.get().into())))),
275
276 Equation(equation) => self.check_math(equation.body().to_untyped().children()),
277 Math(math) => self.check_math(math.to_untyped().children()),
278 CodeBlock(code_block) => self.check_code(code_block.body()),
279 ContentBlock(content_block) => self.check_markup(content_block.body()),
280
281 Ident(ident) => self.check_ident(ident),
282 MathIdent(math_ident) => self.check_math_ident(math_ident),
283 Label(label) => self.check_label(label),
284 Ref(ref_node) => self.check_ref(ref_node),
285
286 LetBinding(let_binding) => self.check_let(let_binding),
287 Closure(closure) => self.check_closure(closure),
288 ModuleImport(module_import) => self.check_module_import(module_import),
289 ModuleInclude(module_include) => self.check_module_include(module_include),
290
291 Parenthesized(paren_expr) => self.check(paren_expr.expr()),
292 Array(array) => self.check_array(array),
293 Dict(dict) => self.check_dict(dict),
294 Unary(unary) => self.check_unary(unary),
295 Binary(binary) => self.check_binary(binary),
296 FieldAccess(field_access) => self.check_field_access(field_access),
297 FuncCall(func_call) => self.check_func_call(func_call),
298 DestructAssignment(destruct_assignment) => {
299 self.check_destruct_assign(destruct_assignment)
300 }
301 SetRule(set_rule) => self.check_set(set_rule),
302 ShowRule(show_rule) => self.check_show(show_rule),
303 Contextual(contextual) => {
304 Expr::Unary(UnInst::new(UnaryOp::Context, self.defer(contextual.body())))
305 }
306 Conditional(conditional) => self.check_conditional(conditional),
307 WhileLoop(while_loop) => self.check_while_loop(while_loop),
308 ForLoop(for_loop) => self.check_for_loop(for_loop),
309 LoopBreak(..) => Expr::Type(Ty::Builtin(BuiltinTy::Break)),
310 LoopContinue(..) => Expr::Type(Ty::Builtin(BuiltinTy::Continue)),
311 FuncReturn(func_return) => Expr::Unary(UnInst::new(
312 UnaryOp::Return,
313 func_return
314 .body()
315 .map_or_else(none_expr, |body| self.check(body)),
316 )),
317
318 Text(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
319 typst::text::TextElem,
320 >())))),
321 MathText(t) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some({
322 match t.get() {
323 MathTextKind::Grapheme(..) => Element::of::<typst::foundations::SymbolElem>(),
324 MathTextKind::Number(..) => Element::of::<typst::foundations::SymbolElem>(),
325 }
326 })))),
327 Raw(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
328 typst::text::RawElem,
329 >())))),
330 Link(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
331 typst::model::LinkElem,
332 >())))),
333 Space(..) => Expr::Type(Ty::Builtin(BuiltinTy::Space)),
334 Linebreak(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
335 LinebreakElem,
336 >())))),
337 Parbreak(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
338 ParbreakElem,
339 >())))),
340 Escape(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
341 typst::text::TextElem,
342 >())))),
343 Shorthand(..) => Expr::Type(Ty::Builtin(BuiltinTy::Type(Type::of::<
344 typst::foundations::Symbol,
345 >()))),
346 SmartQuote(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
347 typst::text::SmartQuoteElem,
348 >())))),
349
350 Strong(strong) => {
351 let body = self.check_inline_markup(strong.body());
352 self.check_element::<StrongElem>(eco_vec![body])
353 }
354 Emph(emph) => {
355 let body = self.check_inline_markup(emph.body());
356 self.check_element::<EmphElem>(eco_vec![body])
357 }
358 Heading(heading) => {
359 let body = self.check_markup(heading.body());
360 self.check_element::<HeadingElem>(eco_vec![body])
361 }
362 ListItem(item) => {
363 let body = self.check_markup(item.body());
364 self.check_element::<ListElem>(eco_vec![body])
365 }
366 EnumItem(item) => {
367 let body = self.check_markup(item.body());
368 self.check_element::<EnumElem>(eco_vec![body])
369 }
370 TermItem(item) => {
371 let term = self.check_markup(item.term());
372 let description = self.check_markup(item.description());
373 self.check_element::<TermsElem>(eco_vec![term, description])
374 }
375
376 MathAlignPoint(..) => Expr::Type(Ty::Builtin(BuiltinTy::Content(Some(Element::of::<
377 typst::math::AlignPointElem,
378 >(
379 ))))),
380 MathShorthand(..) => Expr::Type(Ty::Builtin(BuiltinTy::Type(Type::of::<
381 typst::foundations::Symbol,
382 >()))),
383 MathDelimited(math_delimited) => {
384 self.check_math(math_delimited.body().to_untyped().children())
385 }
386 MathFieldAccess(expr) => self.check_math_field_access(expr),
387 MathCall(expr) => self.check_math_call(expr),
388 MathAttach(attach) => {
389 let mut nodes = vec![attach.base().to_untyped().clone()];
390 if let Some(bottom) = attach.bottom() {
391 nodes.push(bottom.to_untyped().clone());
392 }
393 if let Some(top) = attach.top() {
394 nodes.push(top.to_untyped().clone());
395 }
396 self.check_math(nodes.iter())
397 }
398 MathPrimes(..) => Expr::Type(Ty::Builtin(BuiltinTy::None)),
399 MathFrac(frac) => {
400 let num = frac.num().to_untyped().clone();
401 let denom = frac.denom().to_untyped().clone();
402 self.check_math([num, denom].iter())
403 }
404 MathRoot(root) => self.check(root.radicand()),
405 }
406 }
407
408 fn check_element<T: NativeElement>(&mut self, content: EcoVec<Expr>) -> Expr {
409 let elem = Element::of::<T>();
410 Expr::Element(ElementExpr { elem, content }.into())
411 }
412
413 fn check_let(&mut self, typed: ast::LetBinding) -> Expr {
414 match typed.kind() {
415 ast::LetBindingKind::Closure(..) => {
416 typed.init().map_or_else(none_expr, |expr| self.check(expr))
417 }
418 ast::LetBindingKind::Normal(pat) => {
419 let docs = self.comment_matcher.collect();
420 let body = typed.init().map(|init| self.defer(init));
422
423 let span = pat.span();
424 let decl = Decl::pattern(span).into();
425 self.check_docstring(&decl, docs, DefKind::Variable);
426 let pattern = self.check_pattern(pat);
427 Expr::Let(Interned::new(LetExpr {
428 span,
429 pattern,
430 body,
431 }))
432 }
433 }
434 }
435
436 fn check_closure(&mut self, typed: ast::Closure) -> Expr {
437 let docs = self.comment_matcher.collect();
438 let decl = match typed.name() {
439 Some(name) => Decl::func(name).into(),
440 None => Decl::closure(typed.span()).into(),
441 };
442 self.check_docstring(&decl, docs, DefKind::Function);
443 self.resolve_as(Decl::as_def(&decl, None));
444
445 let (params, body) = self.with_scope(|this| {
446 this.scope_mut()
447 .insert_mut(decl.name().clone(), decl.clone().into());
448 let mut inputs = eco_vec![];
449 let mut names = eco_vec![];
450 let mut spread_left = None;
451 let mut spread_right = None;
452 for arg in typed.params().children() {
453 match arg {
454 ast::Param::Pos(arg) => {
455 inputs.push(this.check_pattern(arg));
456 }
457 ast::Param::Named(arg) => {
458 let key: DeclExpr = Decl::var(arg.name()).into();
459 let val = Pattern::Expr(this.check(arg.expr())).into();
460 names.push((key.clone(), val));
461
462 this.resolve_as(Decl::as_def(&key, None));
463 this.scope_mut().insert_mut(key.name().clone(), key.into());
464 }
465 ast::Param::Spread(s) => {
466 let decl: DeclExpr = if let Some(ident) = s.sink_ident() {
467 Decl::var(ident).into()
468 } else {
469 Decl::spread(s.span()).into()
470 };
471
472 let spread = Pattern::Expr(this.check(s.expr())).into();
473 if inputs.is_empty() {
474 spread_left = Some((decl.clone(), spread));
475 } else {
476 spread_right = Some((decl.clone(), spread));
477 }
478
479 this.resolve_as(Decl::as_def(&decl, None));
480 this.scope_mut()
481 .insert_mut(decl.name().clone(), decl.into());
482 }
483 }
484 }
485
486 if inputs.is_empty() {
487 spread_right = spread_left.take();
488 }
489
490 let pattern = PatternSig {
491 pos: inputs,
492 named: names,
493 spread_left,
494 spread_right,
495 };
496
497 (pattern, this.defer(typed.body()))
498 });
499
500 self.scope_mut()
501 .insert_mut(decl.name().clone(), decl.clone().into());
502 Expr::Func(FuncExpr { decl, params, body }.into())
503 }
504
505 fn check_pattern(&mut self, typed: ast::Pattern) -> Interned<Pattern> {
506 match typed {
507 ast::Pattern::Normal(expr) => self.check_pattern_expr(expr),
508 ast::Pattern::Placeholder(..) => Pattern::Expr(Expr::Star).into(),
509 ast::Pattern::Parenthesized(paren_expr) => self.check_pattern(paren_expr.pattern()),
510 ast::Pattern::Destructuring(destructing) => {
511 let mut inputs = eco_vec![];
512 let mut names = eco_vec![];
513 let mut spread_left = None;
514 let mut spread_right = None;
515
516 for item in destructing.items() {
517 match item {
518 ast::DestructuringItem::Pattern(pos) => {
519 inputs.push(self.check_pattern(pos));
520 }
521 ast::DestructuringItem::Named(named) => {
522 let key = Decl::var(named.name()).into();
523 let val = self.check_pattern(named.pattern());
524 names.push((key, val));
525 }
526 ast::DestructuringItem::Spread(spreading) => {
527 let decl: DeclExpr = if let Some(ident) = spreading.sink_ident() {
528 Decl::var(ident).into()
529 } else {
530 Decl::spread(spreading.span()).into()
531 };
532 let pattern = Pattern::Expr(Expr::Star).into();
533
534 if inputs.is_empty() {
535 spread_left = Some((decl.clone(), pattern));
536 } else {
537 spread_right = Some((decl.clone(), pattern));
538 }
539
540 self.resolve_as(Decl::as_def(&decl, None));
541 self.scope_mut()
542 .insert_mut(decl.name().clone(), decl.into());
543 }
544 }
545 }
546
547 if inputs.is_empty() {
548 spread_right = spread_left.take();
549 }
550
551 let pattern = PatternSig {
552 pos: inputs,
553 named: names,
554 spread_left,
555 spread_right,
556 };
557
558 Pattern::Sig(Box::new(pattern)).into()
559 }
560 }
561 }
562
563 fn check_pattern_expr(&mut self, typed: ast::Expr) -> Interned<Pattern> {
564 match typed {
565 ast::Expr::Ident(ident) => {
566 let decl = Decl::var(ident).into();
567 self.resolve_as(Decl::as_def(&decl, None));
568 self.scope_mut()
569 .insert_mut(decl.name().clone(), decl.clone().into());
570 Pattern::Simple(decl).into()
571 }
572 ast::Expr::Parenthesized(parenthesized) => self.check_pattern(parenthesized.pattern()),
573 _ => Pattern::Expr(self.check(typed)).into(),
574 }
575 }
576
577 fn check_module_import(&mut self, typed: ast::ModuleImport) -> Expr {
578 let is_wildcard_import = matches!(typed.imports(), Some(ast::Imports::Wildcard));
579
580 let source = typed.source();
581 let mod_expr = self.check_import(source, true, is_wildcard_import);
582 crate::log_debug_ct!("checking import: {source:?} => {mod_expr:?}");
583
584 let mod_var = typed.new_name().map(Decl::module_alias).or_else(|| {
585 typed.imports().is_none().then(|| {
586 let name = match mod_expr.as_ref()? {
587 Expr::Decl(decl) if matches!(decl.as_ref(), Decl::Module { .. }) => {
588 decl.name().clone()
589 }
590 _ => return None,
591 };
592 Some(Decl::path_stem(source.to_untyped().clone(), name))
594 })?
595 });
596
597 let creating_mod_var = mod_var.is_some();
598 let mod_var = Interned::new(mod_var.unwrap_or_else(|| Decl::module_import(typed.span())));
599
600 let mod_ref = RefExpr {
605 decl: mod_var.clone(),
606 step: mod_expr.clone(),
607 root: mod_expr.clone(),
608 term: None,
609 };
610 crate::log_debug_ct!("create import variable: {mod_ref:?}");
611 let mod_ref = Interned::new(mod_ref);
612 if creating_mod_var {
613 self.scope_mut()
614 .insert_mut(mod_var.name().clone(), Expr::Ref(mod_ref.clone()));
615 }
616
617 self.resolve_as(mod_ref.clone());
618
619 let fid = mod_expr.as_ref().and_then(|mod_expr| match mod_expr {
620 Expr::Type(Ty::Value(v)) => match &v.val {
621 Value::Module(m) => m.file_id(),
622 _ => None,
623 },
624 Expr::Decl(decl) => {
625 if matches!(decl.as_ref(), Decl::Module { .. }) {
626 decl.file_id()
627 } else {
628 None
629 }
630 }
631 _ => None,
632 });
633
634 if let Some(fid) = fid {
636 crate::log_debug_ct!("prefetch type check: {fid:?}");
637 self.ctx.prefetch_type_check(fid);
638 }
639
640 let scope = if let Some(fid) = &fid {
641 Some(ExprScope::Lexical(self.exports_of(*fid)))
642 } else {
643 match &mod_expr {
644 Some(Expr::Type(Ty::Value(v))) => match &v.val {
645 Value::Module(m) => Some(ExprScope::Module(m.clone())),
646 Value::Func(func) => {
647 if func.scope().is_some() {
648 Some(ExprScope::Func(func.clone()))
649 } else {
650 None
651 }
652 }
653 Value::Type(s) => Some(ExprScope::Type(*s)),
654 _ => None,
655 },
656 _ => None,
657 }
658 };
659
660 let scope = if let Some(scope) = scope {
661 scope
662 } else {
663 log::warn!(
664 "cannot analyze import on: {typed:?}, expr {mod_expr:?}, in file {:?}",
665 typed.span().id()
666 );
667 ExprScope::empty()
668 };
669
670 if let Some(imports) = typed.imports() {
671 match imports {
672 ast::Imports::Wildcard => {
673 crate::log_debug_ct!("checking wildcard: {mod_expr:?}");
674 self.push_scope(scope);
675 }
676 ast::Imports::Items(items) => {
677 let module = Expr::Decl(mod_var.clone());
678 self.import_decls(&scope, Some(mod_var.clone()), module, items);
679 }
680 }
681 };
682
683 Expr::Import(
684 ImportExpr {
685 source: self.check(source),
686 decl: mod_ref,
687 }
688 .into(),
689 )
690 }
691
692 fn check_import(
693 &mut self,
694 source: ast::Expr,
695 is_import: bool,
696 is_wildcard_import: bool,
697 ) -> Option<Expr> {
698 let src = self.eval_expr(source, InterpretMode::Code);
699 let src_expr = self.fold_expr_and_val(src).or_else(|| {
700 self.ctx
701 .analyze_expr(source.to_untyped())
702 .into_iter()
703 .find_map(|(v, _)| match v {
704 Value::Str(s) => Some(Expr::Type(Ty::Value(InsTy::new(Value::Str(s))))),
705 _ => None,
706 })
707 })?;
708
709 crate::log_debug_ct!("checking import source: {src_expr:?}");
710 let const_res = match &src_expr {
711 Expr::Type(Ty::Value(val)) => {
712 self.check_import_source_val(source, &val.val, Some(&src_expr), is_import)
713 }
714 Expr::Decl(decl) if matches!(decl.as_ref(), Decl::Module { .. }) => {
715 return Some(src_expr.clone());
716 }
717
718 _ => None,
719 };
720 const_res
721 .or_else(|| self.check_import_by_def(&src_expr))
722 .or_else(|| is_wildcard_import.then(|| self.check_import_dyn(source, &src_expr))?)
723 }
724
725 fn check_import_dyn(&mut self, source: ast::Expr, src_expr: &Expr) -> Option<Expr> {
726 let src_or_module = self.ctx.analyze_import(source.to_untyped());
727 crate::log_debug_ct!("checking import source dyn: {src_or_module:?}");
728
729 match src_or_module {
730 (_, Some(Value::Module(m))) => {
731 match m.file_id() {
733 Some(fid) => Some(Expr::Decl(
734 Decl::module_with_name(m.name().unwrap().into(), fid).into(),
735 )),
736 None => Some(Expr::Type(Ty::Value(InsTy::new(Value::Module(m))))),
737 }
738 }
739 (_, Some(v)) => Some(Expr::Type(Ty::Value(InsTy::new(v)))),
740 (Some(s), _) => self.check_import_source_val(source, &s, Some(src_expr), true),
741 (None, None) => None,
742 }
743 }
744
745 fn check_import_source_val(
746 &mut self,
747 source: ast::Expr,
748 src: &Value,
749 src_expr: Option<&Expr>,
750 is_import: bool,
751 ) -> Option<Expr> {
752 match &src {
753 _ if src.scope().is_some() => src_expr
754 .cloned()
755 .or_else(|| Some(Expr::Type(Ty::Value(InsTy::new(src.clone()))))),
756 Value::Str(s) => self.check_import_by_str(source, s.as_str(), is_import),
757 _ => None,
758 }
759 }
760
761 fn check_import_by_str(
762 &mut self,
763 source: ast::Expr,
764 src: &str,
765 is_import: bool,
766 ) -> Option<Expr> {
767 let fid = resolve_id_by_path(&self.ctx.world(), self.fid, src)?;
768 let name = Decl::calc_path_stem(src);
769 let module = Expr::Decl(Decl::module_with_name(name.clone(), fid).into());
770
771 let import_path = if is_import {
772 Decl::import_path(source.span(), name)
773 } else {
774 Decl::include_path(source.span(), name)
775 };
776
777 let ref_expr = RefExpr {
782 decl: import_path.into(),
783 step: Some(module.clone()),
784 root: Some(module.clone()),
785 term: None,
786 };
787 self.resolve_as(ref_expr.into());
788 Some(module)
789 }
790
791 fn check_import_by_def(&mut self, src_expr: &Expr) -> Option<Expr> {
792 match src_expr {
793 Expr::Decl(m) if matches!(m.kind(), DefKind::Module) => Some(src_expr.clone()),
794 Expr::Ref(r) => r.root.clone(),
795 _ => None,
796 }
797 }
798
799 fn import_decls(
800 &mut self,
801 scope: &ExprScope,
802 module_decl: Option<DeclExpr>,
803 module: Expr,
804 items: ast::ImportItems,
805 ) {
806 crate::log_debug_ct!("import scope {scope:?}");
807
808 for item in items.iter() {
809 let (path_ast, old, rename) = match item {
810 ast::ImportItem::Simple(path) => {
811 let old: DeclExpr = Decl::import(path.name()).into();
812 (path, old, None)
813 }
814 ast::ImportItem::Renamed(renamed) => {
815 let path = renamed.path();
816 let old: DeclExpr = Decl::import(path.name()).into();
817 let new: DeclExpr = Decl::import_alias(renamed.new_name()).into();
818 (path, old, Some(new))
819 }
820 };
821
822 let item_span = match item {
823 ast::ImportItem::Simple(path) => path.span(),
824 ast::ImportItem::Renamed(renamed) => renamed.span(),
825 };
826
827 if let Some(parent) = module_decl.as_ref() {
828 self.record_module_item(parent, &old, item_span);
829 if let Some(rename_decl) = &rename {
830 self.record_module_item(parent, rename_decl, item_span);
831 }
832 }
833
834 let mut path = Vec::with_capacity(1);
835 for seg in path_ast.iter() {
836 let seg = Interned::new(Decl::ident_ref(seg));
837 path.push(seg);
838 }
839 let (mut root, val) = match path.last().map(|decl| decl.name()) {
841 Some(name) => scope.get(name),
842 None => (None, None),
843 };
844
845 crate::log_debug_ct!("path {path:?} -> {root:?} {val:?}");
846 if root.is_none() && val.is_none() {
847 let mut sel = module.clone();
848 for seg in path.into_iter() {
849 sel = Expr::Select(SelectExpr::new(seg, sel));
850 }
851 root = Some(sel)
852 }
853
854 let (root, step) = extract_ref(root);
855
856 let mut ref_expr = Interned::new(RefExpr {
862 decl: old.clone(),
863 root,
864 step,
865 term: val,
866 });
867 self.resolve_as(ref_expr.clone());
868
869 if let Some(new) = &rename {
872 ref_expr = Interned::new(RefExpr {
877 decl: new.clone(),
878 root: ref_expr.root.clone(),
879 step: Some(ref_expr.decl.clone().into()),
880 term: ref_expr.term.clone(),
881 });
882 self.resolve_as(ref_expr.clone());
883 }
884
885 let name = rename.as_ref().unwrap_or(&old).name().clone();
887 let expr = Expr::Ref(ref_expr);
888 self.scope_mut().insert_mut(name, expr.clone());
889 }
890 }
891
892 fn record_module_item(&mut self, parent: &DeclExpr, child: &DeclExpr, span: Span) {
893 if self.init_stage || span.is_detached() || span.id() != Some(self.fid) {
894 return;
895 }
896 let Some(item_range) = source_range(&self.source, span) else {
897 return;
898 };
899 let Some(binding_range) = source_range(&self.source, child.span()) else {
900 return;
901 };
902 self.module_items.insert(
903 child.clone(),
904 ModuleItemLayout {
905 parent: parent.clone(),
906 item_range,
907 binding_range,
908 },
909 );
910 }
911
912 fn check_module_include(&mut self, typed: ast::ModuleInclude) -> Expr {
913 let _mod_expr = self.check_import(typed.source(), false, false);
914 let source = self.check(typed.source());
915 Expr::Include(IncludeExpr { source }.into())
916 }
917
918 fn check_array(&mut self, typed: ast::Array) -> Expr {
919 let mut items = vec![];
920 for item in typed.items() {
921 match item {
922 ast::ArrayItem::Pos(item) => {
923 items.push(ArgExpr::Pos(self.check(item)));
924 }
925 ast::ArrayItem::Spread(s) => {
926 items.push(ArgExpr::Spread(self.check(s.expr())));
927 }
928 }
929 }
930
931 Expr::Array(ArgsExpr::new(typed.span(), items))
932 }
933
934 fn check_dict(&mut self, typed: ast::Dict) -> Expr {
935 let mut items = vec![];
936 for item in typed.items() {
937 match item {
938 ast::DictItem::Named(item) => {
939 let key = Decl::ident_ref(item.name()).into();
940 let val = self.check(item.expr());
941 items.push(ArgExpr::Named(Box::new((key, val))));
942 }
943 ast::DictItem::Keyed(item) => {
944 let val = self.check(item.expr());
945 let key = item.key();
946 let analyzed = self
947 .const_eval_expr(key)
948 .and_then(|v| match v {
949 Value::Str(s) => Some(s),
950 _ => None,
951 })
952 .or_else(|| {
953 let (expr, term) = self.eval_expr(key, InterpretMode::Code);
954
955 fn const_string_from_ty(ty: &Ty) -> Option<Str> {
956 match ty {
957 Ty::Value(v) => match &v.val {
958 Value::Str(s) => Some(s.clone()),
959 _ => None,
960 },
961 _ => None,
962 }
963 }
964
965 term.as_ref()
966 .and_then(const_string_from_ty)
967 .or_else(|| match expr {
968 Some(Expr::Type(ty)) => const_string_from_ty(&ty),
969 _ => None,
970 })
971 });
972 let Some(analyzed) = analyzed else {
973 let key = self.check(key);
974 items.push(ArgExpr::NamedRt(Box::new((key, val))));
975 continue;
976 };
977 let key = Decl::str_name(key.to_untyped().clone(), analyzed.as_str()).into();
978 items.push(ArgExpr::Named(Box::new((key, val))));
979 }
980 ast::DictItem::Spread(s) => {
981 items.push(ArgExpr::Spread(self.check(s.expr())));
982 }
983 }
984 }
985
986 Expr::Dict(ArgsExpr::new(typed.span(), items))
987 }
988
989 fn check_args(&mut self, typed: ast::Args) -> Expr {
990 let mut args = vec![];
991 for arg in typed.items() {
992 self.check_arg(arg, &mut args);
993 }
994 Expr::Args(ArgsExpr::new(typed.span(), args))
995 }
996
997 fn check_math_args(&mut self, typed: ast::MathArgs) -> Expr {
998 let mut args = vec![];
999 for arg in typed.arg_items() {
1000 self.check_arg(arg.arg, &mut args);
1001 }
1002 Expr::Args(ArgsExpr::new(typed.span(), args))
1003 }
1004
1005 fn check_arg(&mut self, typed: ast::Arg, args: &mut Vec<ArgExpr>) {
1006 match typed {
1007 ast::Arg::Pos(arg) => {
1008 args.push(ArgExpr::Pos(self.check(arg)));
1009 }
1010 ast::Arg::Named(arg) => {
1011 let key = Decl::ident_ref(arg.name()).into();
1012 let val = self.check(arg.expr());
1013 args.push(ArgExpr::Named(Box::new((key, val))));
1014 }
1015 ast::Arg::Spread(s) => {
1016 args.push(ArgExpr::Spread(self.check(s.expr())));
1017 }
1018 }
1019 }
1020
1021 fn check_unary(&mut self, typed: ast::Unary) -> Expr {
1022 let op = match typed.op() {
1023 ast::UnOp::Pos => UnaryOp::Pos,
1024 ast::UnOp::Neg => UnaryOp::Neg,
1025 ast::UnOp::Not => UnaryOp::Not,
1026 };
1027 let lhs = self.check(typed.expr());
1028 Expr::Unary(UnInst::new(op, lhs))
1029 }
1030
1031 fn check_binary(&mut self, typed: ast::Binary) -> Expr {
1032 let lhs = self.check(typed.lhs());
1033 let rhs = self.check(typed.rhs());
1034 Expr::Binary(BinInst::new(typed.op(), lhs, rhs))
1035 }
1036
1037 fn check_destruct_assign(&mut self, typed: ast::DestructAssignment) -> Expr {
1038 let pat = Expr::Pattern(self.check_pattern(typed.pattern()));
1039 let val = self.check(typed.value());
1040 let inst = BinInst::new(ast::BinOp::Assign, pat, val);
1041 Expr::Binary(inst)
1042 }
1043
1044 fn check_field_access(&mut self, typed: ast::FieldAccess) -> Expr {
1045 let lhs = self.check(typed.target());
1046 let key = Decl::ident_ref(typed.field()).into();
1047 let span = typed.span();
1048 Expr::Select(SelectExpr { lhs, key, span }.into())
1049 }
1050
1051 fn check_math_access(&mut self, typed: ast::MathAccess) -> Expr {
1052 match typed {
1053 ast::MathAccess::MathIdent(ident) => self.check_math_ident(ident),
1054 ast::MathAccess::MathFieldAccess(access) => self.check_math_field_access(access),
1055 }
1056 }
1057
1058 fn check_math_field_access(&mut self, typed: ast::MathFieldAccess) -> Expr {
1059 let lhs = self.check_math_access(typed.target());
1060 let key = Decl::math_ident_ref(typed.field()).into();
1061 let span = typed.span();
1062 Expr::Select(SelectExpr { lhs, key, span }.into())
1063 }
1064
1065 fn check_func_call(&mut self, typed: ast::FuncCall) -> Expr {
1066 let callee = self.check(typed.callee());
1067 let args = self.check_args(typed.args());
1068 let span = typed.span();
1069 Expr::Apply(ApplyExpr { callee, args, span }.into())
1070 }
1071
1072 fn check_math_call(&mut self, typed: ast::MathCall) -> Expr {
1073 let callee = self.check_math_access(typed.callee());
1074 let args = self.check_math_args(typed.args());
1075 let span = typed.span();
1076 Expr::Apply(ApplyExpr { callee, args, span }.into())
1077 }
1078
1079 fn check_set(&mut self, typed: ast::SetRule) -> Expr {
1080 let target = self.check(typed.target());
1081 let args = self.check_args(typed.args());
1082 let cond = typed.condition().map(|cond| self.check(cond));
1083 Expr::Set(SetExpr { target, args, cond }.into())
1084 }
1085
1086 fn check_show(&mut self, typed: ast::ShowRule) -> Expr {
1087 let selector = typed.selector().map(|selector| self.check(selector));
1088 let edit = self.defer(typed.transform());
1089 Expr::Show(ShowExpr { selector, edit }.into())
1090 }
1091
1092 fn check_conditional(&mut self, typed: ast::Conditional) -> Expr {
1093 let cond = self.check(typed.condition());
1094 let then = self.defer(typed.if_body());
1095 let else_ = typed
1096 .else_body()
1097 .map_or_else(none_expr, |expr| self.defer(expr));
1098 Expr::Conditional(IfExpr { cond, then, else_ }.into())
1099 }
1100
1101 fn check_while_loop(&mut self, typed: ast::WhileLoop) -> Expr {
1102 let cond = self.check(typed.condition());
1103 let body = self.defer(typed.body());
1104 Expr::WhileLoop(WhileExpr { cond, body }.into())
1105 }
1106
1107 fn check_for_loop(&mut self, typed: ast::ForLoop) -> Expr {
1108 self.with_scope(|this| {
1109 let pattern = this.check_pattern(typed.pattern());
1110 let iter = this.check(typed.iterable());
1111 let body = this.defer(typed.body());
1112 Expr::ForLoop(
1113 ForExpr {
1114 pattern,
1115 iter,
1116 body,
1117 }
1118 .into(),
1119 )
1120 })
1121 }
1122
1123 fn check_inline_markup(&mut self, markup: ast::Markup) -> Expr {
1124 self.check_in_mode(markup.to_untyped().children(), InterpretMode::Markup)
1125 }
1126
1127 fn check_markup(&mut self, markup: ast::Markup) -> Expr {
1128 self.with_scope(|this| this.check_inline_markup(markup))
1129 }
1130
1131 fn check_code(&mut self, code: ast::Code) -> Expr {
1132 self.with_scope(|this| {
1133 this.check_in_mode(code.to_untyped().children(), InterpretMode::Code)
1134 })
1135 }
1136
1137 fn check_math(&mut self, children: SyntaxNodeChildren) -> Expr {
1138 self.check_in_mode(children, InterpretMode::Math)
1139 }
1140
1141 fn check_root_scope(&mut self, children: SyntaxNodeChildren) {
1142 self.init_stage = true;
1143 self.check_in_mode(children, InterpretMode::Markup);
1144 self.init_stage = false;
1145 }
1146
1147 fn check_in_mode(&mut self, children: SyntaxNodeChildren, mode: InterpretMode) -> Expr {
1148 let old_mode = self.lexical.mode;
1149 self.lexical.mode = mode;
1150
1151 self.comment_matcher.reset();
1153
1154 let mut items = Vec::with_capacity(4);
1155 for n in children {
1156 if let Some(expr) = n.cast::<ast::Expr>() {
1157 items.push(self.check(expr));
1158 self.comment_matcher.reset();
1159 continue;
1160 }
1161 if !self.init_stage && self.comment_matcher.process(n) {
1162 self.comment_matcher.reset();
1163 }
1164 }
1165
1166 self.lexical.mode = old_mode;
1167 Expr::Block(items.into())
1168 }
1169
1170 fn check_label(&mut self, label: ast::Label) -> Expr {
1171 let decl: Interned<Decl> = Decl::label(label.get(), label.span()).into();
1172
1173 self.resolve_as(
1174 RefExpr {
1175 decl: decl.clone(),
1176 step: None,
1177 root: None,
1178 term: None,
1179 }
1180 .into(),
1181 );
1182 Expr::Decl(decl)
1183 }
1184
1185 fn check_ref(&mut self, ref_node: ast::Ref) -> Expr {
1186 let ident = Interned::new(Decl::ref_(ref_node));
1187 let body = ref_node
1188 .supplement()
1189 .map(|block| self.check(ast::Expr::ContentBlock(block)));
1190 let ref_expr = ContentRefExpr {
1191 ident: ident.clone(),
1192 of: None,
1193 body,
1194 };
1195 self.resolve_as(
1196 RefExpr {
1197 decl: ident,
1198 step: None,
1199 root: None,
1200 term: None,
1201 }
1202 .into(),
1203 );
1204 Expr::ContentRef(ref_expr.into())
1205 }
1206
1207 fn check_ident(&mut self, ident: ast::Ident) -> Expr {
1208 self.resolve_ident(Decl::ident_ref(ident).into(), InterpretMode::Code)
1209 }
1210
1211 fn check_math_ident(&mut self, ident: ast::MathIdent) -> Expr {
1212 self.resolve_ident(Decl::math_ident_ref(ident).into(), InterpretMode::Math)
1213 }
1214
1215 fn resolve_as(&mut self, r: Interned<RefExpr>) {
1216 self.resolve_as_(r.decl.span(), r);
1217 }
1218
1219 fn resolve_as_(&mut self, s: Span, r: Interned<RefExpr>) {
1220 self.buffer.push((s, r.clone()));
1221 }
1222
1223 fn resolve_ident(&mut self, decl: DeclExpr, mode: InterpretMode) -> Expr {
1224 let r: Interned<RefExpr> = self.resolve_ident_(decl, mode).into();
1225 let s = r.decl.span();
1226 self.buffer.push((s, r.clone()));
1227 Expr::Ref(r)
1228 }
1229
1230 fn resolve_ident_(&mut self, decl: DeclExpr, mode: InterpretMode) -> RefExpr {
1262 let (step, val) = self.eval_ident(decl.name(), mode);
1263 let (root, step) = extract_ref(step);
1264
1265 RefExpr {
1266 decl,
1267 root,
1268 step,
1269 term: val,
1270 }
1271 }
1272
1273 fn defer(&mut self, expr: ast::Expr) -> Expr {
1274 if self.init_stage {
1275 Expr::Star
1276 } else {
1277 self.check(expr)
1278 }
1279 }
1280
1281 fn collect_buffer(&mut self) {
1282 let mut resolves = self.resolves.lock();
1283 resolves.extend(self.buffer.drain(..));
1284 drop(resolves);
1285 let mut imports = self.imports.lock();
1286 imports.extend(self.import_buffer.drain(..));
1287 }
1288
1289 fn const_eval_expr(&self, expr: ast::Expr) -> Option<Value> {
1290 SharedContext::const_eval(expr)
1291 }
1292
1293 fn eval_expr(&mut self, expr: ast::Expr, mode: InterpretMode) -> ConcolicExpr {
1294 if let Some(term) = self.const_eval_expr(expr) {
1295 return (None, Some(Ty::Value(InsTy::new(term))));
1296 }
1297 crate::log_debug_ct!("checking expr: {expr:?}");
1298
1299 match expr {
1300 ast::Expr::Parenthesized(paren) => self.eval_expr(paren.expr(), mode),
1301 ast::Expr::FieldAccess(field_access) => {
1302 let field = Decl::ident_ref(field_access.field());
1303
1304 let (expr, term) = self.eval_expr(field_access.target(), mode);
1305 let term = term.and_then(|v| {
1306 match v {
1309 Ty::Value(val) => {
1310 Some(Ty::Value(InsTy::new(val.val.field(field.name(), ()).ok()?)))
1311 }
1312 _ => None,
1313 }
1314 });
1315 let sel = expr.map(|expr| Expr::Select(SelectExpr::new(field.into(), expr)));
1316 (sel, term)
1317 }
1318 ast::Expr::Ident(ident) => {
1319 let expr_term = self.eval_ident(&ident.get().into(), mode);
1320 crate::log_debug_ct!("checking expr: {expr:?} -> res: {expr_term:?}");
1321 expr_term
1322 }
1323 _ => (None, None),
1324 }
1325 }
1326
1327 fn eval_ident(&self, name: &Interned<str>, mode: InterpretMode) -> ConcolicExpr {
1341 let res = self.lexical.last.get(name);
1342 if res.0.is_some() || res.1.is_some() {
1343 return res;
1344 }
1345
1346 for scope in self.lexical.scopes.iter().rev() {
1347 let res = scope.get(name);
1348 if res.0.is_some() || res.1.is_some() {
1349 return res;
1350 }
1351 }
1352
1353 let scope = match mode {
1354 InterpretMode::Math => self.ctx.world().library.math.scope(),
1355 InterpretMode::Markup | InterpretMode::Code => self.ctx.world().library.global.scope(),
1356 _ => return (None, None),
1357 };
1358
1359 let val = scope
1360 .get(name)
1361 .cloned()
1362 .map(|val| Ty::Value(InsTy::new(val.read().clone())));
1363 if let Some(val) = val {
1364 return (None, Some(val));
1365 }
1366
1367 if name.as_ref() == "std" {
1368 let val = Ty::Value(InsTy::new(self.ctx.world().library.std.read().clone()));
1369 return (None, Some(val));
1370 }
1371
1372 (None, None)
1373 }
1374
1375 fn fold_expr_and_val(&mut self, src: ConcolicExpr) -> Option<Expr> {
1376 crate::log_debug_ct!("folding cc: {src:?}");
1377 match src {
1378 (None, Some(val)) => Some(Expr::Type(val)),
1379 (expr, _) => self.fold_expr(expr),
1380 }
1381 }
1382
1383 fn fold_expr(&mut self, expr: Option<Expr>) -> Option<Expr> {
1384 crate::log_debug_ct!("folding cc: {expr:?}");
1385 match expr {
1386 Some(Expr::Decl(decl)) if !decl.is_def() => {
1387 crate::log_debug_ct!("folding decl: {decl:?}");
1388 let (x, y) = self.eval_ident(decl.name(), InterpretMode::Code);
1389 self.fold_expr_and_val((x, y))
1390 }
1391 Some(Expr::Ref(r)) => {
1392 crate::log_debug_ct!("folding ref: {r:?}");
1393 self.fold_expr_and_val((r.root.clone(), r.term.clone()))
1394 }
1395 Some(Expr::Select(r)) => {
1396 let lhs = self.fold_expr(Some(r.lhs.clone()));
1397 crate::log_debug_ct!("folding select: {r:?} ([{lhs:?}].[{:?}])", r.key);
1398 self.syntax_level_select(lhs?, &r.key, r.span)
1399 }
1400 Some(expr) => {
1401 crate::log_debug_ct!("folding expr: {expr:?}");
1402 Some(expr)
1403 }
1404 _ => None,
1405 }
1406 }
1407
1408 fn syntax_level_select(&mut self, lhs: Expr, key: &Interned<Decl>, span: Span) -> Option<Expr> {
1409 match &lhs {
1410 Expr::Decl(decl) => match decl.as_ref() {
1411 Decl::Module(module) => {
1412 let exports = self.exports_of(module.fid);
1413 let selected = exports.get(key.name())?;
1414
1415 let select_ref = Interned::new(RefExpr {
1416 decl: key.clone(),
1417 root: Some(lhs.clone()),
1418 step: Some(selected.clone()),
1419 term: None,
1420 });
1421 self.resolve_as(select_ref.clone());
1422 self.resolve_as_(span, select_ref);
1423 Some(selected.clone())
1424 }
1425 _ => None,
1426 },
1427 _ => None,
1428 }
1429 }
1430
1431 fn exports_of(&mut self, fid: TypstFileId) -> LexicalScope {
1432 let imported = self
1433 .ctx
1434 .source_by_id(fid)
1435 .ok()
1436 .and_then(|src| self.ctx.exports_of(&src, self.route))
1437 .unwrap_or_default();
1438 let res = imported.as_ref().deref().clone();
1439 self.import_buffer.push((fid, imported));
1440 res
1441 }
1442}
1443
1444fn extract_ref(step: Option<Expr>) -> (Option<Expr>, Option<Expr>) {
1456 match step {
1457 Some(Expr::Ref(r)) => (r.root.clone(), Some(r.decl.clone().into())),
1458 step => (step.clone(), step),
1459 }
1460}
1461
1462fn none_expr() -> Expr {
1463 Expr::Type(Ty::Builtin(BuiltinTy::None))
1464}
1465
1466#[cfg(test)]
1467mod tests {
1468 #[test]
1469 fn test_expr_size() {
1470 use super::*;
1471 assert!(size_of::<Expr>() <= size_of::<usize>() * 2);
1472 }
1473}