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