Skip to main content

rib/
expr_arena.rs

1use la_arena::{Arena, Idx};
2use std::collections::HashMap;
3use std::fmt;
4
5use crate::call_type::{CallType, InstanceCreationType, InstanceIdentifier};
6use crate::expr::{ArmPattern, Expr, MatchArm, Number, Range};
7use crate::parser::type_name::TypeName;
8use crate::rib_source_span::SourceSpan;
9use crate::{InferredType, VariableId};
10
11// ---------------------------------------------------------------------------
12// Index types
13// ---------------------------------------------------------------------------
14
15/// Stable index into [`ExprArena`] identifying a single expression node.
16pub type ExprId = Idx<ExprNode>;
17
18/// Stable index into the arm-pattern arena.
19pub type ArmPatternId = Idx<ArmPatternNode>;
20
21// ---------------------------------------------------------------------------
22// Structural node — no InferredType, children are IDs
23// ---------------------------------------------------------------------------
24
25/// A single expression node stripped of its inferred type.
26/// Child expressions are referenced by [`ExprId`] rather than owned.
27#[derive(Debug, Clone)]
28pub struct ExprNode {
29    pub kind: ExprKind,
30    pub source_span: SourceSpan,
31    pub type_annotation: Option<TypeName>,
32}
33
34/// The shape of an expression node.  
35/// This mirrors [`Expr`] exactly, replacing every `Box<Expr>` / `Vec<Expr>`
36/// with `ExprId` / `Vec<ExprId>` and every `ArmPattern` with `ArmPatternId`.
37#[derive(Debug, Clone)]
38pub enum ExprKind {
39    Let {
40        variable_id: VariableId,
41        expr: ExprId,
42    },
43    SelectField {
44        expr: ExprId,
45        field: String,
46    },
47    SelectIndex {
48        expr: ExprId,
49        index: ExprId,
50    },
51    Sequence {
52        exprs: Vec<ExprId>,
53    },
54    Range {
55        range: RangeKind,
56    },
57    Record {
58        fields: Vec<(String, ExprId)>,
59    },
60    Tuple {
61        exprs: Vec<ExprId>,
62    },
63    Literal {
64        value: String,
65    },
66    Number {
67        number: Number,
68    },
69    Flags {
70        flags: Vec<String>,
71    },
72    Identifier {
73        variable_id: VariableId,
74    },
75    Boolean {
76        value: bool,
77    },
78    Concat {
79        exprs: Vec<ExprId>,
80    },
81    ExprBlock {
82        exprs: Vec<ExprId>,
83    },
84    Not {
85        expr: ExprId,
86    },
87    GreaterThan {
88        lhs: ExprId,
89        rhs: ExprId,
90    },
91    GreaterThanOrEqualTo {
92        lhs: ExprId,
93        rhs: ExprId,
94    },
95    LessThanOrEqualTo {
96        lhs: ExprId,
97        rhs: ExprId,
98    },
99    EqualTo {
100        lhs: ExprId,
101        rhs: ExprId,
102    },
103    LessThan {
104        lhs: ExprId,
105        rhs: ExprId,
106    },
107    And {
108        lhs: ExprId,
109        rhs: ExprId,
110    },
111    Or {
112        lhs: ExprId,
113        rhs: ExprId,
114    },
115    Plus {
116        lhs: ExprId,
117        rhs: ExprId,
118    },
119    Minus {
120        lhs: ExprId,
121        rhs: ExprId,
122    },
123    Multiply {
124        lhs: ExprId,
125        rhs: ExprId,
126    },
127    Divide {
128        lhs: ExprId,
129        rhs: ExprId,
130    },
131    Cond {
132        cond: ExprId,
133        lhs: ExprId,
134        rhs: ExprId,
135    },
136    PatternMatch {
137        predicate: ExprId,
138        match_arms: Vec<MatchArmNode>,
139    },
140    Option {
141        expr: Option<ExprId>,
142    },
143    Result {
144        expr: ResultExprKind,
145    },
146    Call {
147        call_type: CallTypeNode,
148        args: Vec<ExprId>,
149    },
150    InvokeMethodLazy {
151        lhs: ExprId,
152        method: String,
153        args: Vec<ExprId>,
154    },
155    Unwrap {
156        expr: ExprId,
157    },
158    Throw {
159        message: String,
160    },
161    GetTag {
162        expr: ExprId,
163    },
164    ListComprehension {
165        iterated_variable: VariableId,
166        iterable_expr: ExprId,
167        yield_expr: ExprId,
168    },
169    ListReduce {
170        reduce_variable: VariableId,
171        iterated_variable: VariableId,
172        iterable_expr: ExprId,
173        init_value_expr: ExprId,
174        yield_expr: ExprId,
175    },
176    Length {
177        expr: ExprId,
178    },
179    GenerateWorkerName {
180        variable_id: Option<VariableId>,
181    },
182}
183
184/// Arena-friendly version of [`Range`].
185#[derive(Debug, Clone)]
186pub enum RangeKind {
187    Range { from: ExprId, to: ExprId },
188    RangeInclusive { from: ExprId, to: ExprId },
189    RangeFrom { from: ExprId },
190}
191
192/// Arena-friendly version of `Result<Box<Expr>, Box<Expr>>` in [`Expr::Result`].
193#[derive(Debug, Clone)]
194pub enum ResultExprKind {
195    Ok(ExprId),
196    Err(ExprId),
197}
198
199/// Arena-friendly version of [`CallType`].
200/// [`InstanceIdentifier`] embeds `Option<Box<Expr>>` for the worker name;
201/// we replace that with `Option<ExprId>`.
202#[derive(Debug, Clone)]
203pub enum CallTypeNode {
204    Function {
205        component_info: Option<crate::ComponentDependencyKey>,
206        instance_identifier: Option<InstanceIdentifierNode>,
207        function_name: crate::DynamicParsedFunctionName,
208    },
209    VariantConstructor(String),
210    EnumConstructor(String),
211    InstanceCreation(InstanceCreationNode),
212}
213
214impl CallTypeNode {
215    /// Same notion as [`crate::CallType::is_resource_method`], without lowering to [`crate::CallType`].
216    pub fn is_resource_method(&self) -> bool {
217        match self {
218            CallTypeNode::Function { function_name, .. } => function_name
219                .to_parsed_function_name()
220                .function
221                .resource_method_name()
222                .is_some(),
223            _ => false,
224        }
225    }
226}
227
228impl fmt::Display for CallTypeNode {
229    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230        match self {
231            CallTypeNode::Function { function_name, .. } => write!(f, "{function_name}"),
232            CallTypeNode::VariantConstructor(name) => write!(f, "{name}"),
233            CallTypeNode::EnumConstructor(name) => write!(f, "{name}"),
234            CallTypeNode::InstanceCreation(InstanceCreationNode::WitWorker { .. }) => {
235                write!(f, "instance")
236            }
237            CallTypeNode::InstanceCreation(InstanceCreationNode::WitResource {
238                resource_name,
239                ..
240            }) => write!(f, "{}", resource_name.resource_name),
241        }
242    }
243}
244
245#[derive(Debug, Clone)]
246pub enum InstanceIdentifierNode {
247    WitWorker {
248        variable_id: Option<VariableId>,
249        worker_name: Option<ExprId>,
250    },
251    WitResource {
252        variable_id: Option<VariableId>,
253        worker_name: Option<ExprId>,
254        resource_name: String,
255    },
256}
257
258#[derive(Debug, Clone)]
259pub enum InstanceCreationNode {
260    WitWorker {
261        component_info: Option<crate::ComponentDependencyKey>,
262        worker_name: Option<ExprId>,
263    },
264    WitResource {
265        component_info: Option<crate::ComponentDependencyKey>,
266        module: Option<InstanceIdentifierNode>,
267        resource_name: crate::FullyQualifiedResourceConstructor,
268    },
269}
270
271#[derive(Debug, Clone)]
272pub struct MatchArmNode {
273    pub arm_pattern: ArmPatternId,
274    pub arm_resolution_expr: ExprId,
275}
276
277#[derive(Debug, Clone)]
278pub enum ArmPatternNode {
279    WildCard,
280    As(String, ArmPatternId),
281    Constructor(String, Vec<ArmPatternId>),
282    TupleConstructor(Vec<ArmPatternId>),
283    RecordConstructor(Vec<(String, ArmPatternId)>),
284    ListConstructor(Vec<ArmPatternId>),
285    /// A literal pattern (identifier, option node, result node, etc.) is just
286    /// an expression embedded in the pattern — we keep the `ExprId` reference.
287    Literal(ExprId),
288}
289
290#[derive(Debug, Clone)]
291pub struct TypeTable {
292    types: HashMap<ExprId, InferredType>,
293}
294
295impl TypeTable {
296    pub fn new() -> Self {
297        TypeTable {
298            types: HashMap::new(),
299        }
300    }
301
302    pub fn get(&self, id: ExprId) -> &InferredType {
303        self.types
304            .get(&id)
305            .expect("TypeTable: ExprId not found — was it allocated in this arena?")
306    }
307
308    pub fn get_opt(&self, id: ExprId) -> Option<&InferredType> {
309        self.types.get(&id)
310    }
311
312    pub fn set(&mut self, id: ExprId, ty: InferredType) {
313        self.types.insert(id, ty);
314    }
315
316    /// Returns a snapshot of all types. The snapshot is a `Vec` ordered by
317    /// insertion — used for fix-point convergence checks (O(n) clone of
318    /// `InferredType` values, **not** a tree clone).
319    pub fn snapshot(&self) -> Vec<(ExprId, InferredType)> {
320        self.types.iter().map(|(k, v)| (*k, v.clone())).collect()
321    }
322
323    /// Returns `true` if this `TypeTable` has the same types as `other`.
324    /// Used to detect convergence in the fix-point loop.
325    pub fn same_as(&self, other: &TypeTable) -> bool {
326        if self.types.len() != other.types.len() {
327            return false;
328        }
329        self.types
330            .iter()
331            .all(|(id, ty)| other.types.get(id) == Some(ty))
332    }
333
334    /// Returns `true` if the current state matches a previously taken snapshot.
335    pub fn same_as_snapshot(&self, snapshot: &[(ExprId, InferredType)]) -> bool {
336        if self.types.len() != snapshot.len() {
337            return false;
338        }
339        snapshot
340            .iter()
341            .all(|(id, ty)| self.types.get(id) == Some(ty))
342    }
343}
344
345impl Default for TypeTable {
346    fn default() -> Self {
347        TypeTable::new()
348    }
349}
350
351// ---------------------------------------------------------------------------
352// ExprArena — structural storage
353// ---------------------------------------------------------------------------
354
355/// Owns all [`ExprNode`]s and [`ArmPatternNode`]s for a single compiled Rib
356/// expression.  Children are referenced by index, never by pointer.
357#[derive(Debug, Default)]
358pub struct ExprArena {
359    pub exprs: Arena<ExprNode>,
360    pub patterns: Arena<ArmPatternNode>,
361}
362
363impl ExprArena {
364    pub fn new() -> Self {
365        ExprArena::default()
366    }
367
368    /// Allocate a new expression node, returning its stable `ExprId`.
369    pub fn alloc_expr(&mut self, node: ExprNode) -> ExprId {
370        self.exprs.alloc(node)
371    }
372
373    /// Allocate a new arm-pattern node, returning its stable `ArmPatternId`.
374    pub fn alloc_pattern(&mut self, node: ArmPatternNode) -> ArmPatternId {
375        self.patterns.alloc(node)
376    }
377
378    /// Look up an expression node by id.
379    pub fn expr(&self, id: ExprId) -> &ExprNode {
380        &self.exprs[id]
381    }
382
383    /// Look up an expression node mutably by id.
384    /// Used by passes that perform structural mutations (e.g. converting an
385    /// `Identifier` node into a `Call` node during enum/variant inference).
386    pub fn expr_mut(&mut self, id: ExprId) -> &mut ExprNode {
387        &mut self.exprs[id]
388    }
389
390    /// Look up a pattern node by id.
391    pub fn pattern(&self, id: ArmPatternId) -> &ArmPatternNode {
392        &self.patterns[id]
393    }
394
395    /// Look up a pattern node mutably by id.
396    pub fn pattern_mut(&mut self, id: ArmPatternId) -> &mut ArmPatternNode {
397        &mut self.patterns[id]
398    }
399}
400
401/// Lower the recursive `Expr` tree into an arena representation.
402///
403/// Returns `(arena, type_table, root_id)`.  The caller can discard the old
404/// `Expr` once this call returns.
405///
406/// # Panics
407/// Does not panic under normal circumstances.
408pub fn lower(expr: &Expr) -> (ExprArena, TypeTable, ExprId) {
409    let mut arena = ExprArena::new();
410    let mut types = TypeTable::new();
411    let root = lower_expr(expr, &mut arena, &mut types);
412    (arena, types, root)
413}
414
415/// Lower `expr` into an existing arena, allocating fresh [`ExprId`]s and wiring
416/// child pointers within `arena` only (unlike naïvely cloning nodes from a
417/// separate lowered arena, which would leave stale child ids).
418pub fn lower_into(arena: &mut ExprArena, types: &mut TypeTable, expr: &Expr) -> ExprId {
419    lower_expr(expr, arena, types)
420}
421
422// ---------------------------------------------------------------------------
423// Rebuild: ExprArena + TypeTable  →  Expr tree
424// ---------------------------------------------------------------------------
425
426/// Reconstruct a full `Expr` tree from the arena, applying the current
427/// `TypeTable` values.  This is the inverse of [`lower`] and handles
428/// structural mutations (e.g. `InvokeMethodLazy` → `Call`) that occurred
429/// during arena-based inference.
430pub fn rebuild_expr(id: ExprId, arena: &ExprArena, types: &TypeTable) -> Expr {
431    let node = arena.expr(id);
432    let inferred = types
433        .get_opt(id)
434        .cloned()
435        .unwrap_or_else(InferredType::unknown);
436    let span = node.source_span.clone();
437    let annotation = node.type_annotation.clone();
438
439    match &node.kind.clone() {
440        ExprKind::Let {
441            variable_id,
442            expr: rhs_id,
443        } => Expr::Let {
444            variable_id: variable_id.clone(),
445            type_annotation: annotation,
446            expr: Box::new(rebuild_expr(*rhs_id, arena, types)),
447            inferred_type: inferred,
448            source_span: span,
449        },
450        ExprKind::SelectField {
451            expr: inner_id,
452            field,
453        } => Expr::SelectField {
454            expr: Box::new(rebuild_expr(*inner_id, arena, types)),
455            field: field.clone(),
456            type_annotation: annotation,
457            inferred_type: inferred,
458            source_span: span,
459        },
460        ExprKind::SelectIndex {
461            expr: e_id,
462            index: i_id,
463        } => Expr::SelectIndex {
464            expr: Box::new(rebuild_expr(*e_id, arena, types)),
465            index: Box::new(rebuild_expr(*i_id, arena, types)),
466            type_annotation: annotation,
467            inferred_type: inferred,
468            source_span: span,
469        },
470        ExprKind::Sequence { exprs } => Expr::Sequence {
471            exprs: exprs
472                .iter()
473                .map(|&e| rebuild_expr(e, arena, types))
474                .collect(),
475            type_annotation: annotation,
476            inferred_type: inferred,
477            source_span: span,
478        },
479        ExprKind::Tuple { exprs } => Expr::Tuple {
480            exprs: exprs
481                .iter()
482                .map(|&e| rebuild_expr(e, arena, types))
483                .collect(),
484            type_annotation: annotation,
485            inferred_type: inferred,
486            source_span: span,
487        },
488        ExprKind::Concat { exprs } => Expr::Concat {
489            exprs: exprs
490                .iter()
491                .map(|&e| rebuild_expr(e, arena, types))
492                .collect(),
493            type_annotation: annotation,
494            inferred_type: inferred,
495            source_span: span,
496        },
497        ExprKind::ExprBlock { exprs } => Expr::ExprBlock {
498            exprs: exprs
499                .iter()
500                .map(|&e| rebuild_expr(e, arena, types))
501                .collect(),
502            type_annotation: annotation,
503            inferred_type: inferred,
504            source_span: span,
505        },
506        ExprKind::Record { fields } => Expr::Record {
507            exprs: fields
508                .iter()
509                .map(|(name, e)| (name.clone(), Box::new(rebuild_expr(*e, arena, types))))
510                .collect(),
511            type_annotation: annotation,
512            inferred_type: inferred,
513            source_span: span,
514        },
515        ExprKind::Range { range } => {
516            let range_val = match range {
517                RangeKind::Range { from, to } => crate::expr::Range::Range {
518                    from: Box::new(rebuild_expr(*from, arena, types)),
519                    to: Box::new(rebuild_expr(*to, arena, types)),
520                },
521                RangeKind::RangeInclusive { from, to } => crate::expr::Range::RangeInclusive {
522                    from: Box::new(rebuild_expr(*from, arena, types)),
523                    to: Box::new(rebuild_expr(*to, arena, types)),
524                },
525                RangeKind::RangeFrom { from } => crate::expr::Range::RangeFrom {
526                    from: Box::new(rebuild_expr(*from, arena, types)),
527                },
528            };
529            Expr::Range {
530                range: range_val,
531                type_annotation: annotation,
532                inferred_type: inferred,
533                source_span: span,
534            }
535        }
536        ExprKind::Literal { value } => Expr::Literal {
537            value: value.clone(),
538            type_annotation: annotation,
539            inferred_type: inferred,
540            source_span: span,
541        },
542        ExprKind::Number { number } => Expr::Number {
543            number: number.clone(),
544            type_annotation: annotation,
545            inferred_type: inferred,
546            source_span: span,
547        },
548        ExprKind::Flags { flags } => Expr::Flags {
549            flags: flags.clone(),
550            type_annotation: annotation,
551            inferred_type: inferred,
552            source_span: span,
553        },
554        ExprKind::Identifier { variable_id } => Expr::Identifier {
555            variable_id: variable_id.clone(),
556            type_annotation: annotation,
557            inferred_type: inferred,
558            source_span: span,
559        },
560        ExprKind::Boolean { value } => Expr::Boolean {
561            value: *value,
562            type_annotation: annotation,
563            inferred_type: inferred,
564            source_span: span,
565        },
566        ExprKind::Not { expr: inner } => Expr::Not {
567            expr: Box::new(rebuild_expr(*inner, arena, types)),
568            type_annotation: annotation,
569            inferred_type: inferred,
570            source_span: span,
571        },
572        ExprKind::Length { expr: inner } => Expr::Length {
573            expr: Box::new(rebuild_expr(*inner, arena, types)),
574            type_annotation: annotation,
575            inferred_type: inferred,
576            source_span: span,
577        },
578        ExprKind::Unwrap { expr: inner } => Expr::Unwrap {
579            expr: Box::new(rebuild_expr(*inner, arena, types)),
580            type_annotation: annotation,
581            inferred_type: inferred,
582            source_span: span,
583        },
584        ExprKind::GetTag { expr: inner } => Expr::GetTag {
585            expr: Box::new(rebuild_expr(*inner, arena, types)),
586            type_annotation: annotation,
587            inferred_type: inferred,
588            source_span: span,
589        },
590        ExprKind::GreaterThan { lhs, rhs } => Expr::GreaterThan {
591            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
592            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
593            type_annotation: annotation,
594            inferred_type: inferred,
595            source_span: span,
596        },
597        ExprKind::GreaterThanOrEqualTo { lhs, rhs } => Expr::GreaterThanOrEqualTo {
598            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
599            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
600            type_annotation: annotation,
601            inferred_type: inferred,
602            source_span: span,
603        },
604        ExprKind::LessThanOrEqualTo { lhs, rhs } => Expr::LessThanOrEqualTo {
605            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
606            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
607            type_annotation: annotation,
608            inferred_type: inferred,
609            source_span: span,
610        },
611        ExprKind::EqualTo { lhs, rhs } => Expr::EqualTo {
612            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
613            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
614            type_annotation: annotation,
615            inferred_type: inferred,
616            source_span: span,
617        },
618        ExprKind::LessThan { lhs, rhs } => Expr::LessThan {
619            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
620            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
621            type_annotation: annotation,
622            inferred_type: inferred,
623            source_span: span,
624        },
625        ExprKind::And { lhs, rhs } => Expr::And {
626            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
627            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
628            type_annotation: annotation,
629            inferred_type: inferred,
630            source_span: span,
631        },
632        ExprKind::Or { lhs, rhs } => Expr::Or {
633            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
634            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
635            type_annotation: annotation,
636            inferred_type: inferred,
637            source_span: span,
638        },
639        ExprKind::Plus { lhs, rhs } => Expr::Plus {
640            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
641            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
642            type_annotation: annotation,
643            inferred_type: inferred,
644            source_span: span,
645        },
646        ExprKind::Minus { lhs, rhs } => Expr::Minus {
647            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
648            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
649            type_annotation: annotation,
650            inferred_type: inferred,
651            source_span: span,
652        },
653        ExprKind::Multiply { lhs, rhs } => Expr::Multiply {
654            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
655            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
656            type_annotation: annotation,
657            inferred_type: inferred,
658            source_span: span,
659        },
660        ExprKind::Divide { lhs, rhs } => Expr::Divide {
661            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
662            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
663            type_annotation: annotation,
664            inferred_type: inferred,
665            source_span: span,
666        },
667        ExprKind::Cond { cond, lhs, rhs } => Expr::Cond {
668            cond: Box::new(rebuild_expr(*cond, arena, types)),
669            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
670            rhs: Box::new(rebuild_expr(*rhs, arena, types)),
671            type_annotation: annotation,
672            inferred_type: inferred,
673            source_span: span,
674        },
675        ExprKind::PatternMatch {
676            predicate,
677            match_arms,
678        } => Expr::PatternMatch {
679            predicate: Box::new(rebuild_expr(*predicate, arena, types)),
680            match_arms: match_arms
681                .iter()
682                .map(|arm| crate::expr::MatchArm {
683                    arm_pattern: rebuild_arm_pattern(arm.arm_pattern, arena, types),
684                    arm_resolution_expr: Box::new(rebuild_expr(
685                        arm.arm_resolution_expr,
686                        arena,
687                        types,
688                    )),
689                })
690                .collect(),
691            type_annotation: annotation,
692            inferred_type: inferred,
693            source_span: span,
694        },
695        ExprKind::Option { expr: None } => Expr::Option {
696            expr: None,
697            type_annotation: annotation,
698            inferred_type: inferred,
699            source_span: span,
700        },
701        ExprKind::Option { expr: Some(inner) } => Expr::Option {
702            expr: Some(Box::new(rebuild_expr(*inner, arena, types))),
703            type_annotation: annotation,
704            inferred_type: inferred,
705            source_span: span,
706        },
707        ExprKind::Result {
708            expr: ResultExprKind::Ok(inner),
709        } => Expr::Result {
710            expr: Ok(Box::new(rebuild_expr(*inner, arena, types))),
711            type_annotation: annotation,
712            inferred_type: inferred,
713            source_span: span,
714        },
715        ExprKind::Result {
716            expr: ResultExprKind::Err(inner),
717        } => Expr::Result {
718            expr: Err(Box::new(rebuild_expr(*inner, arena, types))),
719            type_annotation: annotation,
720            inferred_type: inferred,
721            source_span: span,
722        },
723        ExprKind::Call { call_type, args } => {
724            let old_call_type = rebuild_call_type(call_type, arena, types);
725            Expr::Call {
726                call_type: old_call_type,
727                args: args
728                    .iter()
729                    .map(|&a| rebuild_expr(a, arena, types))
730                    .collect(),
731                type_annotation: annotation,
732                inferred_type: inferred,
733                source_span: span,
734            }
735        }
736        ExprKind::InvokeMethodLazy { lhs, method, args } => Expr::InvokeMethodLazy {
737            lhs: Box::new(rebuild_expr(*lhs, arena, types)),
738            method: method.clone(),
739            args: args
740                .iter()
741                .map(|&a| rebuild_expr(a, arena, types))
742                .collect(),
743            type_annotation: annotation,
744            inferred_type: inferred,
745            source_span: span,
746        },
747        ExprKind::Throw { message } => Expr::Throw {
748            message: message.clone(),
749            type_annotation: annotation,
750            inferred_type: inferred,
751            source_span: span,
752        },
753        ExprKind::ListComprehension {
754            iterated_variable,
755            iterable_expr,
756            yield_expr,
757        } => Expr::ListComprehension {
758            iterated_variable: iterated_variable.clone(),
759            iterable_expr: Box::new(rebuild_expr(*iterable_expr, arena, types)),
760            yield_expr: Box::new(rebuild_expr(*yield_expr, arena, types)),
761            type_annotation: annotation,
762            inferred_type: inferred,
763            source_span: span,
764        },
765        ExprKind::ListReduce {
766            reduce_variable,
767            iterated_variable,
768            iterable_expr,
769            init_value_expr,
770            yield_expr,
771        } => Expr::ListReduce {
772            reduce_variable: reduce_variable.clone(),
773            iterated_variable: iterated_variable.clone(),
774            iterable_expr: Box::new(rebuild_expr(*iterable_expr, arena, types)),
775            init_value_expr: Box::new(rebuild_expr(*init_value_expr, arena, types)),
776            yield_expr: Box::new(rebuild_expr(*yield_expr, arena, types)),
777            type_annotation: annotation,
778            inferred_type: inferred,
779            source_span: span,
780        },
781        ExprKind::GenerateWorkerName { variable_id } => Expr::GenerateWorkerName {
782            variable_id: variable_id.clone(),
783            type_annotation: annotation,
784            inferred_type: inferred,
785            source_span: span,
786        },
787    }
788}
789
790pub(crate) fn rebuild_arm_pattern(
791    pat_id: ArmPatternId,
792    arena: &ExprArena,
793    types: &TypeTable,
794) -> crate::expr::ArmPattern {
795    match arena.pattern(pat_id) {
796        ArmPatternNode::WildCard => crate::expr::ArmPattern::WildCard,
797        ArmPatternNode::As(name, inner) => {
798            let inner = *inner;
799            crate::expr::ArmPattern::As(
800                name.clone(),
801                Box::new(rebuild_arm_pattern(inner, arena, types)),
802            )
803        }
804        ArmPatternNode::Literal(expr_id) => {
805            crate::expr::ArmPattern::Literal(Box::new(rebuild_expr(*expr_id, arena, types)))
806        }
807        ArmPatternNode::Constructor(name, children) => {
808            let children = children.clone();
809            crate::expr::ArmPattern::Constructor(
810                name.clone(),
811                children
812                    .iter()
813                    .map(|&c| rebuild_arm_pattern(c, arena, types))
814                    .collect(),
815            )
816        }
817        ArmPatternNode::TupleConstructor(children) => {
818            let children = children.clone();
819            crate::expr::ArmPattern::TupleConstructor(
820                children
821                    .iter()
822                    .map(|&c| rebuild_arm_pattern(c, arena, types))
823                    .collect(),
824            )
825        }
826        ArmPatternNode::ListConstructor(children) => {
827            let children = children.clone();
828            crate::expr::ArmPattern::ListConstructor(
829                children
830                    .iter()
831                    .map(|&c| rebuild_arm_pattern(c, arena, types))
832                    .collect(),
833            )
834        }
835        ArmPatternNode::RecordConstructor(fields) => {
836            let fields = fields.clone();
837            crate::expr::ArmPattern::RecordConstructor(
838                fields
839                    .iter()
840                    .map(|(name, c)| (name.clone(), rebuild_arm_pattern(*c, arena, types)))
841                    .collect(),
842            )
843        }
844    }
845}
846
847pub(crate) fn rebuild_call_type(
848    call_type: &CallTypeNode,
849    arena: &ExprArena,
850    types: &TypeTable,
851) -> crate::call_type::CallType {
852    use crate::call_type::{CallType, InstanceCreationType};
853    match call_type {
854        CallTypeNode::Function {
855            component_info,
856            instance_identifier,
857            function_name,
858        } => CallType::Function {
859            component_info: component_info.clone(),
860            instance_identifier: instance_identifier
861                .as_ref()
862                .map(|ii| Box::new(rebuild_instance_identifier(ii, arena, types))),
863            function_name: function_name.clone(),
864        },
865        CallTypeNode::VariantConstructor(name) => CallType::VariantConstructor(name.clone()),
866        CallTypeNode::EnumConstructor(name) => CallType::EnumConstructor(name.clone()),
867        CallTypeNode::InstanceCreation(creation) => {
868            let ict = match creation {
869                InstanceCreationNode::WitWorker {
870                    component_info,
871                    worker_name,
872                } => InstanceCreationType::WitWorker {
873                    component_info: component_info.clone(),
874                    worker_name: worker_name
875                        .map(|wn_id| Box::new(rebuild_expr(wn_id, arena, types))),
876                },
877                InstanceCreationNode::WitResource {
878                    component_info,
879                    module,
880                    resource_name,
881                } => InstanceCreationType::WitResource {
882                    component_info: component_info.clone(),
883                    module: module
884                        .as_ref()
885                        .map(|m| rebuild_instance_identifier(m, arena, types)),
886                    resource_name: resource_name.clone(),
887                },
888            };
889            CallType::InstanceCreation(ict)
890        }
891    }
892}
893
894fn rebuild_instance_identifier(
895    ii: &InstanceIdentifierNode,
896    arena: &ExprArena,
897    types: &TypeTable,
898) -> crate::call_type::InstanceIdentifier {
899    use crate::call_type::InstanceIdentifier;
900    match ii {
901        InstanceIdentifierNode::WitWorker {
902            variable_id,
903            worker_name,
904        } => InstanceIdentifier::WitWorker {
905            variable_id: variable_id.clone(),
906            worker_name: worker_name.map(|wn_id| Box::new(rebuild_expr(wn_id, arena, types))),
907        },
908        InstanceIdentifierNode::WitResource {
909            variable_id,
910            worker_name,
911            resource_name,
912        } => InstanceIdentifier::WitResource {
913            variable_id: variable_id.clone(),
914            worker_name: worker_name.map(|wn_id| Box::new(rebuild_expr(wn_id, arena, types))),
915            resource_name: resource_name.clone(),
916        },
917    }
918}
919
920fn lower_expr(expr: &Expr, arena: &mut ExprArena, types: &mut TypeTable) -> ExprId {
921    let (kind, span, annotation, inferred) = match expr {
922        Expr::Let {
923            variable_id,
924            type_annotation,
925            expr,
926            inferred_type,
927            source_span,
928        } => {
929            let child = lower_expr(expr, arena, types);
930            (
931                ExprKind::Let {
932                    variable_id: variable_id.clone(),
933                    expr: child,
934                },
935                source_span.clone(),
936                type_annotation.clone(),
937                inferred_type.clone(),
938            )
939        }
940
941        Expr::SelectField {
942            expr,
943            field,
944            type_annotation,
945            inferred_type,
946            source_span,
947        } => {
948            let child = lower_expr(expr, arena, types);
949            (
950                ExprKind::SelectField {
951                    expr: child,
952                    field: field.clone(),
953                },
954                source_span.clone(),
955                type_annotation.clone(),
956                inferred_type.clone(),
957            )
958        }
959
960        Expr::SelectIndex {
961            expr,
962            index,
963            type_annotation,
964            inferred_type,
965            source_span,
966        } => {
967            let e = lower_expr(expr, arena, types);
968            let i = lower_expr(index, arena, types);
969            (
970                ExprKind::SelectIndex { expr: e, index: i },
971                source_span.clone(),
972                type_annotation.clone(),
973                inferred_type.clone(),
974            )
975        }
976
977        Expr::Sequence {
978            exprs,
979            type_annotation,
980            inferred_type,
981            source_span,
982        } => {
983            let ids = exprs.iter().map(|e| lower_expr(e, arena, types)).collect();
984            (
985                ExprKind::Sequence { exprs: ids },
986                source_span.clone(),
987                type_annotation.clone(),
988                inferred_type.clone(),
989            )
990        }
991
992        Expr::Range {
993            range,
994            type_annotation,
995            inferred_type,
996            source_span,
997        } => {
998            let range_kind = lower_range(range, arena, types);
999            (
1000                ExprKind::Range { range: range_kind },
1001                source_span.clone(),
1002                type_annotation.clone(),
1003                inferred_type.clone(),
1004            )
1005        }
1006
1007        Expr::Record {
1008            exprs,
1009            type_annotation,
1010            inferred_type,
1011            source_span,
1012        } => {
1013            let fields = exprs
1014                .iter()
1015                .map(|(name, e)| (name.clone(), lower_expr(e, arena, types)))
1016                .collect();
1017            (
1018                ExprKind::Record { fields },
1019                source_span.clone(),
1020                type_annotation.clone(),
1021                inferred_type.clone(),
1022            )
1023        }
1024
1025        Expr::Tuple {
1026            exprs,
1027            type_annotation,
1028            inferred_type,
1029            source_span,
1030        } => {
1031            let ids = exprs.iter().map(|e| lower_expr(e, arena, types)).collect();
1032            (
1033                ExprKind::Tuple { exprs: ids },
1034                source_span.clone(),
1035                type_annotation.clone(),
1036                inferred_type.clone(),
1037            )
1038        }
1039
1040        Expr::Literal {
1041            value,
1042            type_annotation,
1043            inferred_type,
1044            source_span,
1045        } => (
1046            ExprKind::Literal {
1047                value: value.clone(),
1048            },
1049            source_span.clone(),
1050            type_annotation.clone(),
1051            inferred_type.clone(),
1052        ),
1053
1054        Expr::Number {
1055            number,
1056            type_annotation,
1057            inferred_type,
1058            source_span,
1059        } => (
1060            ExprKind::Number {
1061                number: number.clone(),
1062            },
1063            source_span.clone(),
1064            type_annotation.clone(),
1065            inferred_type.clone(),
1066        ),
1067
1068        Expr::Flags {
1069            flags,
1070            type_annotation,
1071            inferred_type,
1072            source_span,
1073        } => (
1074            ExprKind::Flags {
1075                flags: flags.clone(),
1076            },
1077            source_span.clone(),
1078            type_annotation.clone(),
1079            inferred_type.clone(),
1080        ),
1081
1082        Expr::Identifier {
1083            variable_id,
1084            type_annotation,
1085            inferred_type,
1086            source_span,
1087        } => (
1088            ExprKind::Identifier {
1089                variable_id: variable_id.clone(),
1090            },
1091            source_span.clone(),
1092            type_annotation.clone(),
1093            inferred_type.clone(),
1094        ),
1095
1096        Expr::Boolean {
1097            value,
1098            type_annotation,
1099            inferred_type,
1100            source_span,
1101        } => (
1102            ExprKind::Boolean { value: *value },
1103            source_span.clone(),
1104            type_annotation.clone(),
1105            inferred_type.clone(),
1106        ),
1107
1108        Expr::Concat {
1109            exprs,
1110            type_annotation,
1111            inferred_type,
1112            source_span,
1113        } => {
1114            let ids = exprs.iter().map(|e| lower_expr(e, arena, types)).collect();
1115            (
1116                ExprKind::Concat { exprs: ids },
1117                source_span.clone(),
1118                type_annotation.clone(),
1119                inferred_type.clone(),
1120            )
1121        }
1122
1123        Expr::ExprBlock {
1124            exprs,
1125            type_annotation,
1126            inferred_type,
1127            source_span,
1128        } => {
1129            let ids = exprs.iter().map(|e| lower_expr(e, arena, types)).collect();
1130            (
1131                ExprKind::ExprBlock { exprs: ids },
1132                source_span.clone(),
1133                type_annotation.clone(),
1134                inferred_type.clone(),
1135            )
1136        }
1137
1138        Expr::Not {
1139            expr,
1140            type_annotation,
1141            inferred_type,
1142            source_span,
1143        } => {
1144            let child = lower_expr(expr, arena, types);
1145            (
1146                ExprKind::Not { expr: child },
1147                source_span.clone(),
1148                type_annotation.clone(),
1149                inferred_type.clone(),
1150            )
1151        }
1152
1153        Expr::GreaterThan {
1154            lhs,
1155            rhs,
1156            type_annotation,
1157            inferred_type,
1158            source_span,
1159        } => {
1160            let l = lower_expr(lhs, arena, types);
1161            let r = lower_expr(rhs, arena, types);
1162            (
1163                ExprKind::GreaterThan { lhs: l, rhs: r },
1164                source_span.clone(),
1165                type_annotation.clone(),
1166                inferred_type.clone(),
1167            )
1168        }
1169
1170        Expr::GreaterThanOrEqualTo {
1171            lhs,
1172            rhs,
1173            type_annotation,
1174            inferred_type,
1175            source_span,
1176        } => {
1177            let l = lower_expr(lhs, arena, types);
1178            let r = lower_expr(rhs, arena, types);
1179            (
1180                ExprKind::GreaterThanOrEqualTo { lhs: l, rhs: r },
1181                source_span.clone(),
1182                type_annotation.clone(),
1183                inferred_type.clone(),
1184            )
1185        }
1186
1187        Expr::LessThanOrEqualTo {
1188            lhs,
1189            rhs,
1190            type_annotation,
1191            inferred_type,
1192            source_span,
1193        } => {
1194            let l = lower_expr(lhs, arena, types);
1195            let r = lower_expr(rhs, arena, types);
1196            (
1197                ExprKind::LessThanOrEqualTo { lhs: l, rhs: r },
1198                source_span.clone(),
1199                type_annotation.clone(),
1200                inferred_type.clone(),
1201            )
1202        }
1203
1204        Expr::EqualTo {
1205            lhs,
1206            rhs,
1207            type_annotation,
1208            inferred_type,
1209            source_span,
1210        } => {
1211            let l = lower_expr(lhs, arena, types);
1212            let r = lower_expr(rhs, arena, types);
1213            (
1214                ExprKind::EqualTo { lhs: l, rhs: r },
1215                source_span.clone(),
1216                type_annotation.clone(),
1217                inferred_type.clone(),
1218            )
1219        }
1220
1221        Expr::LessThan {
1222            lhs,
1223            rhs,
1224            type_annotation,
1225            inferred_type,
1226            source_span,
1227        } => {
1228            let l = lower_expr(lhs, arena, types);
1229            let r = lower_expr(rhs, arena, types);
1230            (
1231                ExprKind::LessThan { lhs: l, rhs: r },
1232                source_span.clone(),
1233                type_annotation.clone(),
1234                inferred_type.clone(),
1235            )
1236        }
1237
1238        Expr::And {
1239            lhs,
1240            rhs,
1241            type_annotation,
1242            inferred_type,
1243            source_span,
1244        } => {
1245            let l = lower_expr(lhs, arena, types);
1246            let r = lower_expr(rhs, arena, types);
1247            (
1248                ExprKind::And { lhs: l, rhs: r },
1249                source_span.clone(),
1250                type_annotation.clone(),
1251                inferred_type.clone(),
1252            )
1253        }
1254
1255        Expr::Or {
1256            lhs,
1257            rhs,
1258            type_annotation,
1259            inferred_type,
1260            source_span,
1261        } => {
1262            let l = lower_expr(lhs, arena, types);
1263            let r = lower_expr(rhs, arena, types);
1264            (
1265                ExprKind::Or { lhs: l, rhs: r },
1266                source_span.clone(),
1267                type_annotation.clone(),
1268                inferred_type.clone(),
1269            )
1270        }
1271
1272        Expr::Plus {
1273            lhs,
1274            rhs,
1275            type_annotation,
1276            inferred_type,
1277            source_span,
1278        } => {
1279            let l = lower_expr(lhs, arena, types);
1280            let r = lower_expr(rhs, arena, types);
1281            (
1282                ExprKind::Plus { lhs: l, rhs: r },
1283                source_span.clone(),
1284                type_annotation.clone(),
1285                inferred_type.clone(),
1286            )
1287        }
1288
1289        Expr::Minus {
1290            lhs,
1291            rhs,
1292            type_annotation,
1293            inferred_type,
1294            source_span,
1295        } => {
1296            let l = lower_expr(lhs, arena, types);
1297            let r = lower_expr(rhs, arena, types);
1298            (
1299                ExprKind::Minus { lhs: l, rhs: r },
1300                source_span.clone(),
1301                type_annotation.clone(),
1302                inferred_type.clone(),
1303            )
1304        }
1305
1306        Expr::Multiply {
1307            lhs,
1308            rhs,
1309            type_annotation,
1310            inferred_type,
1311            source_span,
1312        } => {
1313            let l = lower_expr(lhs, arena, types);
1314            let r = lower_expr(rhs, arena, types);
1315            (
1316                ExprKind::Multiply { lhs: l, rhs: r },
1317                source_span.clone(),
1318                type_annotation.clone(),
1319                inferred_type.clone(),
1320            )
1321        }
1322
1323        Expr::Divide {
1324            lhs,
1325            rhs,
1326            type_annotation,
1327            inferred_type,
1328            source_span,
1329        } => {
1330            let l = lower_expr(lhs, arena, types);
1331            let r = lower_expr(rhs, arena, types);
1332            (
1333                ExprKind::Divide { lhs: l, rhs: r },
1334                source_span.clone(),
1335                type_annotation.clone(),
1336                inferred_type.clone(),
1337            )
1338        }
1339
1340        Expr::Cond {
1341            cond,
1342            lhs,
1343            rhs,
1344            type_annotation,
1345            inferred_type,
1346            source_span,
1347        } => {
1348            let c = lower_expr(cond, arena, types);
1349            let l = lower_expr(lhs, arena, types);
1350            let r = lower_expr(rhs, arena, types);
1351            (
1352                ExprKind::Cond {
1353                    cond: c,
1354                    lhs: l,
1355                    rhs: r,
1356                },
1357                source_span.clone(),
1358                type_annotation.clone(),
1359                inferred_type.clone(),
1360            )
1361        }
1362
1363        Expr::PatternMatch {
1364            predicate,
1365            match_arms,
1366            type_annotation,
1367            inferred_type,
1368            source_span,
1369        } => {
1370            let pred = lower_expr(predicate, arena, types);
1371            let arms = match_arms
1372                .iter()
1373                .map(|arm| lower_match_arm(arm, arena, types))
1374                .collect();
1375            (
1376                ExprKind::PatternMatch {
1377                    predicate: pred,
1378                    match_arms: arms,
1379                },
1380                source_span.clone(),
1381                type_annotation.clone(),
1382                inferred_type.clone(),
1383            )
1384        }
1385
1386        Expr::Option {
1387            expr,
1388            type_annotation,
1389            inferred_type,
1390            source_span,
1391        } => {
1392            let child = expr.as_ref().map(|e| lower_expr(e, arena, types));
1393            (
1394                ExprKind::Option { expr: child },
1395                source_span.clone(),
1396                type_annotation.clone(),
1397                inferred_type.clone(),
1398            )
1399        }
1400
1401        Expr::Result {
1402            expr,
1403            type_annotation,
1404            inferred_type,
1405            source_span,
1406        } => {
1407            let kind = match expr {
1408                Ok(e) => ResultExprKind::Ok(lower_expr(e, arena, types)),
1409                Err(e) => ResultExprKind::Err(lower_expr(e, arena, types)),
1410            };
1411            (
1412                ExprKind::Result { expr: kind },
1413                source_span.clone(),
1414                type_annotation.clone(),
1415                inferred_type.clone(),
1416            )
1417        }
1418
1419        Expr::Call {
1420            call_type,
1421            args,
1422            type_annotation,
1423            inferred_type,
1424            source_span,
1425        } => {
1426            let call_node = lower_call_type(call_type, arena, types);
1427            let arg_ids = args.iter().map(|a| lower_expr(a, arena, types)).collect();
1428            (
1429                ExprKind::Call {
1430                    call_type: call_node,
1431                    args: arg_ids,
1432                },
1433                source_span.clone(),
1434                type_annotation.clone(),
1435                inferred_type.clone(),
1436            )
1437        }
1438
1439        Expr::InvokeMethodLazy {
1440            lhs,
1441            method,
1442            args,
1443            type_annotation,
1444            inferred_type,
1445            source_span,
1446        } => {
1447            let lhs_id = lower_expr(lhs, arena, types);
1448            let arg_ids = args.iter().map(|a| lower_expr(a, arena, types)).collect();
1449            (
1450                ExprKind::InvokeMethodLazy {
1451                    lhs: lhs_id,
1452                    method: method.clone(),
1453                    args: arg_ids,
1454                },
1455                source_span.clone(),
1456                type_annotation.clone(),
1457                inferred_type.clone(),
1458            )
1459        }
1460
1461        Expr::Unwrap {
1462            expr,
1463            type_annotation,
1464            inferred_type,
1465            source_span,
1466        } => {
1467            let child = lower_expr(expr, arena, types);
1468            (
1469                ExprKind::Unwrap { expr: child },
1470                source_span.clone(),
1471                type_annotation.clone(),
1472                inferred_type.clone(),
1473            )
1474        }
1475
1476        Expr::Throw {
1477            message,
1478            type_annotation,
1479            inferred_type,
1480            source_span,
1481        } => (
1482            ExprKind::Throw {
1483                message: message.clone(),
1484            },
1485            source_span.clone(),
1486            type_annotation.clone(),
1487            inferred_type.clone(),
1488        ),
1489
1490        Expr::GetTag {
1491            expr,
1492            type_annotation,
1493            inferred_type,
1494            source_span,
1495        } => {
1496            let child = lower_expr(expr, arena, types);
1497            (
1498                ExprKind::GetTag { expr: child },
1499                source_span.clone(),
1500                type_annotation.clone(),
1501                inferred_type.clone(),
1502            )
1503        }
1504
1505        Expr::ListComprehension {
1506            iterated_variable,
1507            iterable_expr,
1508            yield_expr,
1509            type_annotation,
1510            inferred_type,
1511            source_span,
1512        } => {
1513            let iterable = lower_expr(iterable_expr, arena, types);
1514            let yield_ = lower_expr(yield_expr, arena, types);
1515            (
1516                ExprKind::ListComprehension {
1517                    iterated_variable: iterated_variable.clone(),
1518                    iterable_expr: iterable,
1519                    yield_expr: yield_,
1520                },
1521                source_span.clone(),
1522                type_annotation.clone(),
1523                inferred_type.clone(),
1524            )
1525        }
1526
1527        Expr::ListReduce {
1528            reduce_variable,
1529            iterated_variable,
1530            iterable_expr,
1531            init_value_expr,
1532            yield_expr,
1533            type_annotation,
1534            inferred_type,
1535            source_span,
1536        } => {
1537            let iterable = lower_expr(iterable_expr, arena, types);
1538            let init = lower_expr(init_value_expr, arena, types);
1539            let yield_ = lower_expr(yield_expr, arena, types);
1540            (
1541                ExprKind::ListReduce {
1542                    reduce_variable: reduce_variable.clone(),
1543                    iterated_variable: iterated_variable.clone(),
1544                    iterable_expr: iterable,
1545                    init_value_expr: init,
1546                    yield_expr: yield_,
1547                },
1548                source_span.clone(),
1549                type_annotation.clone(),
1550                inferred_type.clone(),
1551            )
1552        }
1553
1554        Expr::Length {
1555            expr,
1556            type_annotation,
1557            inferred_type,
1558            source_span,
1559        } => {
1560            let child = lower_expr(expr, arena, types);
1561            (
1562                ExprKind::Length { expr: child },
1563                source_span.clone(),
1564                type_annotation.clone(),
1565                inferred_type.clone(),
1566            )
1567        }
1568
1569        Expr::GenerateWorkerName {
1570            variable_id,
1571            type_annotation,
1572            inferred_type,
1573            source_span,
1574        } => (
1575            ExprKind::GenerateWorkerName {
1576                variable_id: variable_id.clone(),
1577            },
1578            source_span.clone(),
1579            type_annotation.clone(),
1580            inferred_type.clone(),
1581        ),
1582    };
1583
1584    let id = arena.alloc_expr(ExprNode {
1585        kind,
1586        source_span: span,
1587        type_annotation: annotation,
1588    });
1589    types.set(id, inferred);
1590    id
1591}
1592
1593fn lower_range(range: &Range, arena: &mut ExprArena, types: &mut TypeTable) -> RangeKind {
1594    match range {
1595        Range::Range { from, to } => RangeKind::Range {
1596            from: lower_expr(from, arena, types),
1597            to: lower_expr(to, arena, types),
1598        },
1599        Range::RangeInclusive { from, to } => RangeKind::RangeInclusive {
1600            from: lower_expr(from, arena, types),
1601            to: lower_expr(to, arena, types),
1602        },
1603        Range::RangeFrom { from } => RangeKind::RangeFrom {
1604            from: lower_expr(from, arena, types),
1605        },
1606    }
1607}
1608
1609fn lower_match_arm(arm: &MatchArm, arena: &mut ExprArena, types: &mut TypeTable) -> MatchArmNode {
1610    let pattern_id = lower_arm_pattern(&arm.arm_pattern, arena, types);
1611    let resolution_id = lower_expr(&arm.arm_resolution_expr, arena, types);
1612    MatchArmNode {
1613        arm_pattern: pattern_id,
1614        arm_resolution_expr: resolution_id,
1615    }
1616}
1617
1618fn lower_arm_pattern(
1619    pattern: &ArmPattern,
1620    arena: &mut ExprArena,
1621    types: &mut TypeTable,
1622) -> ArmPatternId {
1623    let node = match pattern {
1624        ArmPattern::WildCard => ArmPatternNode::WildCard,
1625
1626        ArmPattern::As(name, inner) => {
1627            let inner_id = lower_arm_pattern(inner, arena, types);
1628            ArmPatternNode::As(name.clone(), inner_id)
1629        }
1630
1631        ArmPattern::Constructor(name, patterns) => {
1632            let ids = patterns
1633                .iter()
1634                .map(|p| lower_arm_pattern(p, arena, types))
1635                .collect();
1636            ArmPatternNode::Constructor(name.clone(), ids)
1637        }
1638
1639        ArmPattern::TupleConstructor(patterns) => {
1640            let ids = patterns
1641                .iter()
1642                .map(|p| lower_arm_pattern(p, arena, types))
1643                .collect();
1644            ArmPatternNode::TupleConstructor(ids)
1645        }
1646
1647        ArmPattern::RecordConstructor(fields) => {
1648            let pairs = fields
1649                .iter()
1650                .map(|(name, p)| (name.clone(), lower_arm_pattern(p, arena, types)))
1651                .collect();
1652            ArmPatternNode::RecordConstructor(pairs)
1653        }
1654
1655        ArmPattern::ListConstructor(patterns) => {
1656            let ids = patterns
1657                .iter()
1658                .map(|p| lower_arm_pattern(p, arena, types))
1659                .collect();
1660            ArmPatternNode::ListConstructor(ids)
1661        }
1662
1663        ArmPattern::Literal(expr) => {
1664            let expr_id = lower_expr(expr, arena, types);
1665            ArmPatternNode::Literal(expr_id)
1666        }
1667    };
1668
1669    arena.alloc_pattern(node)
1670}
1671
1672fn lower_call_type(
1673    call_type: &CallType,
1674    arena: &mut ExprArena,
1675    types: &mut TypeTable,
1676) -> CallTypeNode {
1677    match call_type {
1678        CallType::Function {
1679            component_info,
1680            instance_identifier,
1681            function_name,
1682        } => CallTypeNode::Function {
1683            component_info: component_info.clone(),
1684            instance_identifier: instance_identifier
1685                .as_ref()
1686                .map(|ii| lower_instance_identifier(ii, arena, types)),
1687            function_name: function_name.clone(),
1688        },
1689
1690        CallType::VariantConstructor(name) => CallTypeNode::VariantConstructor(name.clone()),
1691        CallType::EnumConstructor(name) => CallTypeNode::EnumConstructor(name.clone()),
1692
1693        CallType::InstanceCreation(creation) => {
1694            CallTypeNode::InstanceCreation(lower_instance_creation(creation, arena, types))
1695        }
1696    }
1697}
1698
1699fn lower_instance_identifier(
1700    ii: &InstanceIdentifier,
1701    arena: &mut ExprArena,
1702    types: &mut TypeTable,
1703) -> InstanceIdentifierNode {
1704    match ii {
1705        InstanceIdentifier::WitWorker {
1706            variable_id,
1707            worker_name,
1708        } => InstanceIdentifierNode::WitWorker {
1709            variable_id: variable_id.clone(),
1710            worker_name: worker_name
1711                .as_ref()
1712                .map(|wn| lower_expr(wn.as_ref(), arena, types)),
1713        },
1714        InstanceIdentifier::WitResource {
1715            variable_id,
1716            worker_name,
1717            resource_name,
1718        } => InstanceIdentifierNode::WitResource {
1719            variable_id: variable_id.clone(),
1720            worker_name: worker_name
1721                .as_ref()
1722                .map(|wn| lower_expr(wn.as_ref(), arena, types)),
1723            resource_name: resource_name.clone(),
1724        },
1725    }
1726}
1727
1728fn lower_instance_creation(
1729    creation: &InstanceCreationType,
1730    arena: &mut ExprArena,
1731    types: &mut TypeTable,
1732) -> InstanceCreationNode {
1733    match creation {
1734        InstanceCreationType::WitWorker {
1735            component_info,
1736            worker_name,
1737        } => InstanceCreationNode::WitWorker {
1738            component_info: component_info.clone(),
1739            worker_name: worker_name
1740                .as_ref()
1741                .map(|wn| lower_expr(wn.as_ref(), arena, types)),
1742        },
1743        InstanceCreationType::WitResource {
1744            component_info,
1745            module,
1746            resource_name,
1747        } => InstanceCreationNode::WitResource {
1748            component_info: component_info.clone(),
1749            module: module
1750                .as_ref()
1751                .map(|m| lower_instance_identifier(m, arena, types)),
1752            resource_name: resource_name.clone(),
1753        },
1754    }
1755}
1756
1757// ---------------------------------------------------------------------------
1758// Tests
1759// ---------------------------------------------------------------------------
1760
1761#[cfg(test)]
1762mod tests {
1763    use test_r::test;
1764
1765    use super::*;
1766    use crate::Expr;
1767
1768    #[test]
1769    fn test_lower_literal() {
1770        let expr = Expr::from_text(r#""hello""#).unwrap();
1771        let (arena, types, root) = lower(&expr);
1772        let node = arena.expr(root);
1773        assert!(matches!(node.kind, ExprKind::Literal { .. }));
1774        // TypeTable must contain an entry for the root
1775        assert!(types.get_opt(root).is_some());
1776    }
1777
1778    #[test]
1779    fn test_lower_let_binding() {
1780        let expr = Expr::from_text("let x = 1; x").unwrap();
1781        let (arena, types, root) = lower(&expr);
1782        // root should be an ExprBlock
1783        let node = arena.expr(root);
1784        assert!(matches!(node.kind, ExprKind::ExprBlock { .. }));
1785        // All nodes must have a type entry
1786        for (id, _) in arena.exprs.iter() {
1787            assert!(types.get_opt(id).is_some(), "missing type for expr node");
1788        }
1789    }
1790
1791    #[test]
1792    fn test_lower_pattern_match() {
1793        let src = r#"
1794            let x = some("hello");
1795            match x {
1796              some(v) => v,
1797              none => "default"
1798            }
1799        "#;
1800        let expr = Expr::from_text(src).unwrap();
1801        let (arena, types, root) = lower(&expr);
1802        // Verify every node and every pattern has a type / exists
1803        for (id, _) in arena.exprs.iter() {
1804            assert!(types.get_opt(id).is_some());
1805        }
1806        // Patterns should all be allocated
1807        assert!(arena.patterns.iter().count() > 0);
1808        let _ = root;
1809    }
1810
1811    #[test]
1812    fn test_type_table_snapshot_and_same_as() {
1813        let expr = Expr::from_text(r#"1 + 2"#).unwrap();
1814        let (_arena, types, _root) = lower(&expr);
1815        let snap = types.snapshot();
1816        // Reconstruct a TypeTable from the snapshot and verify same_as
1817        let mut reconstructed = TypeTable::new();
1818        for (id, ty) in snap {
1819            reconstructed.set(id, ty);
1820        }
1821        assert!(types.same_as(&reconstructed));
1822    }
1823
1824    #[test]
1825    fn test_node_count_matches() {
1826        // A simple expr "1" has exactly 1 node
1827        let expr = Expr::from_text(r#"1"#).unwrap();
1828        let (arena, types, _root) = lower(&expr);
1829        assert_eq!(arena.exprs.iter().count(), types.snapshot().len());
1830    }
1831}