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