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