1use crate::syntax::ast::{
38 AssertBody, AssertDecl, Attribute, AttributeArg, BaseDimDecl, ConstNodeDecl, DagDecl, DeclKind,
39 Declaration, DimDecl, DimExpr, DimExprItem, DimTerm, DomainBound, Encoding, Expr, ExprKind,
40 FieldDecl, FieldInit, FigureDecl, File, ForBinding, ForBindingIndex, GenericArg, GenericParam,
41 Ident, IdentPath, ImportDecl, ImportItem, ImportKind, IncludeDecl, IndexArg, IndexDecl,
42 IndexDeclKind, IndexExpr, LayerDecl, MapEntry, MapEntryKey, MarkSpec, MatchArm, MatchPattern,
43 ModulePath, MultiDataRow, MultiDecl, MultiDeclSharedAxes, MultiDeclSlice, MultiDeclSlot,
44 MultiHeaderCell, MultiSlotAxis, MultiSlotColumnSpan, NatExpr, NodeDecl, ParamBinding,
45 ParamDecl, PatternBinding, PlotDecl, PlotField, RawDeclSugar, RawExprSugar, TableIndexSpec,
46 TypeDecl, TypeDeclBody, TypeExpr, TypeExprKind, UnionMember, UnitDecl, UnitDef, UnitExpr,
47 UnitExprItem, UnresolvedRef,
48};
49use crate::syntax::names::{
50 ConstructorName, DeclName, DimName, FieldName, GenericParamName, IndexName, IndexVariantName,
51 ModuleAliasName, NamePath, PlotPropertyName, ScopedName, StructTypeName, UnitName,
52};
53use crate::syntax::non_empty::NonEmpty;
54use crate::syntax::span::Spanned;
55
56pub trait FormatEquivalent {
63 fn format_equivalent(&self, other: &Self) -> bool;
65}
66
67macro_rules! format_equivalent_via_eq {
77 ($($t:ty),+ $(,)?) => {
78 $(impl FormatEquivalent for $t {
79 fn format_equivalent(&self, other: &Self) -> bool {
80 self == other
81 }
82 })+
83 };
84}
85
86format_equivalent_via_eq!(
87 bool,
88 i32,
89 i64,
90 crate::syntax::dimension::Rational,
91 u64,
92 usize,
93 String,
94 DeclName,
96 DimName,
97 UnitName,
98 IndexName,
99 IndexVariantName,
100 FieldName,
101 ConstructorName,
102 StructTypeName,
103 GenericParamName,
104 PlotPropertyName,
105 ScopedName,
106 crate::syntax::names::LocalName,
107 NamePath,
108 ModuleAliasName,
109 crate::syntax::names::UnitRef,
110 crate::syntax::ast::BinOp,
112 crate::syntax::ast::UnaryOp,
113 crate::syntax::ast::MulDivOp,
114 crate::syntax::ast::Visibility,
115 crate::syntax::ast::BindableVisibility,
116 crate::syntax::ast::UnitConstness,
117 crate::syntax::ast::MarkType,
118 crate::syntax::ast::EncodingChannel,
119 crate::syntax::ast::MultiSlotKind,
120 crate::syntax::ast::GenericConstraint,
121 crate::syntax::ast::DomainBoundKind,
122 crate::syntax::ast::ImportItemNamespace,
123 crate::syntax::ast::MapEntryIndex,
124);
125
126impl FormatEquivalent for f64 {
132 fn format_equivalent(&self, other: &Self) -> bool {
133 self.to_bits() == other.to_bits()
134 }
135}
136
137impl<T: FormatEquivalent> FormatEquivalent for Box<T> {
142 fn format_equivalent(&self, other: &Self) -> bool {
143 (**self).format_equivalent(&**other)
144 }
145}
146
147impl<T: FormatEquivalent> FormatEquivalent for Option<T> {
148 fn format_equivalent(&self, other: &Self) -> bool {
149 match (self, other) {
150 (Some(a), Some(b)) => a.format_equivalent(b),
151 (None, None) => true,
152 (Some(_), None) | (None, Some(_)) => false,
153 }
154 }
155}
156
157impl<T: FormatEquivalent> FormatEquivalent for [T] {
158 fn format_equivalent(&self, other: &Self) -> bool {
159 self.len() == other.len()
160 && self
161 .iter()
162 .zip(other.iter())
163 .all(|(a, b)| a.format_equivalent(b))
164 }
165}
166
167impl<T: FormatEquivalent> FormatEquivalent for Vec<T> {
168 fn format_equivalent(&self, other: &Self) -> bool {
169 self.as_slice().format_equivalent(other.as_slice())
170 }
171}
172
173impl<T: FormatEquivalent> FormatEquivalent for NonEmpty<T> {
174 fn format_equivalent(&self, other: &Self) -> bool {
175 self.as_slice().format_equivalent(other.as_slice())
176 }
177}
178
179impl<T: FormatEquivalent> FormatEquivalent for Spanned<T> {
182 fn format_equivalent(&self, other: &Self) -> bool {
183 let Self { value, span: _ } = self;
184 let Self {
185 value: other_value,
186 span: _,
187 } = other;
188 value.format_equivalent(other_value)
189 }
190}
191
192impl FormatEquivalent for Ident {
197 fn format_equivalent(&self, other: &Self) -> bool {
198 let Self { name, span: _ } = self;
199 let Self {
200 name: other_name,
201 span: _,
202 } = other;
203 name == other_name
204 }
205}
206
207impl FormatEquivalent for Attribute {
208 fn format_equivalent(&self, other: &Self) -> bool {
209 let Self {
210 name,
211 args,
212 span: _,
213 } = self;
214 let Self {
215 name: other_name,
216 args: other_args,
217 span: _,
218 } = other;
219 name.format_equivalent(other_name) && args.format_equivalent(other_args)
220 }
221}
222
223impl FormatEquivalent for AttributeArg {
224 fn format_equivalent(&self, other: &Self) -> bool {
225 match self {
226 Self::Path { segments, span: _ } => {
227 let Self::Path {
228 segments: other_segments,
229 span: _,
230 } = other
231 else {
232 return false;
233 };
234 segments.format_equivalent(other_segments)
235 }
236 Self::RangeStep { step, span: _ } => {
237 let Self::RangeStep {
238 step: other_step,
239 span: _,
240 } = other
241 else {
242 return false;
243 };
244 step == other_step
245 }
246 Self::Group { elements, span: _ } => {
247 let Self::Group {
248 elements: other_elements,
249 span: _,
250 } = other
251 else {
252 return false;
253 };
254 elements.format_equivalent(other_elements)
255 }
256 }
257 }
258}
259
260impl FormatEquivalent for ImportKind {
261 fn format_equivalent(&self, other: &Self) -> bool {
262 match self {
263 Self::Selective(items) => {
264 let Self::Selective(other_items) = other else {
265 return false;
266 };
267 items.format_equivalent(other_items)
268 }
269 Self::Module { alias } => {
270 let Self::Module { alias: other_alias } = other else {
271 return false;
272 };
273 alias.format_equivalent(other_alias)
274 }
275 }
276 }
277}
278
279impl FormatEquivalent for ModulePath {
280 fn format_equivalent(&self, other: &Self) -> bool {
281 let Self { segments, span: _ } = self;
282 let Self {
283 segments: other_segments,
284 span: _,
285 } = other;
286 segments.format_equivalent(other_segments)
287 }
288}
289
290impl FormatEquivalent for ImportItem {
291 fn format_equivalent(&self, other: &Self) -> bool {
292 let Self {
293 attributes,
294 is_pub,
295 namespace,
296 name,
297 alias,
298 } = self;
299 let Self {
300 attributes: other_attributes,
301 is_pub: other_is_pub,
302 namespace: other_namespace,
303 name: other_name,
304 alias: other_alias,
305 } = other;
306 attributes.format_equivalent(other_attributes)
307 && is_pub.format_equivalent(other_is_pub)
308 && namespace.format_equivalent(other_namespace)
309 && name.format_equivalent(other_name)
310 && alias.format_equivalent(other_alias)
311 }
312}
313
314impl FormatEquivalent for File {
319 fn format_equivalent(&self, other: &Self) -> bool {
320 let Self { declarations } = self;
323 let Self {
324 declarations: other_declarations,
325 } = other;
326 declarations.format_equivalent(other_declarations)
327 }
328}
329
330impl FormatEquivalent for Declaration {
331 fn format_equivalent(&self, other: &Self) -> bool {
332 let Self {
333 attributes,
334 kind,
335 span: _,
336 } = self;
337 let Self {
338 attributes: other_attributes,
339 kind: other_kind,
340 span: _,
341 } = other;
342 attributes.format_equivalent(other_attributes) && kind.format_equivalent(other_kind)
343 }
344}
345
346impl FormatEquivalent for DeclKind {
347 fn format_equivalent(&self, other: &Self) -> bool {
348 match self {
349 Self::Param(a) => {
350 let Self::Param(b) = other else { return false };
351 a.format_equivalent(b)
352 }
353 Self::Node(a) => {
354 let Self::Node(b) = other else { return false };
355 a.format_equivalent(b)
356 }
357 Self::ConstNode(a) => {
358 let Self::ConstNode(b) = other else {
359 return false;
360 };
361 a.format_equivalent(b)
362 }
363 Self::BaseDimension(a) => {
364 let Self::BaseDimension(b) = other else {
365 return false;
366 };
367 a.format_equivalent(b)
368 }
369 Self::Dimension(a) => {
370 let Self::Dimension(b) = other else {
371 return false;
372 };
373 a.format_equivalent(b)
374 }
375 Self::Unit(a) => {
376 let Self::Unit(b) = other else { return false };
377 a.format_equivalent(b)
378 }
379 Self::Type(a) => {
380 let Self::Type(b) = other else { return false };
381 a.format_equivalent(b)
382 }
383 Self::Index(a) => {
384 let Self::Index(b) = other else { return false };
385 a.format_equivalent(b)
386 }
387 Self::Import(a) => {
388 let Self::Import(b) = other else { return false };
389 a.format_equivalent(b)
390 }
391 Self::Include(a) => {
392 let Self::Include(b) = other else {
393 return false;
394 };
395 a.format_equivalent(b)
396 }
397 Self::Dag(a) => {
398 let Self::Dag(b) = other else { return false };
399 a.format_equivalent(b)
400 }
401 Self::Assert(a) => {
402 let Self::Assert(b) = other else { return false };
403 a.format_equivalent(b)
404 }
405 Self::Plot(a) => {
406 let Self::Plot(b) = other else { return false };
407 a.format_equivalent(b)
408 }
409 Self::Figure(a) => {
410 let Self::Figure(b) = other else { return false };
411 a.format_equivalent(b)
412 }
413 Self::Layer(a) => {
414 let Self::Layer(b) = other else { return false };
415 a.format_equivalent(b)
416 }
417 Self::Sugar(a) => {
418 let Self::Sugar(b) = other else { return false };
419 a.format_equivalent(b)
420 }
421 }
422 }
423}
424
425impl FormatEquivalent for RawDeclSugar {
426 fn format_equivalent(&self, other: &Self) -> bool {
427 let Self::Multi(a) = self;
428 let Self::Multi(b) = other;
429 a.format_equivalent(b)
430 }
431}
432
433impl FormatEquivalent for ParamDecl {
434 fn format_equivalent(&self, other: &Self) -> bool {
435 let Self {
436 name,
437 type_ann,
438 value,
439 } = self;
440 let Self {
441 name: other_name,
442 type_ann: other_type_ann,
443 value: other_value,
444 } = other;
445 name.format_equivalent(other_name)
446 && type_ann.format_equivalent(other_type_ann)
447 && value.format_equivalent(other_value)
448 }
449}
450
451impl FormatEquivalent for NodeDecl {
452 fn format_equivalent(&self, other: &Self) -> bool {
453 let Self {
454 visibility,
455 name,
456 type_ann,
457 value,
458 } = self;
459 let Self {
460 visibility: other_visibility,
461 name: other_name,
462 type_ann: other_type_ann,
463 value: other_value,
464 } = other;
465 visibility.format_equivalent(other_visibility)
466 && name.format_equivalent(other_name)
467 && type_ann.format_equivalent(other_type_ann)
468 && value.format_equivalent(other_value)
469 }
470}
471
472impl FormatEquivalent for ConstNodeDecl {
473 fn format_equivalent(&self, other: &Self) -> bool {
474 let Self {
475 visibility,
476 name,
477 type_ann,
478 value,
479 } = self;
480 let Self {
481 visibility: other_visibility,
482 name: other_name,
483 type_ann: other_type_ann,
484 value: other_value,
485 } = other;
486 visibility.format_equivalent(other_visibility)
487 && name.format_equivalent(other_name)
488 && type_ann.format_equivalent(other_type_ann)
489 && value.format_equivalent(other_value)
490 }
491}
492
493impl FormatEquivalent for BaseDimDecl {
494 fn format_equivalent(&self, other: &Self) -> bool {
495 let Self { visibility, name } = self;
496 let Self {
497 visibility: other_visibility,
498 name: other_name,
499 } = other;
500 visibility.format_equivalent(other_visibility) && name.format_equivalent(other_name)
501 }
502}
503
504impl FormatEquivalent for DimDecl {
505 fn format_equivalent(&self, other: &Self) -> bool {
506 let Self {
507 visibility,
508 name,
509 definition,
510 } = self;
511 let Self {
512 visibility: other_visibility,
513 name: other_name,
514 definition: other_definition,
515 } = other;
516 visibility.format_equivalent(other_visibility)
517 && name.format_equivalent(other_name)
518 && definition.format_equivalent(other_definition)
519 }
520}
521
522impl FormatEquivalent for UnitDecl {
523 fn format_equivalent(&self, other: &Self) -> bool {
524 let Self {
525 visibility,
526 constness,
527 name,
528 dim_type,
529 definition,
530 } = self;
531 let Self {
532 visibility: other_visibility,
533 constness: other_constness,
534 name: other_name,
535 dim_type: other_dim_type,
536 definition: other_definition,
537 } = other;
538 visibility.format_equivalent(other_visibility)
539 && constness.format_equivalent(other_constness)
540 && name.format_equivalent(other_name)
541 && dim_type.format_equivalent(other_dim_type)
542 && definition.format_equivalent(other_definition)
543 }
544}
545
546impl FormatEquivalent for UnitDef {
547 fn format_equivalent(&self, other: &Self) -> bool {
548 let Self {
549 scale_expr,
550 unit_expr,
551 span: _,
552 } = self;
553 let Self {
554 scale_expr: other_scale_expr,
555 unit_expr: other_unit_expr,
556 span: _,
557 } = other;
558 scale_expr.format_equivalent(other_scale_expr)
559 && unit_expr.format_equivalent(other_unit_expr)
560 }
561}
562
563impl FormatEquivalent for TypeDecl {
564 fn format_equivalent(&self, other: &Self) -> bool {
565 let Self {
566 visibility,
567 name,
568 generic_params,
569 body,
570 } = self;
571 let Self {
572 visibility: other_visibility,
573 name: other_name,
574 generic_params: other_generic_params,
575 body: other_body,
576 } = other;
577 visibility.format_equivalent(other_visibility)
578 && name.format_equivalent(other_name)
579 && generic_params.format_equivalent(other_generic_params)
580 && body.format_equivalent(other_body)
581 }
582}
583
584impl FormatEquivalent for TypeDeclBody {
585 fn format_equivalent(&self, other: &Self) -> bool {
586 match self {
587 Self::Required => matches!(other, Self::Required),
588 Self::Constructors(members) => {
589 let Self::Constructors(other_members) = other else {
590 return false;
591 };
592 members.format_equivalent(other_members)
593 }
594 }
595 }
596}
597
598impl FormatEquivalent for UnionMember {
599 fn format_equivalent(&self, other: &Self) -> bool {
600 let Self {
601 name,
602 payload,
603 span: _,
604 } = self;
605 let Self {
606 name: other_name,
607 payload: other_payload,
608 span: _,
609 } = other;
610 name.format_equivalent(other_name) && payload.format_equivalent(other_payload)
611 }
612}
613
614impl FormatEquivalent for FieldDecl {
615 fn format_equivalent(&self, other: &Self) -> bool {
616 let Self { name, type_ann } = self;
617 let Self {
618 name: other_name,
619 type_ann: other_type_ann,
620 } = other;
621 name.format_equivalent(other_name) && type_ann.format_equivalent(other_type_ann)
622 }
623}
624
625impl FormatEquivalent for IndexDecl {
626 fn format_equivalent(&self, other: &Self) -> bool {
627 let Self {
628 visibility,
629 name,
630 kind,
631 } = self;
632 let Self {
633 visibility: other_visibility,
634 name: other_name,
635 kind: other_kind,
636 } = other;
637 visibility.format_equivalent(other_visibility)
638 && name.format_equivalent(other_name)
639 && kind.format_equivalent(other_kind)
640 }
641}
642
643impl FormatEquivalent for IndexDeclKind {
644 fn format_equivalent(&self, other: &Self) -> bool {
645 match self {
646 Self::Named { variants } => {
647 let Self::Named {
648 variants: other_variants,
649 } = other
650 else {
651 return false;
652 };
653 variants.format_equivalent(other_variants)
654 }
655 Self::Range { start, end, step } => {
656 let Self::Range {
657 start: other_start,
658 end: other_end,
659 step: other_step,
660 } = other
661 else {
662 return false;
663 };
664 start.format_equivalent(other_start)
665 && end.format_equivalent(other_end)
666 && step.format_equivalent(other_step)
667 }
668 Self::RequiredNamed => matches!(other, Self::RequiredNamed),
669 Self::RequiredRange { dimension } => {
670 let Self::RequiredRange {
671 dimension: other_dimension,
672 } = other
673 else {
674 return false;
675 };
676 dimension.format_equivalent(other_dimension)
677 }
678 }
679 }
680}
681
682impl FormatEquivalent for GenericParam {
683 fn format_equivalent(&self, other: &Self) -> bool {
684 let Self {
685 name,
686 constraint,
687 default,
688 } = self;
689 let Self {
690 name: other_name,
691 constraint: other_constraint,
692 default: other_default,
693 } = other;
694 name.format_equivalent(other_name)
695 && constraint.format_equivalent(other_constraint)
696 && default.format_equivalent(other_default)
697 }
698}
699
700impl FormatEquivalent for ImportDecl {
701 fn format_equivalent(&self, other: &Self) -> bool {
702 let Self {
703 visibility,
704 path,
705 kind,
706 } = self;
707 let Self {
708 visibility: other_visibility,
709 path: other_path,
710 kind: other_kind,
711 } = other;
712 visibility.format_equivalent(other_visibility)
713 && path.format_equivalent(other_path)
714 && kind.format_equivalent(other_kind)
715 }
716}
717
718impl FormatEquivalent for IncludeDecl {
719 fn format_equivalent(&self, other: &Self) -> bool {
720 let Self {
721 visibility,
722 path,
723 param_bindings,
724 kind,
725 } = self;
726 let Self {
727 visibility: other_visibility,
728 path: other_path,
729 param_bindings: other_param_bindings,
730 kind: other_kind,
731 } = other;
732 visibility.format_equivalent(other_visibility)
733 && path.format_equivalent(other_path)
734 && param_bindings.format_equivalent(other_param_bindings)
735 && kind.format_equivalent(other_kind)
736 }
737}
738
739impl FormatEquivalent for DagDecl {
740 fn format_equivalent(&self, other: &Self) -> bool {
741 let Self {
742 visibility,
743 name,
744 body,
745 span: _,
746 } = self;
747 let Self {
748 visibility: other_visibility,
749 name: other_name,
750 body: other_body,
751 span: _,
752 } = other;
753 visibility.format_equivalent(other_visibility)
754 && name.format_equivalent(other_name)
755 && body.format_equivalent(other_body)
756 }
757}
758
759impl FormatEquivalent for AssertDecl {
760 fn format_equivalent(&self, other: &Self) -> bool {
761 let Self {
762 visibility,
763 name,
764 body,
765 } = self;
766 let Self {
767 visibility: other_visibility,
768 name: other_name,
769 body: other_body,
770 } = other;
771 visibility.format_equivalent(other_visibility)
772 && name.format_equivalent(other_name)
773 && body.format_equivalent(other_body)
774 }
775}
776
777impl FormatEquivalent for AssertBody {
778 fn format_equivalent(&self, other: &Self) -> bool {
779 match self {
780 Self::Expr(expr) => {
781 let Self::Expr(other_expr) = other else {
782 return false;
783 };
784 expr.format_equivalent(other_expr)
785 }
786 Self::Tolerance {
787 actual,
788 expected,
789 tolerance,
790 is_relative,
791 } => {
792 let Self::Tolerance {
793 actual: other_actual,
794 expected: other_expected,
795 tolerance: other_tolerance,
796 is_relative: other_is_relative,
797 } = other
798 else {
799 return false;
800 };
801 actual.format_equivalent(other_actual)
802 && expected.format_equivalent(other_expected)
803 && tolerance.format_equivalent(other_tolerance)
804 && is_relative.format_equivalent(other_is_relative)
805 }
806 }
807 }
808}
809
810impl FormatEquivalent for PlotDecl {
811 fn format_equivalent(&self, other: &Self) -> bool {
812 let Self {
813 visibility,
814 name,
815 mark,
816 encodings,
817 properties,
818 } = self;
819 let Self {
820 visibility: other_visibility,
821 name: other_name,
822 mark: other_mark,
823 encodings: other_encodings,
824 properties: other_properties,
825 } = other;
826 visibility.format_equivalent(other_visibility)
827 && name.format_equivalent(other_name)
828 && mark.format_equivalent(other_mark)
829 && encodings.format_equivalent(other_encodings)
830 && properties.format_equivalent(other_properties)
831 }
832}
833
834impl FormatEquivalent for MarkSpec {
835 fn format_equivalent(&self, other: &Self) -> bool {
836 let Self {
837 mark_type,
838 mark_type_span: _,
839 properties,
840 span: _,
841 } = self;
842 let Self {
843 mark_type: other_mark_type,
844 mark_type_span: _,
845 properties: other_properties,
846 span: _,
847 } = other;
848 mark_type.format_equivalent(other_mark_type)
849 && properties.format_equivalent(other_properties)
850 }
851}
852
853impl FormatEquivalent for Encoding {
854 fn format_equivalent(&self, other: &Self) -> bool {
855 let Self {
856 channel,
857 channel_span: _,
858 value,
859 span: _,
860 } = self;
861 let Self {
862 channel: other_channel,
863 channel_span: _,
864 value: other_value,
865 span: _,
866 } = other;
867 channel.format_equivalent(other_channel) && value.format_equivalent(other_value)
868 }
869}
870
871impl FormatEquivalent for PlotField {
872 fn format_equivalent(&self, other: &Self) -> bool {
873 let Self {
874 name,
875 value,
876 span: _,
877 } = self;
878 let Self {
879 name: other_name,
880 value: other_value,
881 span: _,
882 } = other;
883 name.format_equivalent(other_name) && value.format_equivalent(other_value)
884 }
885}
886
887impl FormatEquivalent for FigureDecl {
888 fn format_equivalent(&self, other: &Self) -> bool {
889 let Self {
890 visibility,
891 name,
892 plot_names,
893 fields,
894 } = self;
895 let Self {
896 visibility: other_visibility,
897 name: other_name,
898 plot_names: other_plot_names,
899 fields: other_fields,
900 } = other;
901 visibility.format_equivalent(other_visibility)
902 && name.format_equivalent(other_name)
903 && plot_names.format_equivalent(other_plot_names)
904 && fields.format_equivalent(other_fields)
905 }
906}
907
908impl FormatEquivalent for LayerDecl {
909 fn format_equivalent(&self, other: &Self) -> bool {
910 let Self {
911 visibility,
912 name,
913 plot_names,
914 fields,
915 } = self;
916 let Self {
917 visibility: other_visibility,
918 name: other_name,
919 plot_names: other_plot_names,
920 fields: other_fields,
921 } = other;
922 visibility.format_equivalent(other_visibility)
923 && name.format_equivalent(other_name)
924 && plot_names.format_equivalent(other_plot_names)
925 && fields.format_equivalent(other_fields)
926 }
927}
928
929impl FormatEquivalent for MultiDecl {
930 fn format_equivalent(&self, other: &Self) -> bool {
931 let Self {
932 slots,
933 shared_axes,
934 slot_axes,
935 slices,
936 span: _,
937 table_expr_span: _,
938 } = self;
939 let Self {
940 slots: other_slots,
941 shared_axes: other_shared_axes,
942 slot_axes: other_slot_axes,
943 slices: other_slices,
944 span: _,
945 table_expr_span: _,
946 } = other;
947 slots.format_equivalent(other_slots)
948 && shared_axes.format_equivalent(other_shared_axes)
949 && slot_axes.format_equivalent(other_slot_axes)
950 && slices.format_equivalent(other_slices)
951 }
952}
953
954impl FormatEquivalent for MultiDeclSlot {
955 fn format_equivalent(&self, other: &Self) -> bool {
956 let Self {
957 visibility,
958 kind,
959 kind_span: _,
960 name,
961 type_ann,
962 header_span: _,
963 } = self;
964 let Self {
965 visibility: other_visibility,
966 kind: other_kind,
967 kind_span: _,
968 name: other_name,
969 type_ann: other_type_ann,
970 header_span: _,
971 } = other;
972 visibility.format_equivalent(other_visibility)
973 && kind.format_equivalent(other_kind)
974 && name.format_equivalent(other_name)
975 && type_ann.format_equivalent(other_type_ann)
976 }
977}
978
979impl FormatEquivalent for MultiSlotAxis {
980 fn format_equivalent(&self, other: &Self) -> bool {
981 match self {
982 Self::Underscore => matches!(other, Self::Underscore),
983 Self::Axis(axis) => {
984 let Self::Axis(other_axis) = other else {
985 return false;
986 };
987 axis.format_equivalent(other_axis)
988 }
989 }
990 }
991}
992
993impl FormatEquivalent for MultiSlotColumnSpan {
994 fn format_equivalent(&self, other: &Self) -> bool {
995 match self {
996 Self::Single(col) => {
997 let Self::Single(other_col) = other else {
998 return false;
999 };
1000 col.format_equivalent(other_col)
1001 }
1002 Self::Range {
1003 start,
1004 end,
1005 extra_axis,
1006 } => {
1007 let Self::Range {
1008 start: other_start,
1009 end: other_end,
1010 extra_axis: other_extra_axis,
1011 } = other
1012 else {
1013 return false;
1014 };
1015 start.format_equivalent(other_start)
1016 && end.format_equivalent(other_end)
1017 && extra_axis.format_equivalent(other_extra_axis)
1018 }
1019 }
1020 }
1021}
1022
1023impl FormatEquivalent for MultiDeclSlice {
1024 fn format_equivalent(&self, other: &Self) -> bool {
1025 let Self {
1026 prefix_keys,
1027 header_cells,
1028 header_span: _,
1029 column_layout,
1030 rows,
1031 } = self;
1032 let Self {
1033 prefix_keys: other_prefix_keys,
1034 header_cells: other_header_cells,
1035 header_span: _,
1036 column_layout: other_column_layout,
1037 rows: other_rows,
1038 } = other;
1039 prefix_keys.format_equivalent(other_prefix_keys)
1040 && header_cells.format_equivalent(other_header_cells)
1041 && column_layout.format_equivalent(other_column_layout)
1042 && rows.format_equivalent(other_rows)
1043 }
1044}
1045
1046impl FormatEquivalent for MultiHeaderCell {
1047 fn format_equivalent(&self, other: &Self) -> bool {
1048 match self {
1049 Self::Underscore { span: _ } => matches!(other, Self::Underscore { .. }),
1050 Self::Variant {
1051 axis,
1052 variant,
1053 span: _,
1054 } => {
1055 let Self::Variant {
1056 axis: other_axis,
1057 variant: other_variant,
1058 span: _,
1059 } = other
1060 else {
1061 return false;
1062 };
1063 axis.format_equivalent(other_axis) && variant.format_equivalent(other_variant)
1064 }
1065 }
1066 }
1067}
1068
1069impl FormatEquivalent for MultiDataRow {
1070 fn format_equivalent(&self, other: &Self) -> bool {
1071 let Self {
1072 label,
1073 values,
1074 span: _,
1075 } = self;
1076 let Self {
1077 label: other_label,
1078 values: other_values,
1079 span: _,
1080 } = other;
1081 label.format_equivalent(other_label) && values.format_equivalent(other_values)
1082 }
1083}
1084
1085impl FormatEquivalent for TypeExpr {
1090 fn format_equivalent(&self, other: &Self) -> bool {
1091 let Self {
1092 kind,
1093 constraints,
1094 span: _,
1095 } = self;
1096 let Self {
1097 kind: other_kind,
1098 constraints: other_constraints,
1099 span: _,
1100 } = other;
1101 kind.format_equivalent(other_kind) && constraints.format_equivalent(other_constraints)
1102 }
1103}
1104
1105impl FormatEquivalent for TypeExprKind {
1106 fn format_equivalent(&self, other: &Self) -> bool {
1107 match self {
1108 Self::Dimensionless => matches!(other, Self::Dimensionless),
1109 Self::Bool => matches!(other, Self::Bool),
1110 Self::Int => matches!(other, Self::Int),
1111 Self::Datetime => matches!(other, Self::Datetime),
1112 Self::DatetimeApplication { type_args } => {
1113 let Self::DatetimeApplication {
1114 type_args: other_type_args,
1115 } = other
1116 else {
1117 return false;
1118 };
1119 type_args.format_equivalent(other_type_args)
1120 }
1121 Self::DimExpr(dim) => {
1122 let Self::DimExpr(other_dim) = other else {
1123 return false;
1124 };
1125 dim.format_equivalent(other_dim)
1126 }
1127 Self::Indexed { base, indexes } => {
1128 let Self::Indexed {
1129 base: other_base,
1130 indexes: other_indexes,
1131 } = other
1132 else {
1133 return false;
1134 };
1135 base.format_equivalent(other_base) && indexes.format_equivalent(other_indexes)
1136 }
1137 Self::TypeApplication { name, type_args } => {
1138 let Self::TypeApplication {
1139 name: other_name,
1140 type_args: other_type_args,
1141 } = other
1142 else {
1143 return false;
1144 };
1145 name.format_equivalent(other_name) && type_args.format_equivalent(other_type_args)
1146 }
1147 }
1148 }
1149}
1150
1151impl FormatEquivalent for DomainBound {
1152 fn format_equivalent(&self, other: &Self) -> bool {
1153 let Self {
1154 kind,
1155 kind_span: _,
1156 value,
1157 span: _,
1158 } = self;
1159 let Self {
1160 kind: other_kind,
1161 kind_span: _,
1162 value: other_value,
1163 span: _,
1164 } = other;
1165 kind.format_equivalent(other_kind) && value.format_equivalent(other_value)
1166 }
1167}
1168
1169impl FormatEquivalent for IndexExpr {
1170 fn format_equivalent(&self, other: &Self) -> bool {
1171 match self {
1172 Self::Name(name) => {
1173 let Self::Name(other_name) = other else {
1174 return false;
1175 };
1176 name.format_equivalent(other_name)
1177 }
1178 Self::NatExpr(nat) => {
1179 let Self::NatExpr(other_nat) = other else {
1180 return false;
1181 };
1182 nat.format_equivalent(other_nat)
1183 }
1184 }
1185 }
1186}
1187
1188impl FormatEquivalent for DimExpr {
1189 fn format_equivalent(&self, other: &Self) -> bool {
1190 let Self { terms, span: _ } = self;
1191 let Self {
1192 terms: other_terms,
1193 span: _,
1194 } = other;
1195 terms.format_equivalent(other_terms)
1196 }
1197}
1198
1199impl FormatEquivalent for DimExprItem {
1200 fn format_equivalent(&self, other: &Self) -> bool {
1201 let Self { op, term } = self;
1202 let Self {
1203 op: other_op,
1204 term: other_term,
1205 } = other;
1206 op.format_equivalent(other_op) && term.format_equivalent(other_term)
1207 }
1208}
1209
1210impl FormatEquivalent for DimTerm {
1211 fn format_equivalent(&self, other: &Self) -> bool {
1212 let Self {
1213 name,
1214 power,
1215 span: _,
1216 } = self;
1217 let Self {
1218 name: other_name,
1219 power: other_power,
1220 span: _,
1221 } = other;
1222 name.format_equivalent(other_name) && power.format_equivalent(other_power)
1223 }
1224}
1225
1226impl FormatEquivalent for UnitExpr {
1227 fn format_equivalent(&self, other: &Self) -> bool {
1228 let Self { terms, span: _ } = self;
1229 let Self {
1230 terms: other_terms,
1231 span: _,
1232 } = other;
1233 terms.format_equivalent(other_terms)
1234 }
1235}
1236
1237impl FormatEquivalent for UnitExprItem {
1238 fn format_equivalent(&self, other: &Self) -> bool {
1239 let Self { op, name, power } = self;
1240 let Self {
1241 op: other_op,
1242 name: other_name,
1243 power: other_power,
1244 } = other;
1245 op.format_equivalent(other_op)
1246 && name.format_equivalent(other_name)
1247 && power.format_equivalent(other_power)
1248 }
1249}
1250
1251impl FormatEquivalent for UnresolvedRef {
1252 fn format_equivalent(&self, other: &Self) -> bool {
1253 let Self::Path(a) = self;
1254 let Self::Path(b) = other;
1255 a.format_equivalent(b)
1256 }
1257}
1258
1259impl FormatEquivalent for IdentPath {
1260 fn format_equivalent(&self, other: &Self) -> bool {
1261 let Self { segments } = self;
1262 let Self {
1263 segments: other_segments,
1264 } = other;
1265 segments.format_equivalent(other_segments)
1266 }
1267}
1268
1269impl FormatEquivalent for ParamBinding {
1270 fn format_equivalent(&self, other: &Self) -> bool {
1271 let Self {
1272 name,
1273 value,
1274 span: _,
1275 } = self;
1276 let Self {
1277 name: other_name,
1278 value: other_value,
1279 span: _,
1280 } = other;
1281 name.format_equivalent(other_name) && value.format_equivalent(other_value)
1282 }
1283}
1284
1285impl FormatEquivalent for TableIndexSpec {
1286 fn format_equivalent(&self, other: &Self) -> bool {
1287 match self {
1288 Self::Named(name) => {
1289 let Self::Named(other_name) = other else {
1290 return false;
1291 };
1292 name.format_equivalent(other_name)
1293 }
1294 Self::NatRange(size, _span) => {
1295 let Self::NatRange(other_size, _other_span) = other else {
1296 return false;
1297 };
1298 size.format_equivalent(other_size)
1299 }
1300 }
1301 }
1302}
1303
1304impl FormatEquivalent for MultiDeclSharedAxes {
1305 fn format_equivalent(&self, other: &Self) -> bool {
1306 self.slice_axes().format_equivalent(other.slice_axes())
1310 && self.row_axis().format_equivalent(other.row_axis())
1311 }
1312}
1313
1314impl FormatEquivalent for MapEntryKey {
1315 fn format_equivalent(&self, other: &Self) -> bool {
1316 let Self { index, variant } = self;
1317 let Self {
1318 index: other_index,
1319 variant: other_variant,
1320 } = other;
1321 index.format_equivalent(other_index) && variant.format_equivalent(other_variant)
1322 }
1323}
1324
1325impl FormatEquivalent for MapEntry {
1326 fn format_equivalent(&self, other: &Self) -> bool {
1327 let Self { keys, value } = self;
1328 let Self {
1329 keys: other_keys,
1330 value: other_value,
1331 } = other;
1332 keys.format_equivalent(other_keys) && value.format_equivalent(other_value)
1333 }
1334}
1335
1336impl FormatEquivalent for ForBinding {
1337 fn format_equivalent(&self, other: &Self) -> bool {
1338 let Self { var, index } = self;
1339 let Self {
1340 var: other_var,
1341 index: other_index,
1342 } = other;
1343 var.format_equivalent(other_var) && index.format_equivalent(other_index)
1344 }
1345}
1346
1347impl FormatEquivalent for ForBindingIndex {
1348 fn format_equivalent(&self, other: &Self) -> bool {
1349 match self {
1350 Self::Named(name) => {
1351 let Self::Named(other_name) = other else {
1352 return false;
1353 };
1354 name.format_equivalent(other_name)
1355 }
1356 Self::Range { arg, span: _ } => {
1357 let Self::Range {
1358 arg: other_arg,
1359 span: _,
1360 } = other
1361 else {
1362 return false;
1363 };
1364 arg.format_equivalent(other_arg)
1365 }
1366 }
1367 }
1368}
1369
1370impl FormatEquivalent for NatExpr {
1371 fn format_equivalent(&self, other: &Self) -> bool {
1372 match self {
1373 Self::Literal(value, _span) => {
1374 let Self::Literal(other_value, _other_span) = other else {
1375 return false;
1376 };
1377 value.format_equivalent(other_value)
1378 }
1379 Self::Var(ident) => {
1380 let Self::Var(other_ident) = other else {
1381 return false;
1382 };
1383 ident.format_equivalent(other_ident)
1384 }
1385 Self::Add(lhs, rhs, _span) => {
1386 let Self::Add(other_lhs, other_rhs, _other_span) = other else {
1387 return false;
1388 };
1389 lhs.format_equivalent(other_lhs) && rhs.format_equivalent(other_rhs)
1390 }
1391 Self::Mul(lhs, rhs, _span) => {
1392 let Self::Mul(other_lhs, other_rhs, _other_span) = other else {
1393 return false;
1394 };
1395 lhs.format_equivalent(other_lhs) && rhs.format_equivalent(other_rhs)
1396 }
1397 }
1398 }
1399}
1400
1401impl FormatEquivalent for GenericArg {
1402 fn format_equivalent(&self, other: &Self) -> bool {
1403 match self {
1404 Self::Type(type_expr) => {
1405 let Self::Type(other_type_expr) = other else {
1406 return false;
1407 };
1408 type_expr.format_equivalent(other_type_expr)
1409 }
1410 Self::Nat(nat) => {
1411 let Self::Nat(other_nat) = other else {
1412 return false;
1413 };
1414 nat.format_equivalent(other_nat)
1415 }
1416 }
1417 }
1418}
1419
1420impl FormatEquivalent for IndexArg {
1421 fn format_equivalent(&self, other: &Self) -> bool {
1422 match self {
1423 Self::Variant { index, variant } => {
1424 let Self::Variant {
1425 index: other_index,
1426 variant: other_variant,
1427 } = other
1428 else {
1429 return false;
1430 };
1431 index.format_equivalent(other_index) && variant.format_equivalent(other_variant)
1432 }
1433 Self::Var(ident) => {
1434 let Self::Var(other_ident) = other else {
1435 return false;
1436 };
1437 ident.format_equivalent(other_ident)
1438 }
1439 Self::Expr(expr) => {
1440 let Self::Expr(other_expr) = other else {
1441 return false;
1442 };
1443 expr.format_equivalent(other_expr)
1444 }
1445 }
1446 }
1447}
1448
1449impl FormatEquivalent for FieldInit {
1450 fn format_equivalent(&self, other: &Self) -> bool {
1451 let Self { name, value } = self;
1452 let Self {
1453 name: other_name,
1454 value: other_value,
1455 } = other;
1456 name.format_equivalent(other_name) && value.format_equivalent(other_value)
1457 }
1458}
1459
1460impl FormatEquivalent for MatchArm {
1461 fn format_equivalent(&self, other: &Self) -> bool {
1462 let Self {
1463 pattern,
1464 body,
1465 span: _,
1466 } = self;
1467 let Self {
1468 pattern: other_pattern,
1469 body: other_body,
1470 span: _,
1471 } = other;
1472 pattern.format_equivalent(other_pattern) && body.format_equivalent(other_body)
1473 }
1474}
1475
1476impl FormatEquivalent for MatchPattern {
1477 fn format_equivalent(&self, other: &Self) -> bool {
1478 match self {
1479 Self::Path {
1480 path,
1481 bindings,
1482 span: _,
1483 } => {
1484 let Self::Path {
1485 path: other_path,
1486 bindings: other_bindings,
1487 span: _,
1488 } = other
1489 else {
1490 return false;
1491 };
1492 path.format_equivalent(other_path) && bindings.format_equivalent(other_bindings)
1493 }
1494 Self::Constructor {
1495 name,
1496 bindings,
1497 span: _,
1498 } => {
1499 let Self::Constructor {
1500 name: other_name,
1501 bindings: other_bindings,
1502 span: _,
1503 } = other
1504 else {
1505 return false;
1506 };
1507 name.format_equivalent(other_name) && bindings.format_equivalent(other_bindings)
1508 }
1509 Self::IndexLabel {
1510 index,
1511 variant,
1512 span: _,
1513 } => {
1514 let Self::IndexLabel {
1515 index: other_index,
1516 variant: other_variant,
1517 span: _,
1518 } = other
1519 else {
1520 return false;
1521 };
1522 index.format_equivalent(other_index) && variant.format_equivalent(other_variant)
1523 }
1524 }
1525 }
1526}
1527
1528impl FormatEquivalent for PatternBinding {
1529 fn format_equivalent(&self, other: &Self) -> bool {
1530 match self {
1531 Self::Bind { field, var } => {
1532 let Self::Bind {
1533 field: other_field,
1534 var: other_var,
1535 } = other
1536 else {
1537 return false;
1538 };
1539 field.format_equivalent(other_field) && var.format_equivalent(other_var)
1540 }
1541 Self::Wildcard { field, span: _ } => {
1542 let Self::Wildcard {
1543 field: other_field,
1544 span: _,
1545 } = other
1546 else {
1547 return false;
1548 };
1549 field.format_equivalent(other_field)
1550 }
1551 }
1552 }
1553}
1554
1555impl FormatEquivalent for RawExprSugar {
1556 fn format_equivalent(&self, other: &Self) -> bool {
1557 let Self::TableLiteral { indexes, entries } = self;
1558 let Self::TableLiteral {
1559 indexes: other_indexes,
1560 entries: other_entries,
1561 } = other;
1562 indexes.format_equivalent(other_indexes) && entries.format_equivalent(other_entries)
1563 }
1564}
1565
1566impl FormatEquivalent for Expr {
1567 fn format_equivalent(&self, other: &Self) -> bool {
1568 crate::stack::with_stack_growth(|| self.kind.format_equivalent(&other.kind))
1572 }
1573}
1574
1575impl FormatEquivalent for ExprKind {
1576 #[expect(
1577 clippy::too_many_lines,
1578 reason = "one arm per ExprKind variant; exhaustiveness is the point"
1579 )]
1580 fn format_equivalent(&self, other: &Self) -> bool {
1581 match self {
1582 Self::Number(value) => {
1583 let Self::Number(other_value) = other else {
1584 return false;
1585 };
1586 value.format_equivalent(other_value)
1587 }
1588 Self::Integer(value) => {
1589 let Self::Integer(other_value) = other else {
1590 return false;
1591 };
1592 value.format_equivalent(other_value)
1593 }
1594 Self::Bool(value) => {
1595 let Self::Bool(other_value) = other else {
1596 return false;
1597 };
1598 value.format_equivalent(other_value)
1599 }
1600 Self::StringLiteral(value) => {
1601 let Self::StringLiteral(other_value) = other else {
1602 return false;
1603 };
1604 value.format_equivalent(other_value)
1605 }
1606 Self::GraphRef(name) => {
1607 let Self::GraphRef(other_name) = other else {
1608 return false;
1609 };
1610 name.format_equivalent(other_name)
1611 }
1612 Self::BinOp { op, lhs, rhs } => {
1613 let Self::BinOp {
1614 op: other_op,
1615 lhs: other_lhs,
1616 rhs: other_rhs,
1617 } = other
1618 else {
1619 return false;
1620 };
1621 op.format_equivalent(other_op)
1622 && lhs.format_equivalent(other_lhs)
1623 && rhs.format_equivalent(other_rhs)
1624 }
1625 Self::UnaryOp { op, operand } => {
1626 let Self::UnaryOp {
1627 op: other_op,
1628 operand: other_operand,
1629 } = other
1630 else {
1631 return false;
1632 };
1633 op.format_equivalent(other_op) && operand.format_equivalent(other_operand)
1634 }
1635 Self::FnCall {
1636 callee,
1637 type_args,
1638 args,
1639 } => {
1640 let Self::FnCall {
1641 callee: other_callee,
1642 type_args: other_type_args,
1643 args: other_args,
1644 } = other
1645 else {
1646 return false;
1647 };
1648 callee.format_equivalent(other_callee)
1649 && type_args.format_equivalent(other_type_args)
1650 && args.format_equivalent(other_args)
1651 }
1652 Self::If {
1653 condition,
1654 then_branch,
1655 else_branch,
1656 } => {
1657 let Self::If {
1658 condition: other_condition,
1659 then_branch: other_then_branch,
1660 else_branch: other_else_branch,
1661 } = other
1662 else {
1663 return false;
1664 };
1665 condition.format_equivalent(other_condition)
1666 && then_branch.format_equivalent(other_then_branch)
1667 && else_branch.format_equivalent(other_else_branch)
1668 }
1669 Self::UnitLiteral { value, unit } => {
1670 let Self::UnitLiteral {
1671 value: other_value,
1672 unit: other_unit,
1673 } = other
1674 else {
1675 return false;
1676 };
1677 value.format_equivalent(other_value) && unit.format_equivalent(other_unit)
1678 }
1679 Self::Convert { expr, target } => {
1680 let Self::Convert {
1681 expr: other_expr,
1682 target: other_target,
1683 } = other
1684 else {
1685 return false;
1686 };
1687 expr.format_equivalent(other_expr) && target.format_equivalent(other_target)
1688 }
1689 Self::DisplayTimezone { expr, timezone } => {
1690 let Self::DisplayTimezone {
1691 expr: other_expr,
1692 timezone: other_timezone,
1693 } = other
1694 else {
1695 return false;
1696 };
1697 expr.format_equivalent(other_expr) && timezone.format_equivalent(other_timezone)
1698 }
1699 Self::FieldAccess { expr, field } => {
1700 let Self::FieldAccess {
1701 expr: other_expr,
1702 field: other_field,
1703 } = other
1704 else {
1705 return false;
1706 };
1707 expr.format_equivalent(other_expr) && field.format_equivalent(other_field)
1708 }
1709 Self::ConstructorCall {
1710 callee,
1711 generic_args,
1712 fields,
1713 } => {
1714 let Self::ConstructorCall {
1715 callee: other_callee,
1716 generic_args: other_generic_args,
1717 fields: other_fields,
1718 } = other
1719 else {
1720 return false;
1721 };
1722 callee.format_equivalent(other_callee)
1723 && generic_args.format_equivalent(other_generic_args)
1724 && fields.format_equivalent(other_fields)
1725 }
1726 Self::MapLiteral { entries } => {
1727 let Self::MapLiteral {
1728 entries: other_entries,
1729 } = other
1730 else {
1731 return false;
1732 };
1733 entries.format_equivalent(other_entries)
1734 }
1735 Self::ForComp { bindings, body } => {
1736 let Self::ForComp {
1737 bindings: other_bindings,
1738 body: other_body,
1739 } = other
1740 else {
1741 return false;
1742 };
1743 bindings.format_equivalent(other_bindings) && body.format_equivalent(other_body)
1744 }
1745 Self::IndexAccess { expr, args } => {
1746 let Self::IndexAccess {
1747 expr: other_expr,
1748 args: other_args,
1749 } = other
1750 else {
1751 return false;
1752 };
1753 expr.format_equivalent(other_expr) && args.format_equivalent(other_args)
1754 }
1755 Self::Scan {
1756 source,
1757 init,
1758 acc_name,
1759 val_name,
1760 body,
1761 } => {
1762 let Self::Scan {
1763 source: other_source,
1764 init: other_init,
1765 acc_name: other_acc_name,
1766 val_name: other_val_name,
1767 body: other_body,
1768 } = other
1769 else {
1770 return false;
1771 };
1772 source.format_equivalent(other_source)
1773 && init.format_equivalent(other_init)
1774 && acc_name.format_equivalent(other_acc_name)
1775 && val_name.format_equivalent(other_val_name)
1776 && body.format_equivalent(other_body)
1777 }
1778 Self::Unfold {
1779 init,
1780 prev_name,
1781 curr_name,
1782 body,
1783 } => {
1784 let Self::Unfold {
1785 init: other_init,
1786 prev_name: other_prev_name,
1787 curr_name: other_curr_name,
1788 body: other_body,
1789 } = other
1790 else {
1791 return false;
1792 };
1793 init.format_equivalent(other_init)
1794 && prev_name.format_equivalent(other_prev_name)
1795 && curr_name.format_equivalent(other_curr_name)
1796 && body.format_equivalent(other_body)
1797 }
1798 Self::Match { scrutinee, arms } => {
1799 let Self::Match {
1800 scrutinee: other_scrutinee,
1801 arms: other_arms,
1802 } = other
1803 else {
1804 return false;
1805 };
1806 scrutinee.format_equivalent(other_scrutinee) && arms.format_equivalent(other_arms)
1807 }
1808 Self::InlineDagRef { path, args, output } => {
1809 let Self::InlineDagRef {
1810 path: other_path,
1811 args: other_args,
1812 output: other_output,
1813 } = other
1814 else {
1815 return false;
1816 };
1817 path.format_equivalent(other_path)
1818 && args.format_equivalent(other_args)
1819 && output.format_equivalent(other_output)
1820 }
1821 Self::UnresolvedRef(reference) => {
1822 let Self::UnresolvedRef(other_reference) = other else {
1823 return false;
1824 };
1825 reference.format_equivalent(other_reference)
1826 }
1827 Self::Sugar(sugar) => {
1828 let Self::Sugar(other_sugar) = other else {
1829 return false;
1830 };
1831 sugar.format_equivalent(other_sugar)
1832 }
1833 }
1834 }
1835}
1836
1837#[cfg(test)]
1838mod tests {
1839 use super::FormatEquivalent;
1840 use crate::syntax::ast::File;
1841 use crate::syntax::parser::Parser;
1842
1843 fn parse(source: &str) -> File {
1844 Parser::new(source)
1845 .parse_file()
1846 .unwrap_or_else(|err| panic!("test source should parse: {err:?}\n---\n{source}"))
1847 }
1848
1849 #[test]
1851 fn identical_sources_are_equivalent() {
1852 let source = "node x: Dimensionless = 1.0 + 2.0 * 3.0;\n";
1853 assert!(parse(source).format_equivalent(&parse(source)));
1854 }
1855
1856 #[test]
1859 fn whitespace_differences_are_equivalent() {
1860 let dense = "node x:Dimensionless=1.0+2.0*3.0;node y:Dimensionless=@x;";
1861 let spaced = "
1862 node x: Dimensionless = 1.0 + 2.0 * 3.0;
1863
1864 node y: Dimensionless = @x;
1865 ";
1866 assert!(parse(dense).format_equivalent(&parse(spaced)));
1867 }
1868
1869 #[test]
1872 fn comment_differences_are_equivalent() {
1873 let bare = "node x: Dimensionless = 1.0;\n";
1874 let commented = "// leading\nnode x: Dimensionless = 1.0; // trailing\n";
1875 assert!(parse(bare).format_equivalent(&parse(commented)));
1876 }
1877
1878 #[test]
1879 fn number_literal_difference_is_not_equivalent() {
1880 let a = "node x: Dimensionless = 1.0;\n";
1881 let b = "node x: Dimensionless = 2.0;\n";
1882 assert!(!parse(a).format_equivalent(&parse(b)));
1883 }
1884
1885 #[test]
1886 fn operator_difference_is_not_equivalent() {
1887 let a = "node x: Dimensionless = 1.0 + 2.0;\n";
1888 let b = "node x: Dimensionless = 1.0 - 2.0;\n";
1889 assert!(!parse(a).format_equivalent(&parse(b)));
1890 }
1891
1892 #[test]
1893 fn name_difference_is_not_equivalent() {
1894 let a = "node x: Dimensionless = 1.0;\n";
1895 let b = "node y: Dimensionless = 1.0;\n";
1896 assert!(!parse(a).format_equivalent(&parse(b)));
1897 }
1898
1899 #[test]
1902 fn operand_order_is_not_equivalent() {
1903 let a = "node x: Dimensionless = 1.0 - 2.0;\n";
1904 let b = "node x: Dimensionless = 2.0 - 1.0;\n";
1905 assert!(!parse(a).format_equivalent(&parse(b)));
1906 }
1907
1908 #[test]
1911 fn missing_declaration_is_not_equivalent() {
1912 let a = "node x: Dimensionless = 1.0;\nnode y: Dimensionless = 2.0;\n";
1913 let b = "node x: Dimensionless = 1.0;\n";
1914 assert!(!parse(a).format_equivalent(&parse(b)));
1915 }
1916}