Skip to main content

graphix_compiler/expr/
resolver.rs

1use crate::{
2    expr::{
3        parser, read_to_arcstr, ApplyExpr, BindExpr, CouldNotResolve, Expr, ExprId,
4        ExprKind, LambdaExpr, ModPath, ModuleKind, Origin, Pattern, SelectExpr, Sig,
5        SigItem, SigKind, Source, StructExpr, StructWithExpr, StructurePattern,
6        TryCatchExpr, TypeDefExpr,
7    },
8    format_with_flags, PrintFlag,
9};
10use ahash::AHashMap;
11use anyhow::{anyhow, bail, Context, Result};
12use arcstr::ArcStr;
13use combine::stream::position::SourcePosition;
14use compact_str::format_compact;
15use futures::future::try_join_all;
16use indexmap::IndexSet;
17use log::info;
18use netidx::{
19    path::Path,
20    subscriber::{Event, Subscriber},
21    utils::Either,
22};
23use netidx_value::Value;
24use parking_lot::Mutex;
25use poolshark::local::LPooled;
26use std::{hash::Hash, path::PathBuf, pin::Pin, str::FromStr, time::Duration};
27use tokio::{join, task, time::Instant, try_join};
28use triomphe::Arc;
29
30pub type BufferOverrides = Arc<Mutex<AHashMap<PathBuf, ArcStr>>>;
31
32#[derive(Debug, Clone)]
33pub enum ModuleResolver {
34    VFS(AHashMap<Path, ArcStr>),
35    Files { base: PathBuf, overrides: Option<BufferOverrides> },
36    Netidx { subscriber: Subscriber, base: Path, timeout: Option<Duration> },
37}
38
39impl ModuleResolver {
40    pub fn parse_env(
41        subscriber: Subscriber,
42        timeout: Option<Duration>,
43        s: &str,
44    ) -> Result<Vec<Self>> {
45        let mut res = vec![];
46        for l in escaping::split(s, '\\', ',') {
47            let l = l.trim();
48            if let Some(s) = l.strip_prefix("netidx:") {
49                let base = Path::from_str(s);
50                let r = Self::Netidx { subscriber: subscriber.clone(), timeout, base };
51                res.push(r);
52            } else if let Some(s) = l.strip_prefix("file:") {
53                let base = PathBuf::from_str(s)?;
54                let r = Self::Files { base, overrides: None };
55                res.push(r);
56            } else {
57                bail!("expected netidx: or file:")
58            }
59        }
60        Ok(res)
61    }
62}
63
64enum Resolution {
65    Resolved { interface: Option<Origin>, implementation: Origin },
66    TryNextMethod,
67}
68
69fn resolve_from_vfs(
70    scope: &ModPath,
71    parent: &Arc<Origin>,
72    name: &Path,
73    vfs: &AHashMap<Path, ArcStr>,
74) -> Resolution {
75    macro_rules! ori {
76        ($s:expr) => {
77            Origin {
78                parent: Some(parent.clone()),
79                source: Source::Internal(name.clone().into()),
80                text: $s.clone(),
81            }
82        };
83    }
84    let scoped_intf = scope.append(&format_compact!("{name}.gxi"));
85    let scoped_impl = scope.append(&format_compact!("{name}.gx"));
86    let implementation = match vfs.get(&scoped_impl) {
87        Some(s) => ori!(s),
88        None => {
89            // try {name}/mod.gx fallback (consistent with file resolver)
90            let mod_impl = scope.append(&format_compact!("{name}/mod.gx"));
91            match vfs.get(&mod_impl) {
92                Some(s) => ori!(s),
93                None => return Resolution::TryNextMethod,
94            }
95        }
96    };
97    let interface = vfs
98        .get(&scoped_intf)
99        .or_else(|| {
100            let mod_intf = scope.append(&format_compact!("{name}/mod.gxi"));
101            vfs.get(&mod_intf)
102        })
103        .map(|s| ori!(s));
104    Resolution::Resolved { interface, implementation }
105}
106
107async fn resolve_from_files(
108    parent: &Arc<Origin>,
109    name: &Path,
110    base: &PathBuf,
111    overrides: Option<&BufferOverrides>,
112    errors: &mut Vec<anyhow::Error>,
113) -> Resolution {
114    macro_rules! ori {
115        ($s:expr, $path:expr) => {
116            Origin {
117                parent: Some(parent.clone()),
118                source: Source::File($path),
119                text: ArcStr::from($s),
120            }
121        };
122    }
123    async fn read(overrides: Option<&BufferOverrides>, path: &PathBuf) -> Result<ArcStr> {
124        match overrides.and_then(|o| o.lock().get(path).cloned()) {
125            Some(s) => Ok(s),
126            None => read_to_arcstr(path).await,
127        }
128    }
129    let mut impl_path = base.clone();
130    for part in Path::parts(&name) {
131        impl_path.push(part);
132    }
133    impl_path.set_extension("gx");
134    let mut intf_path = impl_path.with_extension("gxi");
135    let implementation = match read(overrides, &impl_path).await {
136        Ok(s) => ori!(s, impl_path),
137        Err(_) => {
138            impl_path.set_extension("");
139            impl_path.push("mod.gx");
140            intf_path.set_extension("");
141            intf_path.push("mod.gxi");
142            match read(overrides, &impl_path).await {
143                Ok(s) => ori!(s, impl_path.clone()),
144                Err(e) => {
145                    errors.push(anyhow::Error::from(e));
146                    return Resolution::TryNextMethod;
147                }
148            }
149        }
150    };
151    let interface = match read(overrides, &intf_path).await {
152        Ok(s) => Some(ori!(s, intf_path)),
153        Err(_) => None,
154    };
155    Resolution::Resolved { interface, implementation }
156}
157
158async fn resolve_from_netidx(
159    parent: &Arc<Origin>,
160    name: &Path,
161    subscriber: &Subscriber,
162    base: &Path,
163    timeout: &Option<Duration>,
164    errors: &mut Vec<anyhow::Error>,
165) -> Resolution {
166    macro_rules! ori {
167        ($v:expr, $p:expr) => {
168            match $v.last() {
169                Event::Update(Value::String(text)) => Origin {
170                    parent: Some(parent.clone()),
171                    source: Source::Netidx($p.clone()),
172                    text,
173                },
174                Event::Unsubscribed | Event::Update(_) => {
175                    errors.push(anyhow!("expected string"));
176                    return Resolution::TryNextMethod;
177                }
178            }
179        };
180    }
181    let impl_path = base.append(&format_compact!("{name}.gx"));
182    let intf_path = base.append(&format_compact!("{name}.gxi"));
183    let impl_sub = subscriber.subscribe_nondurable_one(impl_path.clone(), *timeout);
184    let intf_sub = subscriber.subscribe_nondurable_one(intf_path.clone(), *timeout);
185    let (impl_sub, intf_sub) = join!(impl_sub, intf_sub);
186    let implementation = match impl_sub {
187        Ok(v) => ori!(v, impl_path),
188        Err(e) => {
189            errors.push(e);
190            return Resolution::TryNextMethod;
191        }
192    };
193    let interface = match intf_sub {
194        Ok(v) => Some(ori!(v, intf_path)),
195        Err(_) => None,
196    };
197    Resolution::Resolved { interface, implementation }
198}
199
200// add modules that are only mentioned in the interface to the implementation
201// keep their relative location and order intact
202pub fn add_interface_modules(exprs: Arc<[Expr]>, sig: &Sig) -> Arc<[Expr]> {
203    #[derive(Clone, Copy)]
204    struct Item<'a> {
205        kind: ItemKind<'a>,
206        pos: SourcePosition,
207        ori: Option<&'a Arc<Origin>>,
208    }
209    #[derive(Clone, Copy)]
210    enum ItemKind<'a> {
211        Module(&'a ArcStr),
212        TypeDef(&'a TypeDefExpr),
213        Use(&'a ModPath),
214    }
215    impl<'a> PartialEq for Item<'a> {
216        fn eq(&self, other: &Self) -> bool {
217            match (&self.kind, &other.kind) {
218                (ItemKind::Module(a), ItemKind::Module(b)) => a == b,
219                (ItemKind::TypeDef(a), ItemKind::TypeDef(b)) => a.name == b.name,
220                (ItemKind::Use(a), ItemKind::Use(b)) => a == b,
221                (_, _) => false,
222            }
223        }
224    }
225    impl<'a> Eq for Item<'a> {}
226    impl<'a> Hash for Item<'a> {
227        fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
228            match &self.kind {
229                ItemKind::Module(m) => {
230                    0u8.hash(state);
231                    m.hash(state);
232                }
233                ItemKind::TypeDef(td) => {
234                    1u8.hash(state);
235                    td.name.hash(state);
236                }
237                ItemKind::Use(m) => {
238                    2u8.hash(state);
239                    m.hash(state);
240                }
241            }
242        }
243    }
244    impl<'a> Item<'a> {
245        fn synth(self) -> Expr {
246            let kind = match self.kind {
247                ItemKind::Module(name) => ExprKind::Module {
248                    name: name.clone(),
249                    value: ModuleKind::Unresolved { from_interface: true },
250                },
251                ItemKind::TypeDef(td) => ExprKind::TypeDef(td.clone()),
252                ItemKind::Use(m) => ExprKind::Use { name: m.clone() },
253            };
254            let ori = self.ori.cloned().unwrap_or_else(crate::expr::get_origin);
255            Expr { id: ExprId::new(), ori, pos: self.pos, kind }
256        }
257    }
258    let mut in_sig: LPooled<IndexSet<Item>> = LPooled::take();
259    let mut after_bind: LPooled<AHashMap<&ArcStr, Item>> = LPooled::take();
260    let mut after_td: LPooled<AHashMap<&ArcStr, Item>> = LPooled::take();
261    let mut after_mod: LPooled<AHashMap<&ArcStr, Item>> = LPooled::take();
262    let mut after_use: LPooled<AHashMap<&ModPath, Item>> = LPooled::take();
263    let mut first: Option<Item> = None;
264    let mut last: Option<&SigItem> = None;
265    macro_rules! push {
266        ($kind:ident, $name:expr, $si:expr) => {{
267            let name = Item {
268                kind: ItemKind::$kind($name),
269                pos: $si.pos,
270                ori: $si.ori.as_ref(),
271            };
272            in_sig.insert(name);
273            match last {
274                None => first = Some(name),
275                Some(si) => {
276                    match &si.kind {
277                        SigKind::Bind(v) => after_bind.insert(&v.name, name),
278                        SigKind::Module(m) => after_mod.insert(m, name),
279                        SigKind::TypeDef(td) => after_td.insert(&td.name, name),
280                        SigKind::Use(n) => after_use.insert(n, name),
281                    };
282                }
283            }
284        }};
285    }
286    for si in &*sig.items {
287        match &si.kind {
288            SigKind::Module(name) => push!(Module, name, si),
289            SigKind::TypeDef(td) => push!(TypeDef, td, si),
290            SigKind::Use(m) => push!(Use, m, si),
291            SigKind::Bind(_) => (),
292        }
293        last = Some(si);
294    }
295    for e in &*exprs {
296        if let ExprKind::Module { name, .. } = &e.kind {
297            let probe = Item {
298                kind: ItemKind::Module(name),
299                pos: SourcePosition::default(),
300                ori: None,
301            };
302            in_sig.shift_remove(&probe);
303        }
304        if let ExprKind::TypeDef(td) = &e.kind {
305            let probe = Item {
306                kind: ItemKind::TypeDef(td),
307                pos: SourcePosition::default(),
308                ori: None,
309            };
310            in_sig.shift_remove(&probe);
311        }
312        if let ExprKind::Use { name } = &e.kind {
313            let probe = Item {
314                kind: ItemKind::Use(name),
315                pos: SourcePosition::default(),
316                ori: None,
317            };
318            in_sig.shift_remove(&probe);
319        }
320    }
321    if in_sig.is_empty() {
322        drop(in_sig);
323        drop(after_bind);
324        drop(after_td);
325        drop(after_mod);
326        drop(after_use);
327        return exprs;
328    }
329    let mut res: LPooled<Vec<Expr>> = LPooled::take();
330    if let Some(name) = first.take() {
331        if in_sig.shift_remove(&name) {
332            res.push(name.synth());
333        }
334    }
335    let mut iter = exprs.iter();
336    loop {
337        match res.last().map(|e| &e.kind) {
338            Some(ExprKind::Bind(v)) => match &v.pattern {
339                StructurePattern::Bind(n) => {
340                    if let Some(name) = after_bind.remove(n)
341                        && in_sig.shift_remove(&name)
342                    {
343                        res.push(name.synth());
344                        continue;
345                    }
346                }
347                _ => (),
348            },
349            Some(ExprKind::TypeDef(td)) => {
350                if let Some(name) = after_td.remove(&td.name)
351                    && in_sig.shift_remove(&name)
352                {
353                    res.push(name.synth());
354                    continue;
355                }
356            }
357            Some(ExprKind::Module { name, .. }) => {
358                if let Some(name) = after_mod.remove(name)
359                    && in_sig.shift_remove(&name)
360                {
361                    res.push(name.synth());
362                    continue;
363                }
364            }
365            Some(ExprKind::Use { name }) => {
366                if let Some(name) = after_use.remove(name)
367                    && in_sig.shift_remove(&name)
368                {
369                    res.push(name.synth());
370                    continue;
371                }
372            }
373            _ => (),
374        };
375        match iter.next() {
376            None => break,
377            Some(e) => res.push(e.clone()),
378        }
379    }
380    for name in in_sig.drain(..) {
381        res.push(name.synth());
382    }
383    Arc::from_iter(res.drain(..))
384}
385
386async fn resolve(
387    scope: ModPath,
388    prepend: Option<Arc<ModuleResolver>>,
389    resolvers: Arc<[ModuleResolver]>,
390    id: ExprId,
391    parent: Arc<Origin>,
392    pos: SourcePosition,
393    name: ArcStr,
394    from_interface: bool,
395) -> Result<Expr> {
396    macro_rules! check {
397        ($res:expr) => {
398            match $res {
399                Resolution::TryNextMethod => continue,
400                Resolution::Resolved { interface, implementation } => {
401                    (interface, implementation)
402                }
403            }
404        };
405    }
406    let ts = Instant::now();
407    let name = Path::from(name);
408    let mut errors: LPooled<Vec<anyhow::Error>> = LPooled::take();
409    for r in prepend.iter().map(|r| r.as_ref()).chain(resolvers.iter()) {
410        let (interface, implementation) = match r {
411            ModuleResolver::VFS(vfs) => {
412                check!(resolve_from_vfs(&scope, &parent, &name, vfs))
413            }
414            ModuleResolver::Files { base, overrides } => {
415                check!(
416                    resolve_from_files(
417                        &parent,
418                        &name,
419                        base,
420                        overrides.as_ref(),
421                        &mut errors
422                    )
423                    .await
424                )
425            }
426            ModuleResolver::Netidx { subscriber, base, timeout } => {
427                let r = resolve_from_netidx(
428                    &parent,
429                    &name,
430                    subscriber,
431                    base,
432                    timeout,
433                    &mut errors,
434                )
435                .await;
436                check!(r)
437            }
438        };
439        let exprs = task::spawn_blocking({
440            let ori = implementation.clone();
441            move || parser::parse(ori)
442        });
443        let sig = match &interface {
444            None => None,
445            Some(ori) => {
446                let ori = ori.clone();
447                let sig = task::spawn_blocking(move || parser::parse_sig(ori))
448                    .await?
449                    .with_context(|| format!("parsing file {interface:?}"))?;
450                Some(sig)
451            }
452        };
453        let exprs =
454            exprs.await?.with_context(|| format!("parsing file {implementation:?}"))?;
455        let exprs = match &sig {
456            Some(sig) => add_interface_modules(exprs, &sig),
457            None => exprs,
458        };
459        let value = ModuleKind::Resolved { exprs, sig, from_interface };
460        let kind = ExprKind::Module { name: name.clone().into(), value };
461        format_with_flags(PrintFlag::NoSource | PrintFlag::NoParents, || {
462            info!(
463                "load and parse {implementation:?} and {interface:?} {:?}",
464                ts.elapsed()
465            )
466        });
467        let _ = implementation; // implementation lives on the inner exprs
468        return Ok(Expr { id, ori: parent, pos, kind });
469    }
470    let mut msg = format_compact!("module {name} could not be found");
471    use std::fmt::Write as _;
472    let mut first = true;
473    for e in errors.iter() {
474        let _ = write!(&mut msg, "{}{e}", if first { ": " } else { "; " });
475        first = false;
476    }
477    bail!("{msg}")
478}
479
480impl Expr {
481    pub fn has_unresolved_modules(&self) -> bool {
482        self.fold(false, &mut |acc, e| {
483            acc || match &e.kind {
484                ExprKind::Module { value: ModuleKind::Unresolved { .. }, .. } => true,
485                _ => false,
486            }
487        })
488    }
489
490    /// Resolve external modules referenced in the expression using
491    /// the resolvers list. Each resolver will be tried in order,
492    /// until one succeeds. If no resolver succeeds then an error will
493    /// be returned.
494    pub async fn resolve_modules<'a>(
495        &'a self,
496        resolvers: &'a Arc<[ModuleResolver]>,
497    ) -> Result<Expr> {
498        self.resolve_modules_in_scope(&ModPath::root(), resolvers).await
499    }
500
501    /// Like `resolve_modules` but starts at a non-root scope. Used by
502    /// the runtime when typechecking a graphix package crate's source
503    /// under that crate's namespace.
504    pub async fn resolve_modules_in_scope<'a>(
505        &'a self,
506        scope: &'a ModPath,
507        resolvers: &'a Arc<[ModuleResolver]>,
508    ) -> Result<Expr> {
509        self.resolve_modules_int(scope, &None, resolvers).await
510    }
511
512    async fn resolve_modules_int<'a>(
513        &'a self,
514        scope: &ModPath,
515        prepend: &'a Option<Arc<ModuleResolver>>,
516        resolvers: &'a Arc<[ModuleResolver]>,
517    ) -> Result<Expr> {
518        if self.has_unresolved_modules() {
519            self.resolve_modules_inner(scope, prepend, resolvers).await
520        } else {
521            Ok(self.clone())
522        }
523    }
524
525    fn resolve_modules_inner<'a>(
526        &'a self,
527        scope: &'a ModPath,
528        prepend: &'a Option<Arc<ModuleResolver>>,
529        resolvers: &'a Arc<[ModuleResolver]>,
530    ) -> Pin<Box<dyn Future<Output = Result<Expr>> + Send + Sync + 'a>> {
531        macro_rules! subexprs {
532            ($args:expr) => {{
533                try_join_all($args.iter().map(|e| async {
534                    e.resolve_modules_int(scope, prepend, resolvers).await
535                }))
536                .await?
537            }};
538        }
539        macro_rules! subtuples {
540            ($args:expr) => {{
541                try_join_all($args.iter().map(|(k, e)| async {
542                    Ok::<_, anyhow::Error>((
543                        k.clone(),
544                        e.resolve_modules_int(scope, prepend, resolvers).await?,
545                    ))
546                }))
547                .await?
548            }};
549        }
550        macro_rules! expr {
551            ($kind:expr) => {
552                Ok(Expr {
553                    id: self.id,
554                    ori: self.ori.clone(),
555                    pos: self.pos,
556                    kind: $kind,
557                })
558            };
559        }
560        macro_rules! only_args {
561            ($kind:ident, $args:expr) => {
562                Box::pin(async move {
563                    let args = Arc::from(subexprs!($args));
564                    expr!(ExprKind::$kind { args })
565                })
566            };
567        }
568        macro_rules! bin_op {
569            ($kind:ident, $lhs:expr, $rhs:expr) => {
570                Box::pin(async move {
571                    let (lhs, rhs) = try_join!(
572                        $lhs.resolve_modules_int(scope, prepend, resolvers),
573                        $rhs.resolve_modules_int(scope, prepend, resolvers)
574                    )?;
575                    expr!(ExprKind::$kind { lhs: Arc::from(lhs), rhs: Arc::from(rhs) })
576                })
577            };
578        }
579        if !self.has_unresolved_modules() {
580            return Box::pin(async { Ok(self.clone()) });
581        }
582        match self.kind.clone() {
583            ExprKind::Constant(_)
584            | ExprKind::NoOp
585            | ExprKind::Use { .. }
586            | ExprKind::Ref { .. }
587            | ExprKind::StructRef { .. }
588            | ExprKind::TupleRef { .. }
589            | ExprKind::TypeDef { .. } => Box::pin(async move { Ok(self.clone()) }),
590            ExprKind::Module {
591                value: ModuleKind::Unresolved { from_interface },
592                name,
593            } => {
594                let (id, pos, prepend, resolvers) =
595                    (self.id, self.pos, prepend.clone(), Arc::clone(resolvers));
596                Box::pin(async move {
597                    let e = resolve(
598                        scope.clone(),
599                        prepend.clone(),
600                        resolvers.clone(),
601                        id,
602                        self.ori.clone(),
603                        pos,
604                        name.clone(),
605                        from_interface,
606                    )
607                    .await
608                    .with_context(|| CouldNotResolve(name.clone()))?;
609                    let scope = ModPath(scope.append(&*name));
610                    e.resolve_modules_int(&scope, &prepend, &resolvers).await
611                })
612            }
613            ExprKind::Module {
614                value: ModuleKind::Resolved { exprs, sig, from_interface },
615                name,
616            } => Box::pin(async move {
617                // The prepend resolver supplies a base for resolving
618                // *this module's* sub-modules. The right base is the
619                // implementation's sub-module directory, not the
620                // parent's directory: for `foo.gx` (pattern 1) that's
621                // `<dir>/foo/`; for `foo/mod.gx` (pattern 2) it's just
622                // `<dir>/`. We dig the implementation file's path out
623                // of the body — the body's exprs carry the impl file
624                // as their ori, while `self.ori` only points at the
625                // file where `mod foo;` was written.
626                let impl_path: Option<&std::path::Path> =
627                    exprs.iter().find_map(|e| match &e.ori.source {
628                        Source::File(p) => Some(p.as_path()),
629                        _ => None,
630                    });
631                let prepend = match impl_path {
632                    Some(p) => {
633                        let parent = match p.parent() {
634                            Some(par) => par,
635                            None => return Ok(self.clone()),
636                        };
637                        let dir = match p.file_stem().and_then(|s| s.to_str()) {
638                            Some("mod") => parent.to_path_buf(),
639                            Some(stem) => parent.join(stem),
640                            None => parent.to_path_buf(),
641                        };
642                        let overrides = resolvers.iter().find_map(|m| match m {
643                            ModuleResolver::Files { overrides: Some(o), .. } => {
644                                Some(o.clone())
645                            }
646                            _ => None,
647                        });
648                        Some(Arc::new(ModuleResolver::Files { base: dir, overrides }))
649                    }
650                    None => match &self.ori.source {
651                        Source::Unspecified | Source::Internal(_) => None,
652                        Source::File(p) => p.parent().map(|p| {
653                            let overrides = resolvers.iter().find_map(|m| match m {
654                                ModuleResolver::Files { overrides: Some(o), .. } => {
655                                    Some(o.clone())
656                                }
657                                _ => None,
658                            });
659                            Arc::new(ModuleResolver::Files { base: p.into(), overrides })
660                        }),
661                        Source::Netidx(p) => resolvers.iter().find_map(|m| match m {
662                            ModuleResolver::Netidx { subscriber, timeout, .. } => {
663                                Some(Arc::new(ModuleResolver::Netidx {
664                                    subscriber: subscriber.clone(),
665                                    base: p.clone(),
666                                    timeout: *timeout,
667                                }))
668                            }
669                            ModuleResolver::Files { .. } | ModuleResolver::VFS(_) => None,
670                        }),
671                    },
672                };
673                let exprs = try_join_all(exprs.iter().map(|e| async {
674                    e.resolve_modules_int(&scope, &prepend, resolvers).await
675                }))
676                .await?;
677                expr!(ExprKind::Module {
678                    value: ModuleKind::Resolved {
679                        exprs: Arc::from(exprs),
680                        sig,
681                        from_interface
682                    },
683                    name,
684                })
685            }),
686            ExprKind::Module {
687                name,
688                value: ModuleKind::Dynamic { sandbox, sig, source },
689            } => Box::pin(async move {
690                let source = Arc::new(
691                    source.resolve_modules_int(scope, prepend, resolvers).await?,
692                );
693                expr!(ExprKind::Module {
694                    name,
695                    value: ModuleKind::Dynamic { sandbox, sig, source },
696                })
697            }),
698            ExprKind::ExplicitParens(e) => Box::pin(async move {
699                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
700                expr!(ExprKind::ExplicitParens(Arc::new(e)))
701            }),
702            ExprKind::Do { exprs } => Box::pin(async move {
703                let exprs = Arc::from(subexprs!(exprs));
704                expr!(ExprKind::Do { exprs })
705            }),
706            ExprKind::Bind(b) => Box::pin(async move {
707                let BindExpr { rec, pattern, typ, value } = &*b;
708                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
709                expr!(ExprKind::Bind(Arc::new(BindExpr {
710                    rec: *rec,
711                    pattern: pattern.clone(),
712                    typ: typ.clone(),
713                    value,
714                })))
715            }),
716            ExprKind::StructWith(StructWithExpr { source, replace }) => {
717                Box::pin(async move {
718                    expr!(ExprKind::StructWith(StructWithExpr {
719                        source: Arc::new(
720                            source.resolve_modules_int(scope, prepend, resolvers).await?,
721                        ),
722                        replace: Arc::from(subtuples!(replace)),
723                    }))
724                })
725            }
726            ExprKind::Connect { name, value, deref } => Box::pin(async move {
727                let value = value.resolve_modules_int(scope, prepend, resolvers).await?;
728                expr!(ExprKind::Connect { name, value: Arc::new(value), deref })
729            }),
730            ExprKind::Lambda(l) => Box::pin(async move {
731                let LambdaExpr { args, vargs, rtype, constraints, throws, body } = &*l;
732                let body = match body {
733                    Either::Right(s) => Either::Right(s.clone()),
734                    Either::Left(e) => Either::Left(
735                        e.resolve_modules_int(scope, prepend, resolvers).await?,
736                    ),
737                };
738                let l = LambdaExpr {
739                    args: args.clone(),
740                    vargs: vargs.clone(),
741                    rtype: rtype.clone(),
742                    throws: throws.clone(),
743                    constraints: constraints.clone(),
744                    body,
745                };
746                expr!(ExprKind::Lambda(Arc::new(l)))
747            }),
748            ExprKind::TypeCast { expr, typ } => Box::pin(async move {
749                let expr = expr.resolve_modules_int(scope, prepend, resolvers).await?;
750                expr!(ExprKind::TypeCast { expr: Arc::new(expr), typ })
751            }),
752            ExprKind::Apply(ApplyExpr { args, function }) => Box::pin(async move {
753                expr!(ExprKind::Apply(ApplyExpr {
754                    args: Arc::from(subtuples!(args)),
755                    function
756                }))
757            }),
758            ExprKind::Any { args } => only_args!(Any, args),
759            ExprKind::Array { args } => only_args!(Array, args),
760            ExprKind::Map { args } => Box::pin(async move {
761                let args = Arc::from(subtuples!(args));
762                expr!(ExprKind::Map { args })
763            }),
764            ExprKind::MapRef { source, key } => Box::pin(async move {
765                let source = Arc::new(
766                    source.resolve_modules_int(scope, prepend, resolvers).await?,
767                );
768                let key =
769                    Arc::new(key.resolve_modules_inner(scope, prepend, resolvers).await?);
770                expr!(ExprKind::MapRef { source, key })
771            }),
772            ExprKind::Tuple { args } => only_args!(Tuple, args),
773            ExprKind::StringInterpolate { args } => only_args!(StringInterpolate, args),
774            ExprKind::Struct(StructExpr { args }) => Box::pin(async move {
775                let args = Arc::from(subtuples!(args));
776                expr!(ExprKind::Struct(StructExpr { args }))
777            }),
778            ExprKind::ArrayRef { source, i } => Box::pin(async move {
779                let source = Arc::new(
780                    source.resolve_modules_int(scope, prepend, resolvers).await?,
781                );
782                let i = Arc::new(i.resolve_modules_int(scope, prepend, resolvers).await?);
783                expr!(ExprKind::ArrayRef { source, i })
784            }),
785            ExprKind::ArraySlice { source, start, end } => Box::pin(async move {
786                let source = Arc::new(
787                    source.resolve_modules_int(scope, prepend, resolvers).await?,
788                );
789                let start = match start {
790                    None => None,
791                    Some(e) => Some(Arc::new(
792                        e.resolve_modules_int(scope, prepend, resolvers).await?,
793                    )),
794                };
795                let end = match end {
796                    None => None,
797                    Some(e) => Some(Arc::new(
798                        e.resolve_modules_int(scope, prepend, resolvers).await?,
799                    )),
800                };
801                expr!(ExprKind::ArraySlice { source, start, end })
802            }),
803            ExprKind::Variant { tag, args } => Box::pin(async move {
804                let args = Arc::from(subexprs!(args));
805                expr!(ExprKind::Variant { tag, args })
806            }),
807            ExprKind::Select(SelectExpr { arg, arms }) => Box::pin(async move {
808                let arg =
809                    Arc::new(arg.resolve_modules_int(scope, prepend, resolvers).await?);
810                let arms = try_join_all(arms.iter().map(|(p, e)| async {
811                    let p = match &p.guard {
812                        None => p.clone(),
813                        Some(e) => {
814                            let e =
815                                e.resolve_modules_int(scope, prepend, resolvers).await?;
816                            Pattern {
817                                guard: Some(e),
818                                type_predicate: p.type_predicate.clone(),
819                                structure_predicate: p.structure_predicate.clone(),
820                            }
821                        }
822                    };
823                    let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
824                    Ok::<_, anyhow::Error>((p, e))
825                }))
826                .await?;
827                expr!(ExprKind::Select(SelectExpr { arg, arms: Arc::from(arms) }))
828            }),
829            ExprKind::Qop(e) => Box::pin(async move {
830                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
831                expr!(ExprKind::Qop(Arc::new(e)))
832            }),
833            ExprKind::OrNever(e) => Box::pin(async move {
834                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
835                expr!(ExprKind::OrNever(Arc::new(e)))
836            }),
837            ExprKind::TryCatch(tc) => Box::pin(async move {
838                let exprs = try_join_all(tc.exprs.iter().map(|e| async {
839                    e.resolve_modules_int(&scope, &prepend, resolvers).await
840                }))
841                .await?;
842                let handler =
843                    tc.handler.resolve_modules_int(scope, prepend, resolvers).await?;
844                expr!(ExprKind::TryCatch(Arc::new(TryCatchExpr {
845                    bind: tc.bind.clone(),
846                    constraint: tc.constraint.clone(),
847                    handler: Arc::new(handler),
848                    exprs: Arc::from_iter(exprs),
849                })))
850            }),
851            ExprKind::ByRef(e) => Box::pin(async move {
852                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
853                expr!(ExprKind::ByRef(Arc::new(e)))
854            }),
855            ExprKind::Deref(e) => Box::pin(async move {
856                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
857                expr!(ExprKind::Deref(Arc::new(e)))
858            }),
859            ExprKind::Not { expr: e } => Box::pin(async move {
860                let e = e.resolve_modules_int(scope, prepend, resolvers).await?;
861                expr!(ExprKind::Not { expr: Arc::new(e) })
862            }),
863            ExprKind::Add { lhs, rhs } => bin_op!(Add, lhs, rhs),
864            ExprKind::CheckedAdd { lhs, rhs } => bin_op!(CheckedAdd, lhs, rhs),
865            ExprKind::Sub { lhs, rhs } => bin_op!(Sub, lhs, rhs),
866            ExprKind::CheckedSub { lhs, rhs } => bin_op!(CheckedSub, lhs, rhs),
867            ExprKind::Mul { lhs, rhs } => bin_op!(Mul, lhs, rhs),
868            ExprKind::CheckedMul { lhs, rhs } => bin_op!(CheckedMul, lhs, rhs),
869            ExprKind::Div { lhs, rhs } => bin_op!(Div, lhs, rhs),
870            ExprKind::CheckedDiv { lhs, rhs } => bin_op!(CheckedDiv, lhs, rhs),
871            ExprKind::Mod { lhs, rhs } => bin_op!(Mod, lhs, rhs),
872            ExprKind::CheckedMod { lhs, rhs } => bin_op!(CheckedMod, lhs, rhs),
873            ExprKind::And { lhs, rhs } => bin_op!(And, lhs, rhs),
874            ExprKind::Or { lhs, rhs } => bin_op!(Or, lhs, rhs),
875            ExprKind::Eq { lhs, rhs } => bin_op!(Eq, lhs, rhs),
876            ExprKind::Ne { lhs, rhs } => bin_op!(Ne, lhs, rhs),
877            ExprKind::Gt { lhs, rhs } => bin_op!(Gt, lhs, rhs),
878            ExprKind::Lt { lhs, rhs } => bin_op!(Lt, lhs, rhs),
879            ExprKind::Gte { lhs, rhs } => bin_op!(Gte, lhs, rhs),
880            ExprKind::Lte { lhs, rhs } => bin_op!(Lte, lhs, rhs),
881            ExprKind::Sample { lhs, rhs } => bin_op!(Sample, lhs, rhs),
882        }
883    }
884}