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