Skip to main content

lisette_syntax/
ast.rs

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