Skip to main content

lisette_syntax/
ast.rs

1use ecow::EcoString;
2
3use crate::program::{CallKind, DotAccessKind, ReceiverCoercion};
4use crate::types::Type;
5
6const CHILDREN_INLINE_CAP: usize = 4;
7
8pub struct Children<'a> {
9    inline: [Option<&'a Expression>; CHILDREN_INLINE_CAP],
10    inline_len: usize,
11    heap: Vec<&'a Expression>,
12}
13
14impl<'a> Children<'a> {
15    pub fn new() -> Self {
16        Children {
17            inline: [None; CHILDREN_INLINE_CAP],
18            inline_len: 0,
19            heap: Vec::new(),
20        }
21    }
22
23    pub fn push(&mut self, expression: &'a Expression) {
24        if self.heap.is_empty() && self.inline_len < CHILDREN_INLINE_CAP {
25            self.inline[self.inline_len] = Some(expression);
26            self.inline_len += 1;
27        } else {
28            self.heap.push(expression);
29        }
30    }
31
32    pub fn iter(&self) -> impl Iterator<Item = &'a Expression> + '_ {
33        self.inline[..self.inline_len]
34            .iter()
35            .filter_map(|slot| *slot)
36            .chain(self.heap.iter().copied())
37    }
38}
39
40impl Default for Children<'_> {
41    fn default() -> Self {
42        Children::new()
43    }
44}
45
46impl<'a> Extend<&'a Expression> for Children<'a> {
47    fn extend<T: IntoIterator<Item = &'a Expression>>(&mut self, iter: T) {
48        for expression in iter {
49            self.push(expression);
50        }
51    }
52}
53
54impl<'a> FromIterator<&'a Expression> for Children<'a> {
55    fn from_iter<T: IntoIterator<Item = &'a Expression>>(iter: T) -> Self {
56        let mut children = Children::new();
57        children.extend(iter);
58        children
59    }
60}
61
62pub struct ChildrenIntoIter<'a> {
63    inline: [Option<&'a Expression>; CHILDREN_INLINE_CAP],
64    pos: usize,
65    inline_len: usize,
66    heap: std::vec::IntoIter<&'a Expression>,
67}
68
69impl<'a> Iterator for ChildrenIntoIter<'a> {
70    type Item = &'a Expression;
71
72    fn next(&mut self) -> Option<&'a Expression> {
73        if self.pos < self.inline_len {
74            let item = self.inline[self.pos];
75            self.pos += 1;
76            item
77        } else {
78            self.heap.next()
79        }
80    }
81}
82
83impl<'a> IntoIterator for Children<'a> {
84    type Item = &'a Expression;
85    type IntoIter = ChildrenIntoIter<'a>;
86
87    fn into_iter(self) -> ChildrenIntoIter<'a> {
88        ChildrenIntoIter {
89            inline: self.inline,
90            pos: 0,
91            inline_len: self.inline_len,
92            heap: self.heap.into_iter(),
93        }
94    }
95}
96
97macro_rules! children {
98    () => { Children::new() };
99    ($($expression:expr),+ $(,)?) => {{
100        let mut __children = Children::new();
101        $( __children.push($expression); )+
102        __children
103    }};
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum DeadCodeCause {
108    Return,
109    Break,
110    Continue,
111    DivergingIf,
112    DivergingMatch,
113    InfiniteLoop,
114    DivergingCall,
115}
116
117#[derive(Clone, PartialEq)]
118pub struct Binding {
119    pub pattern: Pattern,
120    pub annotation: Option<Annotation>,
121    pub typed_pattern: Option<TypedPattern>,
122    pub ty: Type,
123    pub mutable: bool,
124}
125
126impl std::fmt::Debug for Binding {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        let mut s = f.debug_struct("Binding");
129        s.field("pattern", &self.pattern);
130        s.field("annotation", &self.annotation);
131        s.field("typed_pattern", &self.typed_pattern);
132        s.field("ty", &self.ty);
133        if self.mutable {
134            s.field("mutable", &self.mutable);
135        }
136        s.finish()
137    }
138}
139
140pub type BindingId = u32;
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
143pub enum BindingKind {
144    Let { mutable: bool },
145    Parameter { mutable: bool },
146    MatchArm,
147    IfLet,
148    WhileLet,
149}
150
151impl BindingKind {
152    pub fn is_mutable(&self) -> bool {
153        matches!(
154            self,
155            BindingKind::Let { mutable: true } | BindingKind::Parameter { mutable: true }
156        )
157    }
158
159    pub fn is_param(&self) -> bool {
160        matches!(self, BindingKind::Parameter { .. })
161    }
162
163    pub fn is_match_arm(&self) -> bool {
164        matches!(self, BindingKind::MatchArm)
165    }
166
167    pub fn is_pattern_position(&self) -> bool {
168        matches!(
169            self,
170            BindingKind::MatchArm | BindingKind::IfLet | BindingKind::WhileLet
171        )
172    }
173}
174
175#[derive(Clone, PartialEq)]
176pub struct MatchArm {
177    pub pattern: Pattern,
178    pub guard: Option<Box<Expression>>,
179    pub typed_pattern: Option<TypedPattern>,
180    pub expression: Box<Expression>,
181}
182
183impl MatchArm {
184    pub fn has_guard(&self) -> bool {
185        self.guard.is_some()
186    }
187}
188
189impl std::fmt::Debug for MatchArm {
190    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191        let mut s = f.debug_struct("MatchArm");
192        s.field("pattern", &self.pattern);
193        if self.guard.is_some() {
194            s.field("guard", &self.guard);
195        }
196        s.field("expression", &self.expression);
197        s.finish()
198    }
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub enum MatchOrigin {
203    Explicit,
204    IfLet { else_span: Option<Span> },
205}
206
207#[derive(Debug, Clone, PartialEq)]
208pub struct SelectArm {
209    pub pattern: SelectArmPattern,
210}
211
212#[derive(Debug, Clone, PartialEq)]
213pub enum SelectArmPattern {
214    Receive {
215        binding: Box<Pattern>,
216        typed_pattern: Option<TypedPattern>,
217        receive_expression: Box<Expression>,
218        body: Box<Expression>,
219    },
220    Send {
221        send_expression: Box<Expression>,
222        body: Box<Expression>,
223    },
224    MatchReceive {
225        receive_expression: Box<Expression>,
226        arms: Vec<MatchArm>,
227    },
228    WildCard {
229        body: Box<Expression>,
230    },
231}
232
233#[derive(Debug, Clone, PartialEq)]
234pub enum RestPattern {
235    Absent,
236    Discard(Span),
237    Bind { name: EcoString, span: Span },
238}
239
240impl RestPattern {
241    pub fn is_present(&self) -> bool {
242        !matches!(self, RestPattern::Absent)
243    }
244}
245
246#[derive(Debug, Clone, PartialEq)]
247pub enum Pattern {
248    Literal {
249        literal: Literal,
250        ty: Type,
251        span: Span,
252    },
253    Unit {
254        ty: Type,
255        span: Span,
256    },
257    EnumVariant {
258        identifier: EcoString,
259        fields: Vec<Self>,
260        rest: bool,
261        ty: Type,
262        span: Span,
263    },
264    Struct {
265        identifier: EcoString,
266        fields: Vec<StructFieldPattern>,
267        rest: bool,
268        ty: Type,
269        span: Span,
270    },
271    Tuple {
272        elements: Vec<Self>,
273        span: Span,
274    },
275    WildCard {
276        span: Span,
277    },
278    Identifier {
279        identifier: EcoString,
280        span: Span,
281    },
282    Slice {
283        prefix: Vec<Self>,
284        rest: RestPattern,
285        element_ty: Type,
286        span: Span,
287    },
288    Or {
289        patterns: Vec<Self>,
290        span: Span,
291    },
292    AsBinding {
293        pattern: Box<Self>,
294        name: EcoString,
295        span: Span,
296    },
297}
298
299/// Dataless variant index of [`Pattern`], usable as an array index.
300#[derive(Clone, Copy)]
301pub enum PatternKind {
302    Literal,
303    Unit,
304    EnumVariant,
305    Struct,
306    Tuple,
307    WildCard,
308    Identifier,
309    Slice,
310    Or,
311    AsBinding,
312}
313
314impl PatternKind {
315    // Relies on `AsBinding` staying the last variant.
316    pub const COUNT: usize = PatternKind::AsBinding as usize + 1;
317}
318
319impl Pattern {
320    pub fn kind(&self) -> PatternKind {
321        match self {
322            Pattern::Literal { .. } => PatternKind::Literal,
323            Pattern::Unit { .. } => PatternKind::Unit,
324            Pattern::EnumVariant { .. } => PatternKind::EnumVariant,
325            Pattern::Struct { .. } => PatternKind::Struct,
326            Pattern::Tuple { .. } => PatternKind::Tuple,
327            Pattern::WildCard { .. } => PatternKind::WildCard,
328            Pattern::Identifier { .. } => PatternKind::Identifier,
329            Pattern::Slice { .. } => PatternKind::Slice,
330            Pattern::Or { .. } => PatternKind::Or,
331            Pattern::AsBinding { .. } => PatternKind::AsBinding,
332        }
333    }
334
335    pub fn get_span(&self) -> Span {
336        match self {
337            Pattern::Identifier { span, .. } => *span,
338            Pattern::Literal { span, .. } => *span,
339            Pattern::EnumVariant { span, .. } => *span,
340            Pattern::Struct { span, .. } => *span,
341            Pattern::WildCard { span } => *span,
342            Pattern::Unit { span, .. } => *span,
343            Pattern::Tuple { span, .. } => *span,
344            Pattern::Slice { span, .. } => *span,
345            Pattern::Or { span, .. } => *span,
346            Pattern::AsBinding { span, .. } => *span,
347        }
348    }
349
350    pub fn get_type(&self) -> Option<Type> {
351        match self {
352            Pattern::Identifier { .. } => None,
353            Pattern::Literal { ty, .. } => Some(ty.clone()),
354            Pattern::EnumVariant { ty, .. } => Some(ty.clone()),
355            Pattern::Struct { ty, .. } => Some(ty.clone()),
356            Pattern::WildCard { .. } => None,
357            Pattern::Unit { ty, .. } => Some(ty.clone()),
358            Pattern::Tuple { .. } => None,
359            Pattern::Slice { .. } => None,
360            Pattern::Or { .. } => None,
361            Pattern::AsBinding { pattern, .. } => pattern.get_type(),
362        }
363    }
364
365    pub fn is_identifier(&self) -> bool {
366        matches!(self, Pattern::Identifier { .. } | Pattern::AsBinding { .. })
367    }
368
369    pub fn get_identifier(&self) -> Option<EcoString> {
370        match self {
371            Pattern::Identifier { identifier, .. } => Some(identifier.clone()),
372            Pattern::AsBinding { name, .. } => Some(name.clone()),
373            _ => None,
374        }
375    }
376}
377
378#[derive(Debug, Clone, PartialEq)]
379pub struct StructFieldPattern {
380    pub name: EcoString,
381    pub value: Pattern,
382}
383
384#[derive(Debug, Clone, PartialEq)]
385pub enum TypedPattern {
386    Wildcard,
387    Literal(Literal),
388    /// A qualified const pattern (e.g. `time.Friday`). A value comparison, not
389    /// an enum constructor: `qualified_name` is the resolved constant, `value`
390    /// is its known case-eligible literal when available.
391    Const {
392        qualified_name: EcoString,
393        ty: Type,
394        value: Option<Literal>,
395    },
396    EnumVariant {
397        enum_name: EcoString,
398        variant_name: EcoString,
399        variant_fields: Vec<EnumFieldDefinition>,
400        fields: Vec<TypedPattern>,
401        type_args: Vec<Type>,
402        field_types: Box<[Type]>,
403    },
404    EnumStructVariant {
405        enum_name: EcoString,
406        variant_name: EcoString,
407        variant_fields: Vec<EnumFieldDefinition>,
408        pattern_fields: Vec<(EcoString, TypedPattern)>,
409        type_args: Vec<Type>,
410    },
411    Struct {
412        struct_name: EcoString,
413        struct_fields: Vec<StructFieldDefinition>,
414        pattern_fields: Vec<(EcoString, TypedPattern)>,
415        type_args: Vec<Type>,
416    },
417    Slice {
418        prefix: Vec<TypedPattern>,
419        has_rest: bool,
420        element_type: Type,
421    },
422    Tuple {
423        arity: usize,
424        elements: Vec<TypedPattern>,
425    },
426    Or {
427        alternatives: Vec<TypedPattern>,
428    },
429}
430
431#[derive(Debug, Clone, PartialEq)]
432pub struct FunctionDefinition {
433    pub name: EcoString,
434    pub name_span: Span,
435    pub generics: Vec<Generic>,
436    pub params: Vec<Binding>,
437    pub body: Box<Expression>,
438    pub return_type: Type,
439    pub annotation: Annotation,
440    pub ty: Type,
441}
442
443#[derive(Clone, Copy)]
444pub struct FunctionDefinitionView<'a> {
445    pub name: &'a EcoString,
446    pub name_span: Span,
447    pub generics: &'a [Generic],
448    pub params: &'a [Binding],
449    pub body: &'a Expression,
450    pub return_type: &'a Type,
451}
452
453#[derive(Debug, Clone, PartialEq)]
454pub enum VariantFields {
455    Unit,
456    Tuple(Vec<EnumFieldDefinition>),
457    Struct(Vec<EnumFieldDefinition>),
458}
459
460impl VariantFields {
461    pub fn is_empty(&self) -> bool {
462        match self {
463            VariantFields::Unit => true,
464            VariantFields::Tuple(fields) | VariantFields::Struct(fields) => fields.is_empty(),
465        }
466    }
467
468    pub fn len(&self) -> usize {
469        match self {
470            VariantFields::Unit => 0,
471            VariantFields::Tuple(fields) | VariantFields::Struct(fields) => fields.len(),
472        }
473    }
474
475    pub fn iter(&self) -> std::slice::Iter<'_, EnumFieldDefinition> {
476        match self {
477            VariantFields::Unit => [].iter(),
478            VariantFields::Tuple(fields) | VariantFields::Struct(fields) => fields.iter(),
479        }
480    }
481
482    pub fn is_struct(&self) -> bool {
483        matches!(self, VariantFields::Struct(_))
484    }
485}
486
487impl<'a> IntoIterator for &'a VariantFields {
488    type Item = &'a EnumFieldDefinition;
489    type IntoIter = std::slice::Iter<'a, EnumFieldDefinition>;
490
491    fn into_iter(self) -> Self::IntoIter {
492        self.iter()
493    }
494}
495
496#[derive(Debug, Clone, PartialEq)]
497pub struct EnumVariant {
498    pub doc: Option<String>,
499    pub name: EcoString,
500    pub name_span: Span,
501    pub fields: VariantFields,
502}
503
504#[derive(Debug, Clone, PartialEq)]
505pub struct EnumFieldDefinition {
506    pub name: EcoString,
507    pub name_span: Span,
508    pub annotation: Annotation,
509    pub ty: Type,
510}
511
512#[derive(Debug, Clone, PartialEq)]
513pub struct Attribute {
514    pub name: String,
515    pub args: Vec<AttributeArg>,
516    pub span: Span,
517}
518
519#[derive(Debug, Clone, PartialEq)]
520#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
521pub enum AttributeArg {
522    /// A flag option, e.g., `omitempty`, `skip`, `snake_case`
523    Flag(String),
524    /// A negated flag, e.g., `!omitempty`
525    NegatedFlag(String),
526    /// A quoted string, e.g., `"custom_name"` (name override)
527    String(String),
528    /// A raw backtick literal, e.g., `json:"name,string"`
529    Raw(String),
530}
531
532#[derive(Debug, Clone, Copy, PartialEq)]
533#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
534pub enum StructKind {
535    Record,
536    Tuple,
537}
538
539#[derive(Debug, Clone, PartialEq)]
540pub struct StructFieldDefinition {
541    pub doc: Option<String>,
542    pub attributes: Vec<Attribute>,
543    pub name: EcoString,
544    pub name_span: Span,
545    pub annotation: Annotation,
546    pub visibility: Visibility,
547    pub ty: Type,
548    pub embedded: bool,
549}
550
551#[derive(Debug, Clone, PartialEq)]
552pub struct StructFieldAssignment {
553    pub name: EcoString,
554    pub name_span: Span,
555    pub value: Box<Expression>,
556}
557
558#[derive(Debug, Clone, PartialEq)]
559pub enum StructSpread {
560    None,
561    From(Box<Expression>),
562    ZeroFill { span: Span },
563}
564
565impl StructSpread {
566    pub fn is_none(&self) -> bool {
567        matches!(self, Self::None)
568    }
569
570    pub fn is_some(&self) -> bool {
571        !self.is_none()
572    }
573
574    pub fn span(&self) -> Option<Span> {
575        match self {
576            Self::None => None,
577            Self::From(e) => Some(e.get_span()),
578            Self::ZeroFill { span } => Some(*span),
579        }
580    }
581
582    pub fn as_expression(&self) -> Option<&Expression> {
583        match self {
584            Self::From(e) => Some(e),
585            Self::None | Self::ZeroFill { .. } => None,
586        }
587    }
588}
589
590#[derive(Debug, Clone, PartialEq)]
591#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
592pub enum Annotation {
593    Constructor {
594        name: EcoString,
595        params: Vec<Self>,
596        span: Span,
597    },
598    Function {
599        params: Vec<Self>,
600        return_type: Box<Self>,
601        span: Span,
602    },
603    Tuple {
604        elements: Vec<Self>,
605        span: Span,
606    },
607    Unknown,
608    Opaque {
609        span: Span,
610    },
611}
612
613impl Annotation {
614    pub fn unit() -> Self {
615        Self::Constructor {
616            name: "Unit".into(),
617            params: vec![],
618            span: Span::dummy(),
619        }
620    }
621
622    pub fn get_span(&self) -> Span {
623        match self {
624            Self::Constructor { span, .. } => *span,
625            Self::Function { span, .. } => *span,
626            Self::Tuple { span, .. } => *span,
627            Self::Opaque { span } => *span,
628            Self::Unknown => Span::dummy(),
629        }
630    }
631
632    pub fn get_name(&self) -> Option<String> {
633        match self {
634            Self::Constructor { name, .. } => Some(name.to_string()),
635            _ => None,
636        }
637    }
638
639    pub fn is_unit(&self) -> bool {
640        matches!(self, Self::Constructor { name, params, .. } if name == "Unit" && params.is_empty())
641    }
642
643    pub fn is_unknown(&self) -> bool {
644        matches!(self, Self::Unknown)
645    }
646
647    pub fn is_opaque(&self) -> bool {
648        matches!(self, Self::Opaque { .. })
649    }
650}
651
652#[derive(Debug, Clone, PartialEq)]
653pub struct Generic {
654    pub name: EcoString,
655    pub bounds: Vec<Annotation>,
656    pub span: Span,
657}
658
659#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
660#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
661pub struct Span {
662    pub file_id: u32,
663    pub byte_offset: u32,
664    pub byte_length: u32,
665}
666
667impl Span {
668    pub fn new(file_id: u32, byte_offset: u32, byte_length: u32) -> Self {
669        Span {
670            file_id,
671            byte_offset,
672            byte_length,
673        }
674    }
675
676    pub fn dummy() -> Self {
677        Span {
678            file_id: 0,
679            byte_offset: 0,
680            byte_length: 0,
681        }
682    }
683
684    pub fn is_dummy(&self) -> bool {
685        self.byte_length == 0
686    }
687
688    pub fn end(&self) -> u32 {
689        self.byte_offset + self.byte_length
690    }
691
692    pub fn merge(self, other: Span) -> Span {
693        Span::new(
694            self.file_id,
695            self.byte_offset,
696            other.end() - self.byte_offset,
697        )
698    }
699}
700
701#[derive(Debug, Clone, PartialEq)]
702#[allow(clippy::large_enum_variant)]
703pub enum Expression {
704    Literal {
705        literal: Literal,
706        ty: Type,
707        span: Span,
708    },
709    Function {
710        doc: Option<String>,
711        attributes: Vec<Attribute>,
712        name: EcoString,
713        name_span: Span,
714        generics: Vec<Generic>,
715        params: Vec<Binding>,
716        return_annotation: Annotation,
717        return_type: Type,
718        visibility: Visibility,
719        body: Box<Expression>,
720        ty: Type,
721        span: Span,
722    },
723    Lambda {
724        params: Vec<Binding>,
725        return_annotation: Annotation,
726        body: Box<Expression>,
727        ty: Type,
728        span: Span,
729    },
730    Block {
731        items: Vec<Expression>,
732        ty: Type,
733        span: Span,
734    },
735    Let {
736        binding: Box<Binding>,
737        value: Box<Expression>,
738        mutable: bool,
739        mut_span: Option<Span>,
740        else_block: Option<Box<Expression>>,
741        else_span: Option<Span>,
742        typed_pattern: Option<TypedPattern>,
743        ty: Type,
744        span: Span,
745    },
746    Identifier {
747        value: EcoString,
748        ty: Type,
749        span: Span,
750        binding_id: Option<BindingId>,
751        qualified: Option<EcoString>,
752    },
753    Call {
754        expression: Box<Expression>,
755        args: Vec<Expression>,
756        spread: Box<Option<Expression>>,
757        type_args: Vec<Annotation>,
758        ty: Type,
759        span: Span,
760        call_kind: Option<CallKind>,
761    },
762    If {
763        condition: Box<Expression>,
764        consequence: Box<Expression>,
765        alternative: Box<Expression>,
766        ty: Type,
767        span: Span,
768    },
769    IfLet {
770        pattern: Pattern,
771        scrutinee: Box<Expression>,
772        consequence: Box<Expression>,
773        alternative: Box<Expression>,
774        typed_pattern: Option<TypedPattern>,
775        else_span: Option<Span>,
776        ty: Type,
777        span: Span,
778    },
779    Match {
780        subject: Box<Expression>,
781        arms: Vec<MatchArm>,
782        origin: MatchOrigin,
783        ty: Type,
784        span: Span,
785    },
786    Tuple {
787        elements: Vec<Expression>,
788        ty: Type,
789        span: Span,
790    },
791    StructCall {
792        name: EcoString,
793        field_assignments: Vec<StructFieldAssignment>,
794        spread: StructSpread,
795        ty: Type,
796        span: Span,
797    },
798    DotAccess {
799        expression: Box<Expression>,
800        member: EcoString,
801        ty: Type,
802        span: Span,
803        dot_access_kind: Option<DotAccessKind>,
804        receiver_coercion: Option<ReceiverCoercion>,
805    },
806    Assignment {
807        target: Box<Expression>,
808        value: Box<Expression>,
809        compound_operator: Option<BinaryOperator>,
810        span: Span,
811    },
812    Return {
813        expression: Box<Expression>,
814        ty: Type,
815        span: Span,
816    },
817    Propagate {
818        expression: Box<Expression>,
819        ty: Type,
820        span: Span,
821    },
822    TryBlock {
823        items: Vec<Expression>,
824        ty: Type,
825        try_keyword_span: Span,
826        span: Span,
827    },
828    RecoverBlock {
829        items: Vec<Expression>,
830        ty: Type,
831        recover_keyword_span: Span,
832        span: Span,
833    },
834    ImplBlock {
835        annotation: Annotation,
836        receiver_name: EcoString,
837        methods: Vec<Expression>,
838        generics: Vec<Generic>,
839        ty: Type,
840        span: Span,
841    },
842    Binary {
843        operator: BinaryOperator,
844        left: Box<Expression>,
845        right: Box<Expression>,
846        ty: Type,
847        span: Span,
848    },
849    Unary {
850        operator: UnaryOperator,
851        expression: Box<Expression>,
852        ty: Type,
853        span: Span,
854    },
855    Paren {
856        expression: Box<Expression>,
857        ty: Type,
858        span: Span,
859    },
860    Const {
861        doc: Option<String>,
862        identifier: EcoString,
863        identifier_span: Span,
864        annotation: Option<Annotation>,
865        expression: Box<Expression>,
866        visibility: Visibility,
867        ty: Type,
868        span: Span,
869    },
870    VariableDeclaration {
871        doc: Option<String>,
872        name: EcoString,
873        name_span: Span,
874        annotation: Annotation,
875        visibility: Visibility,
876        ty: Type,
877        span: Span,
878    },
879    RawGo {
880        text: String,
881    },
882    Loop {
883        body: Box<Expression>,
884        ty: Type,
885        span: Span,
886        needs_label: bool,
887    },
888    While {
889        condition: Box<Expression>,
890        body: Box<Expression>,
891        span: Span,
892        needs_label: bool,
893    },
894    WhileLet {
895        pattern: Pattern,
896        scrutinee: Box<Expression>,
897        body: Box<Expression>,
898        typed_pattern: Option<TypedPattern>,
899        span: Span,
900        needs_label: bool,
901    },
902    For {
903        binding: Box<Binding>,
904        iterable: Box<Expression>,
905        body: Box<Expression>,
906        span: Span,
907        needs_label: bool,
908        binding_id: Option<BindingId>,
909    },
910    Break {
911        value: Option<Box<Expression>>,
912        span: Span,
913    },
914    Continue {
915        span: Span,
916    },
917    Enum {
918        doc: Option<String>,
919        attributes: Vec<Attribute>,
920        name: EcoString,
921        name_span: Span,
922        generics: Vec<Generic>,
923        variants: Vec<EnumVariant>,
924        visibility: Visibility,
925        span: Span,
926    },
927    Struct {
928        doc: Option<String>,
929        attributes: Vec<Attribute>,
930        name: EcoString,
931        name_span: Span,
932        generics: Vec<Generic>,
933        fields: Vec<StructFieldDefinition>,
934        kind: StructKind,
935        visibility: Visibility,
936        span: Span,
937    },
938    TypeAlias {
939        doc: Option<String>,
940        attributes: Vec<Attribute>,
941        name: EcoString,
942        name_span: Span,
943        generics: Vec<Generic>,
944        annotation: Annotation,
945        ty: Type,
946        visibility: Visibility,
947        span: Span,
948    },
949    ModuleImport {
950        name: EcoString,
951        name_span: Span,
952        alias: Option<ImportAlias>,
953        span: Span,
954    },
955    Reference {
956        expression: Box<Expression>,
957        ty: Type,
958        span: Span,
959    },
960    Interface {
961        doc: Option<String>,
962        name: EcoString,
963        name_span: Span,
964        generics: Vec<Generic>,
965        parents: Vec<ParentInterface>,
966        method_signatures: Vec<Expression>,
967        visibility: Visibility,
968        span: Span,
969    },
970    IndexedAccess {
971        expression: Box<Expression>,
972        index: Box<Expression>,
973        ty: Type,
974        span: Span,
975        from_colon_syntax: bool,
976    },
977    Task {
978        expression: Box<Expression>,
979        ty: Type,
980        span: Span,
981    },
982    Defer {
983        expression: Box<Expression>,
984        ty: Type,
985        span: Span,
986    },
987    Select {
988        arms: Vec<SelectArm>,
989        ty: Type,
990        span: Span,
991    },
992    Unit {
993        ty: Type,
994        span: Span,
995    },
996    Range {
997        start: Option<Box<Expression>>,
998        end: Option<Box<Expression>>,
999        inclusive: bool,
1000        ty: Type,
1001        span: Span,
1002    },
1003    Cast {
1004        expression: Box<Expression>,
1005        target_type: Annotation,
1006        ty: Type,
1007        span: Span,
1008    },
1009    NoOp,
1010}
1011
1012/// Dataless variant index of [`Expression`], usable as an array index.
1013#[derive(Clone, Copy)]
1014pub enum ExpressionKind {
1015    Literal,
1016    Function,
1017    Lambda,
1018    Block,
1019    Let,
1020    Identifier,
1021    Call,
1022    If,
1023    IfLet,
1024    Match,
1025    Tuple,
1026    StructCall,
1027    DotAccess,
1028    Assignment,
1029    Return,
1030    Propagate,
1031    TryBlock,
1032    RecoverBlock,
1033    ImplBlock,
1034    Binary,
1035    Unary,
1036    Paren,
1037    Const,
1038    VariableDeclaration,
1039    RawGo,
1040    Loop,
1041    While,
1042    WhileLet,
1043    For,
1044    Break,
1045    Continue,
1046    Enum,
1047    Struct,
1048    TypeAlias,
1049    ModuleImport,
1050    Reference,
1051    Interface,
1052    IndexedAccess,
1053    Task,
1054    Defer,
1055    Select,
1056    Unit,
1057    Range,
1058    Cast,
1059    NoOp,
1060}
1061
1062impl ExpressionKind {
1063    // Relies on `NoOp` staying the last variant.
1064    pub const COUNT: usize = ExpressionKind::NoOp as usize + 1;
1065}
1066
1067impl Expression {
1068    pub fn kind(&self) -> ExpressionKind {
1069        match self {
1070            Expression::Literal { .. } => ExpressionKind::Literal,
1071            Expression::Function { .. } => ExpressionKind::Function,
1072            Expression::Lambda { .. } => ExpressionKind::Lambda,
1073            Expression::Block { .. } => ExpressionKind::Block,
1074            Expression::Let { .. } => ExpressionKind::Let,
1075            Expression::Identifier { .. } => ExpressionKind::Identifier,
1076            Expression::Call { .. } => ExpressionKind::Call,
1077            Expression::If { .. } => ExpressionKind::If,
1078            Expression::IfLet { .. } => ExpressionKind::IfLet,
1079            Expression::Match { .. } => ExpressionKind::Match,
1080            Expression::Tuple { .. } => ExpressionKind::Tuple,
1081            Expression::StructCall { .. } => ExpressionKind::StructCall,
1082            Expression::DotAccess { .. } => ExpressionKind::DotAccess,
1083            Expression::Assignment { .. } => ExpressionKind::Assignment,
1084            Expression::Return { .. } => ExpressionKind::Return,
1085            Expression::Propagate { .. } => ExpressionKind::Propagate,
1086            Expression::TryBlock { .. } => ExpressionKind::TryBlock,
1087            Expression::RecoverBlock { .. } => ExpressionKind::RecoverBlock,
1088            Expression::ImplBlock { .. } => ExpressionKind::ImplBlock,
1089            Expression::Binary { .. } => ExpressionKind::Binary,
1090            Expression::Unary { .. } => ExpressionKind::Unary,
1091            Expression::Paren { .. } => ExpressionKind::Paren,
1092            Expression::Const { .. } => ExpressionKind::Const,
1093            Expression::VariableDeclaration { .. } => ExpressionKind::VariableDeclaration,
1094            Expression::RawGo { .. } => ExpressionKind::RawGo,
1095            Expression::Loop { .. } => ExpressionKind::Loop,
1096            Expression::While { .. } => ExpressionKind::While,
1097            Expression::WhileLet { .. } => ExpressionKind::WhileLet,
1098            Expression::For { .. } => ExpressionKind::For,
1099            Expression::Break { .. } => ExpressionKind::Break,
1100            Expression::Continue { .. } => ExpressionKind::Continue,
1101            Expression::Enum { .. } => ExpressionKind::Enum,
1102            Expression::Struct { .. } => ExpressionKind::Struct,
1103            Expression::TypeAlias { .. } => ExpressionKind::TypeAlias,
1104            Expression::ModuleImport { .. } => ExpressionKind::ModuleImport,
1105            Expression::Reference { .. } => ExpressionKind::Reference,
1106            Expression::Interface { .. } => ExpressionKind::Interface,
1107            Expression::IndexedAccess { .. } => ExpressionKind::IndexedAccess,
1108            Expression::Task { .. } => ExpressionKind::Task,
1109            Expression::Defer { .. } => ExpressionKind::Defer,
1110            Expression::Select { .. } => ExpressionKind::Select,
1111            Expression::Unit { .. } => ExpressionKind::Unit,
1112            Expression::Range { .. } => ExpressionKind::Range,
1113            Expression::Cast { .. } => ExpressionKind::Cast,
1114            Expression::NoOp => ExpressionKind::NoOp,
1115        }
1116    }
1117
1118    pub fn is_noop(&self) -> bool {
1119        matches!(self, Expression::NoOp)
1120    }
1121
1122    pub fn is_block(&self) -> bool {
1123        matches!(self, Expression::Block { .. })
1124    }
1125
1126    pub fn is_range(&self) -> bool {
1127        matches!(self, Expression::Range { .. })
1128    }
1129
1130    pub fn is_conditional(&self) -> bool {
1131        matches!(
1132            self,
1133            Expression::If { .. }
1134                | Expression::IfLet { .. }
1135                | Expression::Match {
1136                    origin: MatchOrigin::IfLet { .. },
1137                    ..
1138                }
1139        )
1140    }
1141
1142    pub fn is_control_flow(&self) -> bool {
1143        matches!(
1144            self,
1145            Expression::If { .. }
1146                | Expression::Match { .. }
1147                | Expression::Select { .. }
1148                | Expression::For { .. }
1149                | Expression::While { .. }
1150                | Expression::WhileLet { .. }
1151                | Expression::Loop { .. }
1152        )
1153    }
1154
1155    pub fn callee_name(&self) -> Option<String> {
1156        let Expression::Call { expression, .. } = self else {
1157            return None;
1158        };
1159        match expression.as_ref() {
1160            Expression::Identifier { value, .. } => Some(value.to_string()),
1161            Expression::DotAccess {
1162                expression: base,
1163                member,
1164                ..
1165            } => {
1166                if let Expression::Identifier { value, .. } = base.as_ref() {
1167                    Some(format!("{}.{}", value, member))
1168                } else {
1169                    None
1170                }
1171            }
1172            _ => None,
1173        }
1174    }
1175
1176    pub fn to_function_signature(&self) -> FunctionDefinition {
1177        match self {
1178            Expression::Function {
1179                name,
1180                name_span,
1181                generics,
1182                params,
1183                return_annotation,
1184                return_type,
1185                ty,
1186                ..
1187            } => FunctionDefinition {
1188                name: name.clone(),
1189                name_span: *name_span,
1190                generics: generics.clone(),
1191                params: params.clone(),
1192                body: Box::new(Expression::NoOp),
1193                return_type: return_type.clone(),
1194                annotation: return_annotation.clone(),
1195                ty: ty.clone(),
1196            },
1197            _ => panic!("to_function_signature called on non-Function expression"),
1198        }
1199    }
1200
1201    pub fn function_definition_view(&self) -> FunctionDefinitionView<'_> {
1202        match self {
1203            Expression::Function {
1204                name,
1205                name_span,
1206                generics,
1207                params,
1208                return_type,
1209                body,
1210                ..
1211            } => FunctionDefinitionView {
1212                name,
1213                name_span: *name_span,
1214                generics,
1215                params,
1216                body,
1217                return_type,
1218            },
1219            _ => panic!("function_definition_view called on non-Function expression"),
1220        }
1221    }
1222
1223    pub fn as_option_constructor(&self) -> Option<std::result::Result<(), ()>> {
1224        let variant = match self {
1225            Expression::Identifier { value, .. } => Some(value.as_str()),
1226            _ => None,
1227        }?;
1228
1229        match variant {
1230            "Option.Some" | "Some" => Some(Ok(())),
1231            "Option.None" | "None" => Some(Err(())),
1232            _ => None,
1233        }
1234    }
1235
1236    pub fn is_none_literal(&self) -> bool {
1237        matches!(self.as_option_constructor(), Some(Err(())))
1238    }
1239
1240    pub fn as_result_constructor(&self) -> Option<std::result::Result<(), ()>> {
1241        let variant = match self {
1242            Expression::Identifier { value, .. } => Some(value.as_str()),
1243            _ => None,
1244        }?;
1245
1246        match variant {
1247            "Result.Ok" | "Ok" => Some(Ok(())),
1248            "Result.Err" | "Err" => Some(Err(())),
1249            _ => None,
1250        }
1251    }
1252
1253    pub fn as_partial_constructor(&self) -> Option<&'static str> {
1254        let variant = match self {
1255            Expression::Identifier { value, .. } => Some(value.as_str()),
1256            _ => None,
1257        }?;
1258
1259        match variant {
1260            "Partial.Ok" => Some("Ok"),
1261            "Partial.Err" => Some("Err"),
1262            "Partial.Both" => Some("Both"),
1263            _ => None,
1264        }
1265    }
1266
1267    pub fn get_type(&self) -> Type {
1268        match self {
1269            Self::Literal { ty, .. }
1270            | Self::Function { ty, .. }
1271            | Self::Lambda { ty, .. }
1272            | Self::Block { ty, .. }
1273            | Self::Let { ty, .. }
1274            | Self::Identifier { ty, .. }
1275            | Self::Call { ty, .. }
1276            | Self::If { ty, .. }
1277            | Self::IfLet { ty, .. }
1278            | Self::Match { ty, .. }
1279            | Self::Tuple { ty, .. }
1280            | Self::StructCall { ty, .. }
1281            | Self::DotAccess { ty, .. }
1282            | Self::Return { ty, .. }
1283            | Self::Propagate { ty, .. }
1284            | Self::TryBlock { ty, .. }
1285            | Self::RecoverBlock { ty, .. }
1286            | Self::Binary { ty, .. }
1287            | Self::Paren { ty, .. }
1288            | Self::Unary { ty, .. }
1289            | Self::Const { ty, .. }
1290            | Self::VariableDeclaration { ty, .. }
1291            | Self::Defer { ty, .. }
1292            | Self::Reference { ty, .. }
1293            | Self::IndexedAccess { ty, .. }
1294            | Self::Task { ty, .. }
1295            | Self::Select { ty, .. }
1296            | Self::Unit { ty, .. }
1297            | Self::Loop { ty, .. }
1298            | Self::Range { ty, .. }
1299            | Self::Cast { ty, .. } => ty.clone(),
1300            Self::Enum { .. }
1301            | Self::Struct { .. }
1302            | Self::Assignment { .. }
1303            | Self::ImplBlock { .. }
1304            | Self::TypeAlias { .. }
1305            | Self::ModuleImport { .. }
1306            | Self::Interface { .. }
1307            | Self::NoOp
1308            | Self::RawGo { .. }
1309            | Self::While { .. }
1310            | Self::WhileLet { .. }
1311            | Self::For { .. } => Type::ignored(),
1312            Self::Break { .. } | Self::Continue { .. } => Type::Never,
1313        }
1314    }
1315
1316    pub fn get_span(&self) -> Span {
1317        match self {
1318            Self::Literal { span, .. }
1319            | Self::Function { span, .. }
1320            | Self::Lambda { span, .. }
1321            | Self::Block { span, .. }
1322            | Self::Let { span, .. }
1323            | Self::Identifier { span, .. }
1324            | Self::Call { span, .. }
1325            | Self::If { span, .. }
1326            | Self::IfLet { span, .. }
1327            | Self::Match { span, .. }
1328            | Self::Tuple { span, .. }
1329            | Self::Enum { span, .. }
1330            | Self::Struct { span, .. }
1331            | Self::StructCall { span, .. }
1332            | Self::DotAccess { span, .. }
1333            | Self::Assignment { span, .. }
1334            | Self::Return { span, .. }
1335            | Self::Propagate { span, .. }
1336            | Self::TryBlock { span, .. }
1337            | Self::RecoverBlock { span, .. }
1338            | Self::ImplBlock { span, .. }
1339            | Self::Binary { span, .. }
1340            | Self::Paren { span, .. }
1341            | Self::Unary { span, .. }
1342            | Self::Const { span, .. }
1343            | Self::VariableDeclaration { span, .. }
1344            | Self::Defer { span, .. }
1345            | Self::Reference { span, .. }
1346            | Self::IndexedAccess { span, .. }
1347            | Self::Task { span, .. }
1348            | Self::Select { span, .. }
1349            | Self::Loop { span, .. }
1350            | Self::TypeAlias { span, .. }
1351            | Self::ModuleImport { span, .. }
1352            | Self::Interface { span, .. }
1353            | Self::Unit { span, .. }
1354            | Self::While { span, .. }
1355            | Self::WhileLet { span, .. }
1356            | Self::For { span, .. }
1357            | Self::Break { span, .. }
1358            | Self::Continue { span, .. }
1359            | Self::Range { span, .. }
1360            | Self::Cast { span, .. } => *span,
1361            Self::NoOp | Self::RawGo { .. } => Span::dummy(),
1362        }
1363    }
1364
1365    pub fn contains_break(&self) -> bool {
1366        match self {
1367            Expression::Break { .. } => true,
1368
1369            Expression::Loop { .. }
1370            | Expression::While { .. }
1371            | Expression::WhileLet { .. }
1372            | Expression::For { .. } => false,
1373
1374            Expression::Block { items, .. } => items.iter().any(Self::contains_break),
1375
1376            Expression::TryBlock { items, .. } => items.iter().any(Self::contains_break),
1377            Expression::RecoverBlock { items, .. } => items.iter().any(Self::contains_break),
1378
1379            Expression::If {
1380                condition,
1381                consequence,
1382                alternative,
1383                ..
1384            } => {
1385                condition.contains_break()
1386                    || consequence.contains_break()
1387                    || alternative.contains_break()
1388            }
1389
1390            Expression::IfLet {
1391                scrutinee,
1392                consequence,
1393                alternative,
1394                ..
1395            } => {
1396                scrutinee.contains_break()
1397                    || consequence.contains_break()
1398                    || alternative.contains_break()
1399            }
1400
1401            Expression::Match { subject, arms, .. } => {
1402                subject.contains_break() || arms.iter().any(|arm| arm.expression.contains_break())
1403            }
1404
1405            Expression::Paren { expression, .. } => expression.contains_break(),
1406
1407            Expression::Binary { left, right, .. } => {
1408                left.contains_break() || right.contains_break()
1409            }
1410
1411            Expression::Unary { expression, .. } => expression.contains_break(),
1412
1413            Expression::Call {
1414                expression,
1415                args,
1416                spread,
1417                ..
1418            } => {
1419                expression.contains_break()
1420                    || args.iter().any(Self::contains_break)
1421                    || spread.as_ref().as_ref().is_some_and(Self::contains_break)
1422            }
1423
1424            Expression::Function { .. } | Expression::Lambda { .. } => false,
1425
1426            Expression::Select { arms, .. } => arms.iter().any(|arm| match &arm.pattern {
1427                SelectArmPattern::Receive { body, .. } => body.contains_break(),
1428                SelectArmPattern::Send { body, .. } => body.contains_break(),
1429                SelectArmPattern::MatchReceive { arms, .. } => {
1430                    arms.iter().any(|a| a.expression.contains_break())
1431                }
1432                SelectArmPattern::WildCard { body } => body.contains_break(),
1433            }),
1434
1435            Expression::Cast { expression, .. } => expression.contains_break(),
1436
1437            Expression::Let {
1438                value, else_block, ..
1439            } => value.contains_break() || else_block.as_ref().is_some_and(|e| e.contains_break()),
1440
1441            Expression::Assignment { value, .. } => value.contains_break(),
1442
1443            _ => false,
1444        }
1445    }
1446
1447    pub fn diverges(&self) -> Option<DeadCodeCause> {
1448        match self {
1449            Expression::Return { .. } => Some(DeadCodeCause::Return),
1450            Expression::Break { .. } => Some(DeadCodeCause::Break),
1451            Expression::Continue { .. } => Some(DeadCodeCause::Continue),
1452
1453            Expression::If {
1454                consequence,
1455                alternative,
1456                ..
1457            } => {
1458                if consequence.diverges().is_some() && alternative.diverges().is_some() {
1459                    Some(DeadCodeCause::DivergingIf)
1460                } else {
1461                    None
1462                }
1463            }
1464
1465            Expression::IfLet {
1466                consequence,
1467                alternative,
1468                ..
1469            } => {
1470                if consequence.diverges().is_some() && alternative.diverges().is_some() {
1471                    Some(DeadCodeCause::DivergingIf)
1472                } else {
1473                    None
1474                }
1475            }
1476
1477            Expression::Match { arms, .. } => {
1478                if !arms.is_empty() && arms.iter().all(|arm| arm.expression.diverges().is_some()) {
1479                    Some(DeadCodeCause::DivergingMatch)
1480                } else {
1481                    None
1482                }
1483            }
1484
1485            Expression::Block { items, .. } => {
1486                for item in items {
1487                    if let Some(cause) = item.diverges() {
1488                        return Some(cause);
1489                    }
1490                }
1491                None
1492            }
1493
1494            Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1495                for item in items {
1496                    if let Some(cause) = item.diverges() {
1497                        return Some(cause);
1498                    }
1499                }
1500                None
1501            }
1502
1503            Expression::Paren { expression, .. } | Expression::Cast { expression, .. } => {
1504                expression.diverges()
1505            }
1506
1507            Expression::Loop { body, .. } => {
1508                if !body.contains_break() {
1509                    Some(DeadCodeCause::InfiniteLoop)
1510                } else {
1511                    None
1512                }
1513            }
1514
1515            Expression::Call { ty, .. } if ty.is_never() => Some(DeadCodeCause::DivergingCall),
1516
1517            _ => None,
1518        }
1519    }
1520
1521    /// Returns references to all direct child expressions.
1522    ///
1523    /// This is the single source of truth for expression tree recursion. Use this
1524    /// instead of writing per-variant match arms when you need to walk an expression tree.
1525    pub fn children(&self) -> Children<'_> {
1526        match self {
1527            Expression::Literal { literal, .. } => match literal {
1528                Literal::Slice(elements) => elements.iter().collect(),
1529                Literal::FormatString(parts) => parts
1530                    .iter()
1531                    .filter_map(|p| match p {
1532                        FormatStringPart::Expression(e) => Some(e.as_ref()),
1533                        FormatStringPart::Text(_) => None,
1534                    })
1535                    .collect(),
1536                _ => Children::new(),
1537            },
1538            Expression::Function { body, .. } => children![body],
1539            Expression::Lambda { body, .. } => children![body],
1540            Expression::Block { items, .. } => items.iter().collect(),
1541            Expression::Let {
1542                value, else_block, ..
1543            } => {
1544                let mut c = children![value.as_ref()];
1545                if let Some(eb) = else_block {
1546                    c.push(eb);
1547                }
1548                c
1549            }
1550            Expression::Identifier { .. } => Children::new(),
1551            Expression::Call {
1552                expression,
1553                args,
1554                spread,
1555                ..
1556            } => {
1557                let mut c = children![expression.as_ref()];
1558                c.extend(args);
1559                if let Some(s) = spread.as_ref() {
1560                    c.push(s);
1561                }
1562                c
1563            }
1564            Expression::If {
1565                condition,
1566                consequence,
1567                alternative,
1568                ..
1569            } => children![condition, consequence, alternative],
1570            Expression::IfLet {
1571                scrutinee,
1572                consequence,
1573                alternative,
1574                ..
1575            } => children![scrutinee, consequence, alternative],
1576            Expression::Match { subject, arms, .. } => {
1577                let mut c = children![subject.as_ref()];
1578                for arm in arms {
1579                    if let Some(guard) = &arm.guard {
1580                        c.push(guard);
1581                    }
1582                    c.push(&arm.expression);
1583                }
1584                c
1585            }
1586            Expression::Tuple { elements, .. } => elements.iter().collect(),
1587            Expression::StructCall {
1588                field_assignments,
1589                spread,
1590                ..
1591            } => {
1592                let mut c: Children = field_assignments.iter().map(|f| f.value.as_ref()).collect();
1593                if let Some(s) = spread.as_expression() {
1594                    c.push(s);
1595                }
1596                c
1597            }
1598            Expression::DotAccess { expression, .. } => children![expression],
1599            Expression::Assignment { target, value, .. } => children![target, value],
1600            Expression::Return { expression, .. } => children![expression],
1601            Expression::Propagate { expression, .. } => children![expression],
1602            Expression::TryBlock { items, .. } | Expression::RecoverBlock { items, .. } => {
1603                items.iter().collect()
1604            }
1605            Expression::ImplBlock { methods, .. } => methods.iter().collect(),
1606            Expression::Binary { left, right, .. } => children![left, right],
1607            Expression::Unary { expression, .. } => children![expression],
1608            Expression::Paren { expression, .. } => children![expression],
1609            Expression::Const { expression, .. } => children![expression],
1610            Expression::Loop { body, .. } => children![body],
1611            Expression::While {
1612                condition, body, ..
1613            } => children![condition, body],
1614            Expression::WhileLet {
1615                scrutinee, body, ..
1616            } => children![scrutinee, body],
1617            Expression::For { iterable, body, .. } => children![iterable, body],
1618            Expression::Break { value, .. } => value
1619                .as_ref()
1620                .map(|v| children![v.as_ref()])
1621                .unwrap_or_default(),
1622            Expression::Reference { expression, .. } => children![expression],
1623            Expression::IndexedAccess {
1624                expression, index, ..
1625            } => children![expression, index],
1626            Expression::Task { expression, .. } => children![expression],
1627            Expression::Defer { expression, .. } => children![expression],
1628            Expression::Select { arms, .. } => {
1629                let mut c = Children::new();
1630                for arm in arms {
1631                    match &arm.pattern {
1632                        SelectArmPattern::Receive {
1633                            receive_expression,
1634                            body,
1635                            ..
1636                        } => {
1637                            c.push(receive_expression.as_ref());
1638                            c.push(body.as_ref());
1639                        }
1640                        SelectArmPattern::Send {
1641                            send_expression,
1642                            body,
1643                        } => {
1644                            c.push(send_expression.as_ref());
1645                            c.push(body.as_ref());
1646                        }
1647                        SelectArmPattern::MatchReceive {
1648                            receive_expression,
1649                            arms: match_arms,
1650                        } => {
1651                            c.push(receive_expression.as_ref());
1652                            for ma in match_arms {
1653                                if let Some(guard) = &ma.guard {
1654                                    c.push(guard);
1655                                }
1656                                c.push(&ma.expression);
1657                            }
1658                        }
1659                        SelectArmPattern::WildCard { body } => {
1660                            c.push(body.as_ref());
1661                        }
1662                    }
1663                }
1664                c
1665            }
1666            Expression::Range { start, end, .. } => {
1667                let mut c = Children::new();
1668                if let Some(s) = start {
1669                    c.push(s.as_ref());
1670                }
1671                if let Some(e) = end {
1672                    c.push(e.as_ref());
1673                }
1674                c
1675            }
1676            Expression::Cast { expression, .. } => children![expression],
1677            Expression::Interface {
1678                method_signatures, ..
1679            } => method_signatures.iter().collect(),
1680            Expression::Unit { .. }
1681            | Expression::Continue { .. }
1682            | Expression::Enum { .. }
1683            | Expression::Struct { .. }
1684            | Expression::TypeAlias { .. }
1685            | Expression::VariableDeclaration { .. }
1686            | Expression::ModuleImport { .. }
1687            | Expression::RawGo { .. }
1688            | Expression::NoOp => Children::new(),
1689        }
1690    }
1691
1692    pub fn unwrap_parens(&self) -> &Expression {
1693        match self {
1694            Expression::Paren { expression, .. } => expression.unwrap_parens(),
1695            other => other,
1696        }
1697    }
1698
1699    pub fn binding_id(&self) -> Option<BindingId> {
1700        match self.unwrap_parens() {
1701            Expression::Identifier { binding_id, .. } => *binding_id,
1702            _ => None,
1703        }
1704    }
1705
1706    pub fn as_integer(&self) -> Option<u64> {
1707        match self.unwrap_parens() {
1708            Expression::Literal {
1709                literal: Literal::Integer { value, .. },
1710                ..
1711            } => Some(*value),
1712            _ => None,
1713        }
1714    }
1715
1716    /// Inner expression of an explicit `x.*` deref, or `None` for anything else.
1717    #[inline]
1718    pub fn deref_inner(&self) -> Option<&Expression> {
1719        match self {
1720            Expression::Unary {
1721                operator: UnaryOperator::Deref,
1722                expression,
1723                ..
1724            } => Some(expression),
1725            _ => None,
1726        }
1727    }
1728
1729    pub fn as_dotted_path(&self) -> Option<String> {
1730        match self {
1731            Expression::Identifier { value, .. } => Some(value.to_string()),
1732            Expression::DotAccess {
1733                expression, member, ..
1734            } => Some(format!("{}.{}", expression.as_dotted_path()?, member)),
1735            _ => None,
1736        }
1737    }
1738
1739    pub fn root_identifier(&self) -> Option<&str> {
1740        match self {
1741            Expression::Identifier { value, .. } => Some(value),
1742            Expression::DotAccess { expression, .. } => expression.root_identifier(),
1743            _ => None,
1744        }
1745    }
1746
1747    pub fn is_empty_collection(&self) -> bool {
1748        matches!(
1749            self,
1750            Expression::Literal {
1751                literal: Literal::Slice(elements),
1752                ..
1753            } if elements.is_empty()
1754        )
1755    }
1756
1757    pub fn is_all_literals(&self) -> bool {
1758        match self.unwrap_parens() {
1759            Expression::Literal { literal, .. } => match literal {
1760                Literal::Slice(elements) => elements.iter().all(|e| e.is_all_literals()),
1761                Literal::FormatString(parts) => parts.iter().all(|p| match p {
1762                    FormatStringPart::Text(_) => true,
1763                    FormatStringPart::Expression(e) => e.is_all_literals(),
1764                }),
1765                _ => true,
1766            },
1767            Expression::Tuple { elements, .. } => elements.iter().all(|e| e.is_all_literals()),
1768            Expression::Unit { .. } => true,
1769            _ => false,
1770        }
1771    }
1772
1773    pub fn get_var_name(&self) -> Option<String> {
1774        match self {
1775            Expression::Identifier { value, .. } => Some(value.to_string()),
1776            Expression::DotAccess { expression, .. } => expression.get_var_name(),
1777            Expression::Assignment { target, .. } => target.get_var_name(),
1778            Expression::IndexedAccess { expression, .. } => expression.get_var_name(),
1779            Expression::Paren { expression, .. } => expression.get_var_name(),
1780            Expression::Reference { expression, .. } => expression.get_var_name(),
1781            Expression::Unary {
1782                operator,
1783                expression,
1784                ..
1785            } => {
1786                if operator == &UnaryOperator::Deref {
1787                    expression.get_var_name()
1788                } else {
1789                    None
1790                }
1791            }
1792            _ => None,
1793        }
1794    }
1795
1796    pub fn is_function(&self) -> bool {
1797        matches!(self, Expression::Function { .. })
1798    }
1799
1800    pub fn set_public(self) -> Self {
1801        match self {
1802            Expression::Enum {
1803                doc,
1804                attributes,
1805                name,
1806                name_span,
1807                generics,
1808                variants,
1809                span,
1810                ..
1811            } => Expression::Enum {
1812                doc,
1813                attributes,
1814                name,
1815                name_span,
1816                generics,
1817                variants,
1818                visibility: Visibility::Public,
1819                span,
1820            },
1821            Expression::Struct {
1822                doc,
1823                attributes,
1824                name,
1825                name_span,
1826                generics,
1827                fields,
1828                kind,
1829                span,
1830                ..
1831            } => {
1832                let fields = if kind == StructKind::Tuple {
1833                    fields
1834                        .into_iter()
1835                        .map(|f| StructFieldDefinition {
1836                            visibility: Visibility::Public,
1837                            ..f
1838                        })
1839                        .collect()
1840                } else {
1841                    fields
1842                };
1843                Expression::Struct {
1844                    doc,
1845                    attributes,
1846                    name,
1847                    name_span,
1848                    generics,
1849                    fields,
1850                    kind,
1851                    visibility: Visibility::Public,
1852                    span,
1853                }
1854            }
1855            Expression::Function {
1856                doc,
1857                attributes,
1858                name,
1859                name_span,
1860                generics,
1861                params,
1862                return_annotation,
1863                return_type,
1864                body,
1865                ty,
1866                span,
1867                ..
1868            } => Expression::Function {
1869                doc,
1870                attributes,
1871                name,
1872                name_span,
1873                generics,
1874                params,
1875                return_annotation,
1876                return_type,
1877                visibility: Visibility::Public,
1878                body,
1879                ty,
1880                span,
1881            },
1882            Expression::Const {
1883                doc,
1884                identifier,
1885                identifier_span,
1886                annotation,
1887                expression,
1888                ty,
1889                span,
1890                ..
1891            } => Expression::Const {
1892                doc,
1893                identifier,
1894                identifier_span,
1895                annotation,
1896                expression,
1897                visibility: Visibility::Public,
1898                ty,
1899                span,
1900            },
1901            Expression::VariableDeclaration {
1902                doc,
1903                name,
1904                name_span,
1905                annotation,
1906                ty,
1907                span,
1908                ..
1909            } => Expression::VariableDeclaration {
1910                doc,
1911                name,
1912                name_span,
1913                annotation,
1914                visibility: Visibility::Public,
1915                ty,
1916                span,
1917            },
1918            Expression::TypeAlias {
1919                doc,
1920                attributes,
1921                name,
1922                name_span,
1923                generics,
1924                annotation,
1925                ty,
1926                span,
1927                ..
1928            } => Expression::TypeAlias {
1929                doc,
1930                attributes,
1931                name,
1932                name_span,
1933                generics,
1934                annotation,
1935                ty,
1936                visibility: Visibility::Public,
1937                span,
1938            },
1939            Expression::Interface {
1940                doc,
1941                name,
1942                name_span,
1943                generics,
1944                parents,
1945                method_signatures,
1946                span,
1947                ..
1948            } => Expression::Interface {
1949                doc,
1950                name,
1951                name_span,
1952                generics,
1953                parents,
1954                method_signatures,
1955                visibility: Visibility::Public,
1956                span,
1957            },
1958            expression => expression,
1959        }
1960    }
1961
1962    pub fn has_else(&self) -> bool {
1963        match self {
1964            Self::Block { items, .. } if items.is_empty() => false,
1965            Self::Unit { .. } => false,
1966            Self::If { alternative, .. } | Self::IfLet { alternative, .. } => {
1967                alternative.has_else()
1968            }
1969            _ => true,
1970        }
1971    }
1972}
1973
1974#[derive(Debug, Clone, PartialEq)]
1975pub enum Literal {
1976    Integer {
1977        value: u64,
1978        text: Option<String>,
1979    },
1980    Float {
1981        value: f64,
1982        text: Option<String>,
1983    },
1984    /// Imaginary coefficient, e.g. `4i` stores `4.0`
1985    Imaginary(f64),
1986    Boolean(bool),
1987    String {
1988        value: String,
1989        raw: bool,
1990    },
1991    FormatString(Vec<FormatStringPart>),
1992    Char(String),
1993    Slice(Vec<Expression>),
1994}
1995
1996#[derive(Debug, Clone, PartialEq)]
1997pub enum FormatStringPart {
1998    Text(String),
1999    Expression(Box<Expression>),
2000}
2001
2002#[derive(Debug, Clone, PartialEq)]
2003pub enum UnaryOperator {
2004    Negative,
2005    Not,
2006    BitwiseNot,
2007    Deref,
2008}
2009
2010#[derive(Debug, Clone, Copy, PartialEq)]
2011pub enum BinaryOperator {
2012    Addition,
2013    Subtraction,
2014    Multiplication,
2015    Division,
2016    BitwiseAnd,
2017    BitwiseOr,
2018    BitwiseXor,
2019    BitwiseAndNot,
2020    ShiftLeft,
2021    ShiftRight,
2022    LessThan,
2023    LessThanOrEqual,
2024    GreaterThan,
2025    GreaterThanOrEqual,
2026    Remainder,
2027    Equal,
2028    NotEqual,
2029    And,
2030    Or,
2031    Pipeline,
2032}
2033
2034impl BinaryOperator {
2035    /// The compound-assignment form (`+=`, `<<=`, ...) for operators that have
2036    /// one. Comparison, logical, and pipeline operators return `None`. Mirrors
2037    /// the compound-assignment tokens accepted by `parse_assignment`.
2038    pub fn compound_assignment_symbol(&self) -> Option<&'static str> {
2039        match self {
2040            BinaryOperator::Addition => Some("+="),
2041            BinaryOperator::Subtraction => Some("-="),
2042            BinaryOperator::Multiplication => Some("*="),
2043            BinaryOperator::Division => Some("/="),
2044            BinaryOperator::Remainder => Some("%="),
2045            BinaryOperator::BitwiseAnd => Some("&="),
2046            BinaryOperator::BitwiseOr => Some("|="),
2047            BinaryOperator::BitwiseXor => Some("^="),
2048            BinaryOperator::BitwiseAndNot => Some("&^="),
2049            BinaryOperator::ShiftLeft => Some("<<="),
2050            BinaryOperator::ShiftRight => Some(">>="),
2051            _ => None,
2052        }
2053    }
2054}
2055
2056impl std::fmt::Display for BinaryOperator {
2057    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2058        let symbol = match self {
2059            BinaryOperator::Addition => "+",
2060            BinaryOperator::Subtraction => "-",
2061            BinaryOperator::Multiplication => "*",
2062            BinaryOperator::Division => "/",
2063            BinaryOperator::Remainder => "%",
2064            BinaryOperator::BitwiseAnd => "&",
2065            BinaryOperator::BitwiseOr => "|",
2066            BinaryOperator::BitwiseXor => "^",
2067            BinaryOperator::BitwiseAndNot => "&^",
2068            BinaryOperator::ShiftLeft => "<<",
2069            BinaryOperator::ShiftRight => ">>",
2070            BinaryOperator::Equal => "==",
2071            BinaryOperator::NotEqual => "!=",
2072            BinaryOperator::LessThan => "<",
2073            BinaryOperator::LessThanOrEqual => "<=",
2074            BinaryOperator::GreaterThan => ">",
2075            BinaryOperator::GreaterThanOrEqual => ">=",
2076            BinaryOperator::And => "&&",
2077            BinaryOperator::Or => "||",
2078            BinaryOperator::Pipeline => "|>",
2079        };
2080        write!(f, "{}", symbol)
2081    }
2082}
2083
2084#[derive(Debug, Clone, PartialEq)]
2085pub struct ParentInterface {
2086    pub annotation: Annotation,
2087    pub ty: Type,
2088    pub span: Span,
2089}
2090
2091#[derive(Debug, Clone, Copy, PartialEq)]
2092#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2093pub enum Visibility {
2094    Public,
2095    Private,
2096}
2097
2098impl Visibility {
2099    pub fn is_public(&self) -> bool {
2100        matches!(self, Visibility::Public)
2101    }
2102}
2103
2104#[derive(Debug, Clone, PartialEq)]
2105pub enum ImportAlias {
2106    Named(EcoString, Span),
2107    Blank(Span),
2108}