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