Skip to main content

lisette_syntax/
ast.rs

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