Fork of daniellemaywood.uk/gleam — Wasm codegen work
66 kB
2025 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2021 The Gleam contributors
3
4use hexpm::version::Version;
5use rand::Rng;
6use type_::{AccessorsMap, FieldMap, RecordAccessor};
7
8use super::*;
9use crate::{
10 analyse::Inferred,
11 ast::{
12 BitArrayOption, BitArraySegment, CallArg, Constant, Publicity, SrcSpan, TypedConstant,
13 TypedConstantBitArraySegmentOption,
14 },
15 build::Origin,
16 line_numbers::LineNumbers,
17 parse::LiteralFloatValue,
18 reference::{Reference, ReferenceKind},
19 type_::{
20 self, Deprecation, ModuleInterface, Opaque, References, Type, TypeAliasConstructor,
21 TypeConstructor, TypeValueConstructor, TypeValueConstructorField, TypeVariantConstructors,
22 ValueConstructor, ValueConstructorVariant,
23 expression::{Implementations, Purity},
24 prelude,
25 },
26 uid::UniqueIdGenerator,
27};
28use std::{collections::HashMap, sync::Arc};
29
30use pretty_assertions::assert_eq;
31
32fn roundtrip(input: &ModuleInterface) -> ModuleInterface {
33 let buffer = encode(input).unwrap();
34 let ids = UniqueIdGenerator::new();
35 decode(buffer.as_slice(), ids).unwrap()
36}
37
38fn constant_module(constant: TypedConstant) -> ModuleInterface {
39 ModuleInterface {
40 warnings: vec![],
41 is_internal: true,
42 package: "some_package".into(),
43 origin: Origin::Src,
44 name: "a".into(),
45 types: HashMap::new(),
46 types_value_constructors: HashMap::new(),
47 accessors: HashMap::new(),
48 values: [(
49 "one".into(),
50 ValueConstructor {
51 publicity: Publicity::Public,
52 deprecation: Deprecation::NotDeprecated,
53 type_: type_::int(),
54 variant: ValueConstructorVariant::ModuleConstant {
55 documentation: Some("Some documentation".into()),
56 literal: constant,
57 location: SrcSpan::default(),
58 module: "one/two".into(),
59 implementations: Implementations {
60 gleam: true,
61 uses_erlang_externals: false,
62 uses_javascript_externals: false,
63 can_run_on_erlang: true,
64 can_run_on_javascript: true,
65 },
66 name: "one".into(),
67 },
68 },
69 )]
70 .into(),
71 line_numbers: LineNumbers::new(""),
72 src_path: "some_path".into(),
73 minimum_required_version: Version::new(0, 1, 0),
74 type_aliases: HashMap::new(),
75 documentation: Vec::new(),
76 contains_echo: false,
77
78 references: References::default(),
79 inline_functions: HashMap::new(),
80 }
81}
82
83fn bit_array_segment_option_module(option: TypedConstantBitArraySegmentOption) -> ModuleInterface {
84 constant_module(Constant::BitArray {
85 location: Default::default(),
86 segments: vec![BitArraySegment {
87 location: Default::default(),
88 value: Box::new(Constant::Int {
89 location: Default::default(),
90 value: "1".into(),
91 int_value: 1.into(),
92 }),
93 options: vec![option],
94 type_: type_::int(),
95 }],
96 })
97}
98
99#[test]
100fn empty_module() {
101 let module = ModuleInterface {
102 warnings: vec![],
103 is_internal: true,
104 package: "some_package".into(),
105 origin: Origin::Src,
106 name: "one/two".into(),
107 types: HashMap::new(),
108 types_value_constructors: HashMap::new(),
109 values: HashMap::new(),
110 accessors: HashMap::new(),
111 line_numbers: LineNumbers::new(""),
112 src_path: "some_path".into(),
113 minimum_required_version: Version::new(0, 1, 0),
114 type_aliases: HashMap::new(),
115 documentation: Vec::new(),
116 contains_echo: false,
117
118 references: References::default(),
119 inline_functions: HashMap::new(),
120 };
121 assert_eq!(roundtrip(&module), module);
122}
123
124#[test]
125fn with_line_numbers() {
126 let module = ModuleInterface {
127 warnings: vec![],
128 is_internal: false,
129 package: "some_package".into(),
130 origin: Origin::Src,
131 name: "one/two".into(),
132 types: HashMap::new(),
133 types_value_constructors: HashMap::new(),
134 values: HashMap::new(),
135 accessors: HashMap::new(),
136 line_numbers: LineNumbers::new(
137 "const a = 1
138 const b = 2
139 const c = 3",
140 ),
141 src_path: "some_path".into(),
142 minimum_required_version: Version::new(0, 1, 0),
143 type_aliases: HashMap::new(),
144 documentation: Vec::new(),
145 contains_echo: false,
146
147 references: References::default(),
148 inline_functions: HashMap::new(),
149 };
150 assert_eq!(roundtrip(&module), module);
151}
152
153#[test]
154fn module_with_private_type() {
155 let module = ModuleInterface {
156 warnings: vec![],
157 is_internal: false,
158 package: "some_package".into(),
159 origin: Origin::Src,
160 name: "a/b".into(),
161 types: [(
162 "ListIntType".into(),
163 TypeConstructor {
164 type_: type_::list(type_::int()),
165 publicity: Publicity::Private,
166 origin: Default::default(),
167 module: "the/module".into(),
168 parameters: vec![],
169 deprecation: Deprecation::NotDeprecated,
170 documentation: None,
171 },
172 )]
173 .into(),
174 types_value_constructors: HashMap::new(),
175 values: HashMap::new(),
176 accessors: HashMap::new(),
177 line_numbers: LineNumbers::new(""),
178 src_path: "some_path".into(),
179 minimum_required_version: Version::new(0, 1, 0),
180 type_aliases: HashMap::new(),
181 documentation: Vec::new(),
182 contains_echo: false,
183
184 references: References::default(),
185 inline_functions: HashMap::new(),
186 };
187 assert_eq!(roundtrip(&module), module);
188}
189
190#[test]
191fn module_with_app_type() {
192 let module = ModuleInterface {
193 warnings: vec![],
194 is_internal: false,
195 package: "some_package".into(),
196 origin: Origin::Src,
197 name: "a/b".into(),
198 types: [(
199 "ListIntType".into(),
200 TypeConstructor {
201 type_: type_::list(type_::int()),
202 publicity: Publicity::Public,
203 origin: Default::default(),
204 module: "the/module".into(),
205 parameters: vec![],
206 deprecation: Deprecation::NotDeprecated,
207 documentation: None,
208 },
209 )]
210 .into(),
211 types_value_constructors: HashMap::new(),
212 values: HashMap::new(),
213 accessors: HashMap::new(),
214 line_numbers: LineNumbers::new(""),
215 src_path: "some_path".into(),
216 minimum_required_version: Version::new(0, 1, 0),
217 type_aliases: HashMap::new(),
218 documentation: Vec::new(),
219 contains_echo: false,
220
221 references: References::default(),
222 inline_functions: HashMap::new(),
223 };
224 assert_eq!(roundtrip(&module), module);
225}
226
227#[test]
228fn module_with_fn_type() {
229 let module = ModuleInterface {
230 warnings: vec![],
231 is_internal: false,
232 package: "some_package".into(),
233 origin: Origin::Src,
234 name: "a/b".into(),
235 types: [(
236 "FnType".into(),
237 TypeConstructor {
238 type_: type_::fn_(vec![type_::nil(), type_::float()], type_::int()),
239 publicity: Publicity::Public,
240 origin: Default::default(),
241 module: "the/module".into(),
242 parameters: vec![],
243 deprecation: Deprecation::NotDeprecated,
244 documentation: None,
245 },
246 )]
247 .into(),
248 types_value_constructors: HashMap::new(),
249 values: HashMap::new(),
250 accessors: HashMap::new(),
251 line_numbers: LineNumbers::new(""),
252 src_path: "some_path".into(),
253 minimum_required_version: Version::new(0, 1, 0),
254 type_aliases: HashMap::new(),
255 documentation: Vec::new(),
256 contains_echo: false,
257
258 references: References::default(),
259 inline_functions: HashMap::new(),
260 };
261 assert_eq!(roundtrip(&module), module);
262}
263
264#[test]
265fn module_with_tuple_type() {
266 let module = ModuleInterface {
267 warnings: vec![],
268 is_internal: false,
269 package: "some_package".into(),
270 origin: Origin::Src,
271 name: "a/b".into(),
272 types: [(
273 "TupleType".into(),
274 TypeConstructor {
275 type_: type_::tuple(vec![type_::nil(), type_::float(), type_::int()]),
276 publicity: Publicity::Public,
277 origin: Default::default(),
278 module: "the/module".into(),
279 parameters: vec![],
280 deprecation: Deprecation::NotDeprecated,
281 documentation: None,
282 },
283 )]
284 .into(),
285 types_value_constructors: HashMap::new(),
286 values: HashMap::new(),
287 accessors: HashMap::new(),
288 line_numbers: LineNumbers::new(""),
289 src_path: "some_path".into(),
290 minimum_required_version: Version::new(0, 1, 0),
291 type_aliases: HashMap::new(),
292 documentation: Vec::new(),
293 contains_echo: false,
294
295 references: References::default(),
296 inline_functions: HashMap::new(),
297 };
298 assert_eq!(roundtrip(&module), module);
299}
300
301#[test]
302fn module_with_generic_type() {
303 let t0 = type_::generic_var(0);
304 let t1 = type_::generic_var(1);
305 let t7 = type_::generic_var(7);
306 let t8 = type_::generic_var(8);
307
308 fn make(t1: Arc<Type>, t2: Arc<Type>) -> ModuleInterface {
309 ModuleInterface {
310 warnings: vec![],
311 is_internal: false,
312 package: "some_package".into(),
313 origin: Origin::Src,
314 name: "a/b".into(),
315 types: [(
316 "TupleType".into(),
317 TypeConstructor {
318 type_: type_::tuple(vec![t1.clone(), t1.clone(), t2.clone()]),
319 publicity: Publicity::Public,
320 origin: Default::default(),
321 module: "the/module".into(),
322 parameters: vec![t1, t2],
323 deprecation: Deprecation::NotDeprecated,
324 documentation: None,
325 },
326 )]
327 .into(),
328 types_value_constructors: HashMap::new(),
329 values: HashMap::new(),
330 accessors: HashMap::new(),
331 line_numbers: LineNumbers::new(""),
332 src_path: "some_path".into(),
333 minimum_required_version: Version::new(0, 1, 0),
334 type_aliases: HashMap::new(),
335 documentation: Vec::new(),
336 contains_echo: false,
337 references: References::default(),
338 inline_functions: HashMap::new(),
339 }
340 }
341
342 assert_eq!(roundtrip(&make(t7, t8)), make(t0, t1));
343}
344
345#[test]
346fn module_with_type_links() {
347 let linked_type = type_::link(type_::int());
348 let type_ = type_::int();
349
350 fn make(type_: Arc<Type>) -> ModuleInterface {
351 ModuleInterface {
352 warnings: vec![],
353 is_internal: false,
354 package: "some_package".into(),
355 origin: Origin::Src,
356 name: "a".into(),
357 types: [(
358 "SomeType".into(),
359 TypeConstructor {
360 type_,
361 publicity: Publicity::Public,
362 origin: Default::default(),
363 module: "a".into(),
364 parameters: vec![],
365 deprecation: Deprecation::NotDeprecated,
366 documentation: None,
367 },
368 )]
369 .into(),
370 types_value_constructors: HashMap::new(),
371 values: HashMap::new(),
372 accessors: HashMap::new(),
373 line_numbers: LineNumbers::new(""),
374 src_path: "some_path".into(),
375 minimum_required_version: Version::new(0, 1, 0),
376 type_aliases: HashMap::new(),
377 documentation: Vec::new(),
378 contains_echo: false,
379 references: References::default(),
380 inline_functions: HashMap::new(),
381 }
382 }
383
384 assert_eq!(roundtrip(&make(linked_type)), make(type_));
385}
386
387#[test]
388fn module_with_type_constructor_documentation() {
389 let linked_type = type_::link(type_::int());
390 let type_ = type_::int();
391
392 fn make(type_: Arc<Type>) -> ModuleInterface {
393 ModuleInterface {
394 warnings: vec![],
395 is_internal: false,
396 package: "some_package".into(),
397 origin: Origin::Src,
398 name: "a".into(),
399 types: [(
400 "SomeType".into(),
401 TypeConstructor {
402 type_,
403 publicity: Publicity::Public,
404 origin: Default::default(),
405 module: "a".into(),
406 parameters: vec![],
407 deprecation: Deprecation::NotDeprecated,
408 documentation: Some("type documentation".into()),
409 },
410 )]
411 .into(),
412 types_value_constructors: HashMap::new(),
413 values: HashMap::new(),
414 accessors: HashMap::new(),
415 line_numbers: LineNumbers::new(""),
416 src_path: "some_path".into(),
417 minimum_required_version: Version::new(0, 1, 0),
418 type_aliases: HashMap::new(),
419 documentation: Vec::new(),
420 contains_echo: false,
421 references: References::default(),
422 inline_functions: HashMap::new(),
423 }
424 }
425
426 assert_eq!(roundtrip(&make(linked_type)), make(type_));
427}
428
429#[test]
430fn module_with_type_constructor_origin() {
431 let linked_type = type_::link(type_::int());
432 let type_ = type_::int();
433
434 fn make(type_: Arc<Type>) -> ModuleInterface {
435 ModuleInterface {
436 warnings: vec![],
437 is_internal: false,
438 package: "some_package".into(),
439 origin: Origin::Src,
440 name: "a".into(),
441 types: [(
442 "SomeType".into(),
443 TypeConstructor {
444 type_,
445 publicity: Publicity::Public,
446 origin: SrcSpan {
447 start: 535,
448 end: 543,
449 },
450 module: "a".into(),
451 parameters: vec![],
452 deprecation: Deprecation::NotDeprecated,
453 documentation: None,
454 },
455 )]
456 .into(),
457 types_value_constructors: HashMap::new(),
458 values: HashMap::new(),
459 accessors: HashMap::new(),
460 line_numbers: LineNumbers::new(""),
461 src_path: "some_path".into(),
462 minimum_required_version: Version::new(0, 1, 0),
463 type_aliases: HashMap::new(),
464 documentation: Vec::new(),
465 contains_echo: false,
466 references: References::default(),
467 inline_functions: HashMap::new(),
468 }
469 }
470
471 assert_eq!(roundtrip(&make(linked_type)), make(type_));
472}
473
474#[test]
475fn module_type_to_constructors_mapping() {
476 let module = ModuleInterface {
477 warnings: vec![],
478 is_internal: false,
479 package: "some_package".into(),
480 origin: Origin::Src,
481 name: "a".into(),
482 types: HashMap::new(),
483 types_value_constructors: [(
484 "SomeType".into(),
485 TypeVariantConstructors {
486 type_parameters_ids: vec![0, 1, 2],
487 variants: vec![TypeValueConstructor {
488 name: "One".into(),
489 parameters: vec![],
490 documentation: Some("Some documentation".into()),
491 }],
492 opaque: Opaque::NotOpaque,
493 },
494 )]
495 .into(),
496 accessors: HashMap::new(),
497 values: HashMap::new(),
498 line_numbers: LineNumbers::new(""),
499 src_path: "some_path".into(),
500 minimum_required_version: Version::new(0, 1, 0),
501 type_aliases: HashMap::new(),
502 documentation: Vec::new(),
503 contains_echo: false,
504
505 references: References::default(),
506 inline_functions: HashMap::new(),
507 };
508
509 assert_eq!(roundtrip(&module), module);
510}
511
512#[test]
513fn module_fn_value() {
514 let module = ModuleInterface {
515 warnings: vec![],
516 is_internal: false,
517 package: "some_package".into(),
518 origin: Origin::Src,
519 name: "a".into(),
520 types: HashMap::new(),
521 types_value_constructors: HashMap::new(),
522 accessors: HashMap::new(),
523 values: [(
524 "one".into(),
525 ValueConstructor {
526 publicity: Publicity::Public,
527 deprecation: Deprecation::NotDeprecated,
528 type_: type_::int(),
529 variant: ValueConstructorVariant::ModuleFn {
530 documentation: Some("wobble!".into()),
531 name: "one".into(),
532 field_map: None,
533 module: "a".into(),
534 arity: 5,
535 location: SrcSpan {
536 start: 535,
537 end: 1100,
538 },
539 external_erlang: None,
540 external_javascript: None,
541 implementations: Implementations {
542 gleam: true,
543 uses_erlang_externals: false,
544 uses_javascript_externals: false,
545 can_run_on_erlang: true,
546 can_run_on_javascript: true,
547 },
548 purity: Purity::Pure,
549 },
550 },
551 )]
552 .into(),
553 line_numbers: LineNumbers::new(""),
554 src_path: "some_path".into(),
555 minimum_required_version: Version::new(0, 1, 0),
556 type_aliases: HashMap::new(),
557 documentation: Vec::new(),
558 contains_echo: false,
559
560 references: References::default(),
561 inline_functions: HashMap::new(),
562 };
563 assert_eq!(roundtrip(&module), module);
564}
565
566#[test]
567fn deprecated_module_fn_value() {
568 let module = ModuleInterface {
569 warnings: vec![],
570 is_internal: false,
571 package: "some_package".into(),
572 origin: Origin::Src,
573 name: "a".into(),
574 types: HashMap::new(),
575 types_value_constructors: HashMap::new(),
576 accessors: HashMap::new(),
577 values: [(
578 "one".into(),
579 ValueConstructor {
580 publicity: Publicity::Public,
581 deprecation: Deprecation::Deprecated {
582 message: "wibble wobble".into(),
583 },
584 type_: type_::int(),
585 variant: ValueConstructorVariant::ModuleFn {
586 documentation: Some("wobble!".into()),
587 name: "one".into(),
588 field_map: None,
589 module: "a".into(),
590 arity: 5,
591 location: SrcSpan {
592 start: 535,
593 end: 1100,
594 },
595 external_erlang: None,
596 external_javascript: None,
597 implementations: Implementations {
598 gleam: true,
599 uses_erlang_externals: false,
600 uses_javascript_externals: false,
601 can_run_on_erlang: true,
602 can_run_on_javascript: true,
603 },
604 purity: Purity::Pure,
605 },
606 },
607 )]
608 .into(),
609 line_numbers: LineNumbers::new(""),
610 src_path: "some_path".into(),
611 minimum_required_version: Version::new(0, 1, 0),
612 type_aliases: HashMap::new(),
613 documentation: Vec::new(),
614 contains_echo: false,
615
616 references: References::default(),
617 inline_functions: HashMap::new(),
618 };
619 assert_eq!(roundtrip(&module), module);
620}
621
622#[test]
623fn private_module_fn_value() {
624 let module = ModuleInterface {
625 warnings: vec![],
626 is_internal: false,
627 package: "some_package".into(),
628 origin: Origin::Src,
629 name: "a".into(),
630 types: HashMap::new(),
631 types_value_constructors: HashMap::new(),
632 accessors: HashMap::new(),
633 values: [(
634 "one".into(),
635 ValueConstructor {
636 publicity: Publicity::Private,
637 deprecation: Deprecation::NotDeprecated,
638 type_: type_::int(),
639 variant: ValueConstructorVariant::ModuleFn {
640 documentation: Some("wobble!".into()),
641 name: "one".into(),
642 field_map: None,
643 module: "a".into(),
644 arity: 5,
645 location: SrcSpan {
646 start: 535,
647 end: 1100,
648 },
649 external_erlang: None,
650 external_javascript: None,
651 implementations: Implementations {
652 gleam: true,
653 uses_erlang_externals: false,
654 uses_javascript_externals: false,
655 can_run_on_erlang: true,
656 can_run_on_javascript: true,
657 },
658 purity: Purity::Pure,
659 },
660 },
661 )]
662 .into(),
663 line_numbers: LineNumbers::new(""),
664 src_path: "some_path".into(),
665 minimum_required_version: Version::new(0, 1, 0),
666 type_aliases: HashMap::new(),
667 documentation: Vec::new(),
668 contains_echo: false,
669
670 references: References::default(),
671 inline_functions: HashMap::new(),
672 };
673
674 assert_eq!(roundtrip(&module), module);
675}
676
677// https://github.com/gleam-lang/gleam/commit/c8f3bd0ddbf61c27ea35f37297058ecca7515f6c
678#[test]
679fn module_fn_value_regression() {
680 let module = ModuleInterface {
681 warnings: vec![],
682 is_internal: false,
683 package: "some_package".into(),
684 origin: Origin::Src,
685 name: "a/b/c".into(),
686 types: HashMap::new(),
687 types_value_constructors: HashMap::new(),
688 accessors: HashMap::new(),
689 values: [(
690 "one".into(),
691 ValueConstructor {
692 publicity: Publicity::Public,
693 deprecation: Deprecation::NotDeprecated,
694 type_: type_::int(),
695 variant: ValueConstructorVariant::ModuleFn {
696 documentation: Some("wabble!".into()),
697 name: "one".into(),
698 field_map: None,
699 module: "a".into(),
700 arity: 5,
701 location: SrcSpan {
702 start: 52,
703 end: 1100,
704 },
705 external_erlang: None,
706 external_javascript: None,
707 implementations: Implementations {
708 gleam: true,
709 uses_erlang_externals: false,
710 uses_javascript_externals: false,
711 can_run_on_erlang: true,
712 can_run_on_javascript: true,
713 },
714 purity: Purity::TrustedPure,
715 },
716 },
717 )]
718 .into(),
719 line_numbers: LineNumbers::new(""),
720 src_path: "some_path".into(),
721 minimum_required_version: Version::new(0, 1, 0),
722 type_aliases: HashMap::new(),
723 documentation: Vec::new(),
724 contains_echo: false,
725
726 references: References::default(),
727 inline_functions: HashMap::new(),
728 };
729
730 assert_eq!(roundtrip(&module), module);
731}
732
733#[test]
734fn module_fn_value_with_field_map() {
735 let module = ModuleInterface {
736 warnings: vec![],
737 is_internal: false,
738 package: "some_package".into(),
739 origin: Origin::Src,
740 name: "a".into(),
741 types: HashMap::new(),
742 types_value_constructors: HashMap::new(),
743 accessors: HashMap::new(),
744 values: [(
745 "one".into(),
746 ValueConstructor {
747 publicity: Publicity::Public,
748 deprecation: Deprecation::NotDeprecated,
749 type_: type_::int(),
750 variant: ValueConstructorVariant::ModuleFn {
751 documentation: Some("wubble!".into()),
752 name: "one".into(),
753 field_map: Some(FieldMap {
754 arity: 20,
755 fields: [("ok".into(), 5), ("ko".into(), 7)].into(),
756 }),
757 external_erlang: None,
758 external_javascript: None,
759 module: "a".into(),
760 arity: 5,
761 location: SrcSpan { start: 2, end: 11 },
762 implementations: Implementations {
763 gleam: true,
764 uses_erlang_externals: false,
765 uses_javascript_externals: false,
766 can_run_on_erlang: true,
767 can_run_on_javascript: true,
768 },
769 purity: Purity::Pure,
770 },
771 },
772 )]
773 .into(),
774 line_numbers: LineNumbers::new(""),
775 src_path: "some_path".into(),
776 minimum_required_version: Version::new(0, 1, 0),
777 type_aliases: HashMap::new(),
778 documentation: Vec::new(),
779 contains_echo: false,
780
781 references: References::default(),
782 inline_functions: HashMap::new(),
783 };
784
785 assert_eq!(roundtrip(&module), module);
786}
787
788#[test]
789fn record_value() {
790 let mut random = rand::rng();
791
792 let module = ModuleInterface {
793 warnings: vec![],
794 is_internal: false,
795 package: "some_package".into(),
796 origin: Origin::Src,
797 name: "a".into(),
798 types: HashMap::new(),
799 types_value_constructors: HashMap::new(),
800 accessors: HashMap::new(),
801 values: [(
802 "one".into(),
803 ValueConstructor {
804 publicity: Publicity::Public,
805 deprecation: Deprecation::NotDeprecated,
806 type_: type_::int(),
807 variant: ValueConstructorVariant::Record {
808 documentation: Some("webble!".into()),
809 name: "one".into(),
810 module: "themodule".into(),
811 field_map: None,
812 arity: random.random(),
813 variants_count: random.random(),
814 location: SrcSpan {
815 start: random.random(),
816 end: random.random(),
817 },
818 variant_index: random.random(),
819 },
820 },
821 )]
822 .into(),
823 line_numbers: LineNumbers::new(""),
824 src_path: "some_path".into(),
825 minimum_required_version: Version::new(0, 1, 0),
826 type_aliases: HashMap::new(),
827 documentation: Vec::new(),
828 contains_echo: false,
829
830 references: References::default(),
831 inline_functions: HashMap::new(),
832 };
833
834 assert_eq!(roundtrip(&module), module);
835}
836
837#[test]
838fn record_value_with_field_map() {
839 let mut random = rand::rng();
840
841 let module = ModuleInterface {
842 warnings: vec![],
843 is_internal: false,
844 package: "some_package".into(),
845 origin: Origin::Src,
846 name: "a".into(),
847 types: HashMap::new(),
848 types_value_constructors: HashMap::new(),
849 accessors: HashMap::new(),
850 values: [(
851 "one".into(),
852 ValueConstructor {
853 publicity: Publicity::Public,
854 deprecation: Deprecation::NotDeprecated,
855 type_: type_::int(),
856 variant: ValueConstructorVariant::Record {
857 documentation: Some("wybble!".into()),
858 module: "themodule".into(),
859 name: "one".into(),
860 field_map: Some(FieldMap {
861 arity: random.random(),
862 fields: [
863 ("ok".into(), random.random()),
864 ("ko".into(), random.random()),
865 ]
866 .into(),
867 }),
868 arity: random.random(),
869 variants_count: random.random(),
870 variant_index: random.random(),
871 location: SrcSpan {
872 start: random.random(),
873 end: random.random(),
874 },
875 },
876 },
877 )]
878 .into(),
879 line_numbers: LineNumbers::new(""),
880 src_path: "some_path".into(),
881 minimum_required_version: Version::new(0, 1, 0),
882 type_aliases: HashMap::new(),
883 documentation: Vec::new(),
884 contains_echo: false,
885
886 references: References::default(),
887 inline_functions: HashMap::new(),
888 };
889
890 assert_eq!(roundtrip(&module), module);
891}
892
893#[test]
894fn accessors() {
895 let accessors1 = [
896 (
897 "a".into(),
898 RecordAccessor {
899 index: 6,
900 label: "siiixxx".into(),
901 type_: type_::nil(),
902 documentation: Some("Here is some documentation".into()),
903 },
904 ),
905 (
906 "a".into(),
907 RecordAccessor {
908 index: 5,
909 label: "fiveee".into(),
910 type_: type_::float(),
911 documentation: None,
912 },
913 ),
914 ];
915
916 let accessors2 = [(
917 "a".into(),
918 RecordAccessor {
919 index: 1,
920 label: "ok".into(),
921 type_: type_::float(),
922 documentation: Some("Documentation for the ok field".into()),
923 },
924 )];
925
926 let module = ModuleInterface {
927 warnings: vec![],
928 is_internal: false,
929 package: "some_package".into(),
930 origin: Origin::Src,
931 name: "a".into(),
932 types: HashMap::new(),
933 types_value_constructors: HashMap::new(),
934 values: HashMap::new(),
935 accessors: [
936 (
937 "one".into(),
938 AccessorsMap {
939 publicity: Publicity::Public,
940 type_: type_::int(),
941 shared_accessors: accessors1.clone().into(),
942 variant_specific_accessors: vec![accessors1.into()],
943 variant_positional_accessors: vec![vec![type_::int(), type_::float()]],
944 },
945 ),
946 (
947 "two".into(),
948 AccessorsMap {
949 publicity: Publicity::Public,
950 type_: type_::int(),
951 shared_accessors: accessors2.clone().into(),
952 variant_specific_accessors: vec![accessors2.into()],
953 variant_positional_accessors: vec![vec![]],
954 },
955 ),
956 ]
957 .into(),
958 line_numbers: LineNumbers::new(""),
959 src_path: "some_path".into(),
960 minimum_required_version: Version::new(0, 1, 0),
961 type_aliases: HashMap::new(),
962 documentation: Vec::new(),
963 contains_echo: false,
964
965 references: References::default(),
966 inline_functions: HashMap::new(),
967 };
968
969 assert_eq!(roundtrip(&module), module);
970}
971
972#[test]
973fn private_accessors() {
974 let accessors1 = [
975 (
976 "a".into(),
977 RecordAccessor {
978 index: 6,
979 label: "siiixxx".into(),
980 type_: type_::nil(),
981 documentation: None,
982 },
983 ),
984 (
985 "a".into(),
986 RecordAccessor {
987 index: 5,
988 label: "fiveee".into(),
989 type_: type_::float(),
990 documentation: None,
991 },
992 ),
993 ];
994
995 let accessors2 = [(
996 "a".into(),
997 RecordAccessor {
998 index: 1,
999 label: "ok".into(),
1000 type_: type_::float(),
1001 documentation: None,
1002 },
1003 )];
1004
1005 let module = ModuleInterface {
1006 warnings: vec![],
1007 is_internal: false,
1008 package: "some_package".into(),
1009 origin: Origin::Src,
1010 name: "a".into(),
1011 types: HashMap::new(),
1012 types_value_constructors: HashMap::new(),
1013 contains_echo: false,
1014 values: HashMap::new(),
1015 accessors: [
1016 (
1017 "one".into(),
1018 AccessorsMap {
1019 publicity: Publicity::Private,
1020 type_: type_::int(),
1021 shared_accessors: accessors1.clone().into(),
1022 variant_specific_accessors: vec![accessors1.into()],
1023 variant_positional_accessors: vec![vec![type_::int(), type_::float()]],
1024 },
1025 ),
1026 (
1027 "two".into(),
1028 AccessorsMap {
1029 publicity: Publicity::Public,
1030 type_: type_::int(),
1031 shared_accessors: accessors2.clone().into(),
1032 variant_specific_accessors: vec![accessors2.into()],
1033 variant_positional_accessors: vec![vec![]],
1034 },
1035 ),
1036 ]
1037 .into(),
1038 line_numbers: LineNumbers::new(""),
1039 src_path: "some_path".into(),
1040 minimum_required_version: Version::new(0, 1, 0),
1041 type_aliases: HashMap::new(),
1042 documentation: Vec::new(),
1043 references: References::default(),
1044 inline_functions: HashMap::new(),
1045 };
1046
1047 assert_eq!(roundtrip(&module), module);
1048}
1049
1050#[test]
1051fn constant_int() {
1052 let module = constant_module(Constant::Int {
1053 location: Default::default(),
1054 value: "100".into(),
1055 int_value: 100.into(),
1056 });
1057
1058 assert_eq!(roundtrip(&module), module);
1059}
1060
1061#[test]
1062fn constant_float() {
1063 let module = constant_module(Constant::Float {
1064 location: Default::default(),
1065 value: "1.0".into(),
1066 float_value: LiteralFloatValue::ONE,
1067 });
1068
1069 assert_eq!(roundtrip(&module), module);
1070}
1071
1072#[test]
1073fn constant_string() {
1074 let module = constant_module(Constant::String {
1075 location: Default::default(),
1076 value: "hello".into(),
1077 });
1078
1079 assert_eq!(roundtrip(&module), module);
1080}
1081
1082#[test]
1083fn constant_tuple() {
1084 let int_float_tuple_type = type_::tuple(vec![type_::int(), type_::float()]);
1085 let module = constant_module(Constant::Tuple {
1086 location: Default::default(),
1087 type_: type_::tuple(vec![
1088 type_::int(),
1089 type_::float(),
1090 int_float_tuple_type.clone(),
1091 ]),
1092 elements: vec![
1093 Constant::Int {
1094 location: Default::default(),
1095 value: "1".into(),
1096 int_value: 1.into(),
1097 },
1098 Constant::Float {
1099 location: Default::default(),
1100 value: "1.0".into(),
1101 float_value: LiteralFloatValue::ONE,
1102 },
1103 Constant::Tuple {
1104 location: Default::default(),
1105 type_: int_float_tuple_type,
1106 elements: vec![
1107 Constant::Int {
1108 location: Default::default(),
1109 value: "1".into(),
1110 int_value: 1.into(),
1111 },
1112 Constant::Float {
1113 location: Default::default(),
1114 value: "1.0".into(),
1115 float_value: LiteralFloatValue::ONE,
1116 },
1117 ],
1118 },
1119 ],
1120 });
1121
1122 assert_eq!(roundtrip(&module), module);
1123}
1124
1125#[test]
1126fn constant_list() {
1127 let module = constant_module(Constant::List {
1128 location: Default::default(),
1129 type_: type_::int(),
1130 elements: vec![
1131 Constant::Int {
1132 location: Default::default(),
1133 value: "1".into(),
1134 int_value: 1.into(),
1135 },
1136 Constant::Int {
1137 location: Default::default(),
1138 value: "2".into(),
1139 int_value: 2.into(),
1140 },
1141 Constant::Int {
1142 location: Default::default(),
1143 value: "3".into(),
1144 int_value: 3.into(),
1145 },
1146 ],
1147 tail: Some(Box::new(Constant::List {
1148 location: Default::default(),
1149 type_: type_::list(type_::int()),
1150 elements: vec![
1151 Constant::Int {
1152 location: Default::default(),
1153 value: "4".into(),
1154 int_value: 4.into(),
1155 },
1156 Constant::Int {
1157 location: Default::default(),
1158 value: "5".into(),
1159 int_value: 5.into(),
1160 },
1161 ],
1162 tail: None,
1163 })),
1164 });
1165
1166 assert_eq!(roundtrip(&module), module);
1167}
1168
1169#[test]
1170fn constant_record() {
1171 let module = constant_module(Constant::Record {
1172 location: Default::default(),
1173 module: None,
1174 name: "".into(),
1175 arguments: Some(vec![
1176 CallArg {
1177 implicit: None,
1178 label: None,
1179 location: Default::default(),
1180 value: Constant::Float {
1181 location: Default::default(),
1182 value: "0.0".into(),
1183 float_value: LiteralFloatValue::ZERO,
1184 },
1185 },
1186 CallArg {
1187 implicit: None,
1188 label: None,
1189 location: Default::default(),
1190 value: Constant::Int {
1191 location: Default::default(),
1192 value: "1".into(),
1193 int_value: 1.into(),
1194 },
1195 },
1196 ]),
1197 type_: type_::int(),
1198 field_map: Inferred::Unknown,
1199 record_constructor: None,
1200 });
1201
1202 assert_eq!(roundtrip(&module), module);
1203}
1204
1205#[test]
1206fn constant_var() {
1207 let one_original = Constant::Int {
1208 location: Default::default(),
1209 value: "1".into(),
1210 int_value: 1.into(),
1211 };
1212
1213 let one = Constant::Var {
1214 location: Default::default(),
1215 module: None,
1216 name: "one_original".into(),
1217 type_: type_::int(),
1218 constructor: Some(Box::from(ValueConstructor {
1219 publicity: Publicity::Public,
1220 deprecation: Deprecation::NotDeprecated,
1221 type_: type_::int(),
1222 variant: ValueConstructorVariant::ModuleConstant {
1223 documentation: Some("some doc".into()),
1224 literal: one_original.clone(),
1225 location: SrcSpan::default(),
1226 module: "one/two".into(),
1227 implementations: Implementations {
1228 gleam: true,
1229 uses_erlang_externals: false,
1230 uses_javascript_externals: false,
1231 can_run_on_erlang: true,
1232 can_run_on_javascript: true,
1233 },
1234 name: "one_original".into(),
1235 },
1236 })),
1237 };
1238
1239 let module = ModuleInterface {
1240 warnings: vec![],
1241 is_internal: false,
1242 package: "some_package".into(),
1243 origin: Origin::Src,
1244 name: "a".into(),
1245 types: HashMap::new(),
1246 types_value_constructors: HashMap::new(),
1247 accessors: HashMap::new(),
1248 values: [
1249 (
1250 "one".into(),
1251 ValueConstructor {
1252 publicity: Publicity::Public,
1253 deprecation: Deprecation::NotDeprecated,
1254 type_: type_::int(),
1255 variant: ValueConstructorVariant::ModuleConstant {
1256 documentation: Some("some doc!!!!!!!!!".into()),
1257 literal: one,
1258 location: SrcSpan::default(),
1259 module: "one/two".into(),
1260 implementations: Implementations {
1261 gleam: true,
1262 uses_erlang_externals: false,
1263 uses_javascript_externals: false,
1264 can_run_on_erlang: true,
1265 can_run_on_javascript: true,
1266 },
1267 name: "one".into(),
1268 },
1269 },
1270 ),
1271 (
1272 "one_original".into(),
1273 ValueConstructor {
1274 publicity: Publicity::Public,
1275 deprecation: Deprecation::NotDeprecated,
1276 type_: type_::int(),
1277 variant: ValueConstructorVariant::ModuleConstant {
1278 documentation: Some("some doc yeah".into()),
1279 literal: one_original,
1280 location: SrcSpan::default(),
1281 module: "one/two".into(),
1282 implementations: Implementations {
1283 gleam: true,
1284 uses_erlang_externals: false,
1285 uses_javascript_externals: false,
1286 can_run_on_erlang: true,
1287 can_run_on_javascript: true,
1288 },
1289 name: "one_original".into(),
1290 },
1291 },
1292 ),
1293 ]
1294 .into(),
1295 line_numbers: LineNumbers::new(""),
1296 src_path: "some_path".into(),
1297 minimum_required_version: Version::new(0, 1, 0),
1298 type_aliases: HashMap::new(),
1299 documentation: Vec::new(),
1300 contains_echo: false,
1301
1302 references: References::default(),
1303 inline_functions: HashMap::new(),
1304 };
1305
1306 assert_eq!(roundtrip(&module), module);
1307}
1308
1309#[test]
1310fn constant_bit_array() {
1311 let module = constant_module(Constant::BitArray {
1312 location: Default::default(),
1313 segments: vec![],
1314 });
1315 assert_eq!(roundtrip(&module), module);
1316}
1317
1318#[test]
1319fn constant_bit_array_unit() {
1320 let module = bit_array_segment_option_module(BitArrayOption::Unit {
1321 location: Default::default(),
1322 value: 234,
1323 });
1324 assert_eq!(roundtrip(&module), module);
1325}
1326
1327#[test]
1328fn constant_bit_array_float() {
1329 let module = bit_array_segment_option_module(BitArrayOption::Float {
1330 location: Default::default(),
1331 });
1332 assert_eq!(roundtrip(&module), module);
1333}
1334
1335#[test]
1336fn constant_bit_array_int() {
1337 let module = bit_array_segment_option_module(BitArrayOption::Int {
1338 location: Default::default(),
1339 });
1340 assert_eq!(roundtrip(&module), module);
1341}
1342
1343#[test]
1344fn constant_bit_array_size() {
1345 let module = bit_array_segment_option_module(BitArrayOption::Size {
1346 location: Default::default(),
1347 value: Box::new(Constant::Int {
1348 location: Default::default(),
1349 value: "1".into(),
1350 int_value: 1.into(),
1351 }),
1352 short_form: false,
1353 });
1354 assert_eq!(roundtrip(&module), module);
1355}
1356
1357#[test]
1358fn constant_bit_array_size_short_form() {
1359 let module = bit_array_segment_option_module(BitArrayOption::Size {
1360 location: Default::default(),
1361 value: Box::new(Constant::Int {
1362 location: Default::default(),
1363 value: "1".into(),
1364 int_value: 1.into(),
1365 }),
1366 short_form: true,
1367 });
1368 assert_eq!(roundtrip(&module), module);
1369}
1370
1371#[test]
1372fn constant_bit_array_bit_arry() {
1373 let module = bit_array_segment_option_module(BitArrayOption::Bits {
1374 location: Default::default(),
1375 });
1376 assert_eq!(roundtrip(&module), module);
1377}
1378
1379#[test]
1380fn constant_bit_array_utf8() {
1381 let module = bit_array_segment_option_module(BitArrayOption::Utf8 {
1382 location: Default::default(),
1383 });
1384 assert_eq!(roundtrip(&module), module);
1385}
1386
1387#[test]
1388fn constant_bit_array_utf16() {
1389 let module = bit_array_segment_option_module(BitArrayOption::Utf16 {
1390 location: Default::default(),
1391 });
1392 assert_eq!(roundtrip(&module), module);
1393}
1394
1395#[test]
1396fn constant_bit_array_utf32() {
1397 let module = bit_array_segment_option_module(BitArrayOption::Utf32 {
1398 location: Default::default(),
1399 });
1400 assert_eq!(roundtrip(&module), module);
1401}
1402
1403#[test]
1404fn constant_bit_array_utf8codepoint() {
1405 let module = bit_array_segment_option_module(BitArrayOption::Utf8Codepoint {
1406 location: Default::default(),
1407 });
1408 assert_eq!(roundtrip(&module), module);
1409}
1410
1411#[test]
1412fn constant_bit_array_utf16codepoint() {
1413 let module = bit_array_segment_option_module(BitArrayOption::Utf16Codepoint {
1414 location: Default::default(),
1415 });
1416 assert_eq!(roundtrip(&module), module);
1417}
1418
1419#[test]
1420fn constant_bit_array_utf32codepoint() {
1421 let module = bit_array_segment_option_module(BitArrayOption::Utf32Codepoint {
1422 location: Default::default(),
1423 });
1424 assert_eq!(roundtrip(&module), module);
1425}
1426
1427#[test]
1428fn constant_bit_array_signed() {
1429 let module = bit_array_segment_option_module(BitArrayOption::Signed {
1430 location: Default::default(),
1431 });
1432 assert_eq!(roundtrip(&module), module);
1433}
1434
1435#[test]
1436fn constant_bit_array_unsigned() {
1437 let module = bit_array_segment_option_module(BitArrayOption::Unsigned {
1438 location: Default::default(),
1439 });
1440 assert_eq!(roundtrip(&module), module);
1441}
1442
1443#[test]
1444fn constant_bit_array_big() {
1445 let module = bit_array_segment_option_module(BitArrayOption::Big {
1446 location: Default::default(),
1447 });
1448 assert_eq!(roundtrip(&module), module);
1449}
1450
1451#[test]
1452fn constant_bit_array_little() {
1453 let module = bit_array_segment_option_module(BitArrayOption::Little {
1454 location: Default::default(),
1455 });
1456 assert_eq!(roundtrip(&module), module);
1457}
1458
1459#[test]
1460fn constant_bit_array_native() {
1461 let module = bit_array_segment_option_module(BitArrayOption::Native {
1462 location: Default::default(),
1463 });
1464 assert_eq!(roundtrip(&module), module);
1465}
1466
1467#[test]
1468fn deprecated_type() {
1469 let module = ModuleInterface {
1470 warnings: vec![],
1471 is_internal: false,
1472 package: "some_package".into(),
1473 origin: Origin::Src,
1474 name: "a/b".into(),
1475 types: [(
1476 "ListIntType".into(),
1477 TypeConstructor {
1478 type_: type_::list(type_::int()),
1479 publicity: Publicity::Public,
1480 origin: Default::default(),
1481 module: "the/module".into(),
1482 parameters: vec![],
1483 deprecation: Deprecation::Deprecated {
1484 message: "oh no".into(),
1485 },
1486 documentation: None,
1487 },
1488 )]
1489 .into(),
1490 types_value_constructors: HashMap::new(),
1491 values: HashMap::new(),
1492 accessors: HashMap::new(),
1493 line_numbers: LineNumbers::new(""),
1494 src_path: "some_path".into(),
1495 minimum_required_version: Version::new(0, 1, 0),
1496 type_aliases: HashMap::new(),
1497 documentation: Vec::new(),
1498 contains_echo: false,
1499
1500 references: References::default(),
1501 inline_functions: HashMap::new(),
1502 };
1503 assert_eq!(roundtrip(&module), module);
1504}
1505
1506#[test]
1507fn module_fn_value_with_external_implementations() {
1508 let module = ModuleInterface {
1509 warnings: vec![],
1510 is_internal: false,
1511 package: "some_package".into(),
1512 origin: Origin::Src,
1513 name: "a/b/c".into(),
1514 types: HashMap::new(),
1515 types_value_constructors: HashMap::new(),
1516 accessors: HashMap::new(),
1517 values: [(
1518 "one".into(),
1519 ValueConstructor {
1520 publicity: Publicity::Public,
1521 deprecation: Deprecation::NotDeprecated,
1522 type_: type_::int(),
1523 variant: ValueConstructorVariant::ModuleFn {
1524 documentation: Some("wabble!".into()),
1525 name: "one".into(),
1526 field_map: None,
1527 module: "a".into(),
1528 arity: 5,
1529 location: SrcSpan {
1530 start: 52,
1531 end: 1100,
1532 },
1533 external_erlang: Some(("wibble".into(), "wobble".into())),
1534 external_javascript: Some(("wobble".into(), "wibble".into())),
1535 implementations: Implementations {
1536 gleam: false,
1537 uses_erlang_externals: true,
1538 uses_javascript_externals: true,
1539 can_run_on_erlang: false,
1540 can_run_on_javascript: true,
1541 },
1542 purity: Purity::Impure,
1543 },
1544 },
1545 )]
1546 .into(),
1547 line_numbers: LineNumbers::new(""),
1548 src_path: "some_path".into(),
1549 minimum_required_version: Version::new(0, 1, 0),
1550 type_aliases: HashMap::new(),
1551 documentation: Vec::new(),
1552 contains_echo: false,
1553 references: References::default(),
1554 inline_functions: HashMap::new(),
1555 };
1556
1557 assert_eq!(roundtrip(&module), module);
1558}
1559
1560#[test]
1561fn module_containing_echo() {
1562 let module = ModuleInterface {
1563 warnings: vec![],
1564 is_internal: false,
1565 package: "some_package".into(),
1566 origin: Origin::Src,
1567 name: "a/b/c".into(),
1568 types: HashMap::new(),
1569 types_value_constructors: HashMap::new(),
1570 accessors: HashMap::new(),
1571 values: [].into(),
1572 line_numbers: LineNumbers::new(""),
1573 src_path: "some_path".into(),
1574 minimum_required_version: Version::new(0, 1, 0),
1575 type_aliases: HashMap::new(),
1576 documentation: Vec::new(),
1577 contains_echo: true,
1578 references: References::default(),
1579 inline_functions: HashMap::new(),
1580 };
1581
1582 assert_eq!(roundtrip(&module), module);
1583}
1584
1585#[test]
1586fn internal_module_fn() {
1587 let module = ModuleInterface {
1588 warnings: vec![],
1589 is_internal: false,
1590 package: "some_package".into(),
1591 origin: Origin::Src,
1592 name: "a/b/c".into(),
1593 types: HashMap::new(),
1594 types_value_constructors: HashMap::new(),
1595 accessors: HashMap::new(),
1596 values: [(
1597 "one".into(),
1598 ValueConstructor {
1599 publicity: Publicity::Internal {
1600 attribute_location: None,
1601 },
1602 deprecation: Deprecation::NotDeprecated,
1603 type_: type_::int(),
1604 variant: ValueConstructorVariant::ModuleFn {
1605 documentation: Some("wabble!".into()),
1606 name: "one".into(),
1607 field_map: None,
1608 module: "a".into(),
1609 arity: 5,
1610 location: SrcSpan {
1611 start: 52,
1612 end: 1100,
1613 },
1614 external_erlang: Some(("wibble".into(), "wobble".into())),
1615 external_javascript: Some(("wobble".into(), "wibble".into())),
1616 implementations: Implementations {
1617 gleam: false,
1618 uses_erlang_externals: true,
1619 uses_javascript_externals: true,
1620 can_run_on_erlang: true,
1621 can_run_on_javascript: true,
1622 },
1623 purity: Purity::Unknown,
1624 },
1625 },
1626 )]
1627 .into(),
1628 line_numbers: LineNumbers::new(""),
1629 src_path: "some_path".into(),
1630 minimum_required_version: Version::new(0, 1, 0),
1631 type_aliases: HashMap::new(),
1632 documentation: Vec::new(),
1633 contains_echo: false,
1634
1635 references: References::default(),
1636 inline_functions: HashMap::new(),
1637 };
1638
1639 assert_eq!(roundtrip(&module), module);
1640}
1641
1642#[test]
1643fn internal_annotated_module_fn() {
1644 let module = ModuleInterface {
1645 warnings: vec![],
1646 is_internal: false,
1647 package: "some_package".into(),
1648 origin: Origin::Src,
1649 name: "a/b/c".into(),
1650 types: HashMap::new(),
1651 types_value_constructors: HashMap::new(),
1652 accessors: HashMap::new(),
1653 values: [(
1654 "one".into(),
1655 ValueConstructor {
1656 publicity: Publicity::Internal {
1657 attribute_location: Some(SrcSpan {
1658 start: 11,
1659 end: 111,
1660 }),
1661 },
1662 deprecation: Deprecation::NotDeprecated,
1663 type_: type_::int(),
1664 variant: ValueConstructorVariant::ModuleFn {
1665 documentation: Some("wabble!".into()),
1666 name: "one".into(),
1667 field_map: None,
1668 module: "a".into(),
1669 arity: 5,
1670 location: SrcSpan {
1671 start: 52,
1672 end: 1100,
1673 },
1674 external_erlang: Some(("wibble".into(), "wobble".into())),
1675 external_javascript: Some(("wobble".into(), "wibble".into())),
1676 implementations: Implementations {
1677 gleam: false,
1678 uses_erlang_externals: true,
1679 uses_javascript_externals: true,
1680 can_run_on_erlang: true,
1681 can_run_on_javascript: true,
1682 },
1683 purity: Purity::Impure,
1684 },
1685 },
1686 )]
1687 .into(),
1688 line_numbers: LineNumbers::new(""),
1689 src_path: "some_path".into(),
1690 minimum_required_version: Version::new(0, 1, 0),
1691 type_aliases: HashMap::new(),
1692 documentation: Vec::new(),
1693 contains_echo: false,
1694
1695 references: References::default(),
1696 inline_functions: HashMap::new(),
1697 };
1698
1699 assert_eq!(roundtrip(&module), module);
1700}
1701
1702// https://github.com/gleam-lang/gleam/issues/2599
1703#[test]
1704fn type_variable_ids_in_constructors_are_shared() {
1705 let module = ModuleInterface {
1706 warnings: vec![],
1707 is_internal: false,
1708 package: "some_package".into(),
1709 origin: Origin::Src,
1710 name: "a/b/c".into(),
1711 types: HashMap::new(),
1712 types_value_constructors: HashMap::from([(
1713 "SomeType".into(),
1714 TypeVariantConstructors {
1715 type_parameters_ids: vec![4, 5, 6],
1716 variants: vec![TypeValueConstructor {
1717 name: "One".into(),
1718 parameters: vec![
1719 TypeValueConstructorField {
1720 type_: type_::generic_var(6),
1721 label: None,
1722 documentation: Some("Here's some documentation".into()),
1723 },
1724 TypeValueConstructorField {
1725 type_: type_::int(),
1726 label: None,
1727 documentation: None,
1728 },
1729 TypeValueConstructorField {
1730 type_: type_::tuple(vec![type_::generic_var(4), type_::generic_var(5)]),
1731 label: None,
1732 documentation: None,
1733 },
1734 ],
1735 documentation: None,
1736 }],
1737 opaque: Opaque::NotOpaque,
1738 },
1739 )]),
1740 accessors: HashMap::new(),
1741 values: [].into(),
1742 line_numbers: LineNumbers::new(""),
1743 src_path: "some_path".into(),
1744 minimum_required_version: Version::new(0, 1, 0),
1745 type_aliases: HashMap::new(),
1746 documentation: Vec::new(),
1747 contains_echo: false,
1748
1749 references: References::default(),
1750 inline_functions: HashMap::new(),
1751 };
1752
1753 let expected = HashMap::from([(
1754 "SomeType".into(),
1755 TypeVariantConstructors {
1756 type_parameters_ids: vec![0, 1, 2],
1757 variants: vec![TypeValueConstructor {
1758 name: "One".into(),
1759 parameters: vec![
1760 TypeValueConstructorField {
1761 type_: type_::generic_var(2),
1762 label: None,
1763 documentation: Some("Here's some documentation".into()),
1764 },
1765 TypeValueConstructorField {
1766 type_: type_::int(),
1767 label: None,
1768 documentation: None,
1769 },
1770 TypeValueConstructorField {
1771 type_: type_::tuple(vec![type_::generic_var(0), type_::generic_var(1)]),
1772 label: None,
1773 documentation: None,
1774 },
1775 ],
1776 documentation: None,
1777 }],
1778 opaque: Opaque::NotOpaque,
1779 },
1780 )]);
1781
1782 assert_eq!(roundtrip(&module).types_value_constructors, expected);
1783}
1784
1785#[test]
1786fn type_with_inferred_variant() {
1787 let module = ModuleInterface {
1788 warnings: vec![],
1789 is_internal: false,
1790 package: "some_package".into(),
1791 contains_echo: false,
1792 origin: Origin::Src,
1793 name: "a/b".into(),
1794 types: [(
1795 "Wibble".into(),
1796 TypeConstructor {
1797 type_: Arc::new(Type::Named {
1798 publicity: Publicity::Internal {
1799 attribute_location: None,
1800 },
1801 package: "some_package".into(),
1802 module: "the/module".into(),
1803 name: "Wibble".into(),
1804 arguments: Vec::new(),
1805 inferred_variant: Some(1),
1806 }),
1807 publicity: Publicity::Internal {
1808 attribute_location: Some(SrcSpan::new(0, 10)),
1809 },
1810 origin: Default::default(),
1811 module: "the/module".into(),
1812 parameters: vec![],
1813 deprecation: Deprecation::NotDeprecated,
1814 documentation: None,
1815 },
1816 )]
1817 .into(),
1818 types_value_constructors: HashMap::new(),
1819 values: HashMap::new(),
1820 accessors: HashMap::new(),
1821 line_numbers: LineNumbers::new(""),
1822 src_path: "some_path".into(),
1823 minimum_required_version: Version::new(0, 1, 0),
1824 type_aliases: HashMap::new(),
1825 documentation: Vec::new(),
1826 references: References::default(),
1827 inline_functions: HashMap::new(),
1828 };
1829 assert_eq!(roundtrip(&module), module);
1830}
1831
1832#[test]
1833fn module_with_type_aliases() {
1834 let module = ModuleInterface {
1835 warnings: vec![],
1836 is_internal: false,
1837 package: "some_package".into(),
1838 origin: Origin::Src,
1839 name: "some_module".into(),
1840 types: HashMap::new(),
1841 types_value_constructors: HashMap::new(),
1842 values: HashMap::new(),
1843 accessors: HashMap::new(),
1844 line_numbers: LineNumbers::new(""),
1845 src_path: "some_path".into(),
1846 minimum_required_version: Version::new(0, 1, 0),
1847 type_aliases: [(
1848 "MyAlias".into(),
1849 TypeAliasConstructor {
1850 publicity: Publicity::Public,
1851 module: "some_module".into(),
1852 type_: prelude::int(),
1853 arity: 1,
1854 deprecation: Deprecation::NotDeprecated,
1855 documentation: Some("Some documentation".into()),
1856 origin: Default::default(),
1857 parameters: vec![type_::generic_var(0)],
1858 },
1859 )]
1860 .into(),
1861 documentation: Vec::new(),
1862 contains_echo: false,
1863
1864 references: References::default(),
1865 inline_functions: HashMap::new(),
1866 };
1867 assert_eq!(roundtrip(&module), module);
1868}
1869
1870#[test]
1871fn module_with_documentation() {
1872 let module = ModuleInterface {
1873 warnings: vec![],
1874 is_internal: false,
1875 package: "some_package".into(),
1876 origin: Origin::Src,
1877 name: "some_module".into(),
1878 types: HashMap::new(),
1879 types_value_constructors: HashMap::new(),
1880 values: HashMap::new(),
1881 accessors: HashMap::new(),
1882 line_numbers: LineNumbers::new(""),
1883 src_path: "some_path".into(),
1884 minimum_required_version: Version::new(0, 1, 0),
1885 type_aliases: HashMap::new(),
1886 documentation: vec![
1887 "This is a line of documentation".into(),
1888 "And here is another".into(),
1889 "And finally, a third".into(),
1890 ],
1891 contains_echo: false,
1892
1893 references: References::default(),
1894 inline_functions: HashMap::new(),
1895 };
1896 assert_eq!(roundtrip(&module), module);
1897}
1898
1899#[test]
1900fn module_with_opaque_type() {
1901 let module = ModuleInterface {
1902 warnings: vec![],
1903 is_internal: false,
1904 package: "some_package".into(),
1905 origin: Origin::Src,
1906 name: "a".into(),
1907 types: HashMap::new(),
1908 types_value_constructors: [(
1909 "SomeType".into(),
1910 TypeVariantConstructors {
1911 type_parameters_ids: vec![0, 1, 2],
1912 variants: vec![TypeValueConstructor {
1913 name: "One".into(),
1914 parameters: vec![],
1915 documentation: Some("Some documentation".into()),
1916 }],
1917 opaque: Opaque::Opaque,
1918 },
1919 )]
1920 .into(),
1921 accessors: HashMap::new(),
1922 values: HashMap::new(),
1923 line_numbers: LineNumbers::new(""),
1924 src_path: "some_path".into(),
1925 minimum_required_version: Version::new(0, 1, 0),
1926 type_aliases: HashMap::new(),
1927 documentation: Vec::new(),
1928 contains_echo: false,
1929 references: References::default(),
1930 inline_functions: HashMap::new(),
1931 };
1932
1933 assert_eq!(roundtrip(&module), module);
1934}
1935
1936#[test]
1937fn module_with_references() {
1938 let module = ModuleInterface {
1939 warnings: vec![],
1940 is_internal: false,
1941 package: "some_package".into(),
1942 origin: Origin::Src,
1943 name: "a".into(),
1944 types: HashMap::new(),
1945 types_value_constructors: HashMap::new(),
1946 accessors: HashMap::new(),
1947 values: HashMap::new(),
1948 line_numbers: LineNumbers::new(""),
1949 src_path: "some_path".into(),
1950 minimum_required_version: Version::new(0, 1, 0),
1951 type_aliases: HashMap::new(),
1952 documentation: Vec::new(),
1953 contains_echo: false,
1954 references: References {
1955 imported_modules: ["some_module".into(), "some_other_module".into()].into(),
1956 value_references: [
1957 (
1958 ("some_module".into(), "some_function".into()),
1959 vec![
1960 Reference {
1961 location: SrcSpan::new(1, 6),
1962 kind: ReferenceKind::Definition,
1963 },
1964 Reference {
1965 location: SrcSpan::new(7, 11),
1966 kind: ReferenceKind::Unqualified,
1967 },
1968 ],
1969 ),
1970 (
1971 ("some_other_module".into(), "some_constant".into()),
1972 vec![
1973 Reference {
1974 location: SrcSpan::new(6, 9),
1975 kind: ReferenceKind::Import,
1976 },
1977 Reference {
1978 location: SrcSpan::new(90, 108),
1979 kind: ReferenceKind::Unqualified,
1980 },
1981 ],
1982 ),
1983 (
1984 ("some_other_module".into(), "SomeTypeVariant".into()),
1985 vec![
1986 Reference {
1987 location: SrcSpan::new(26, 35),
1988 kind: ReferenceKind::Qualified,
1989 },
1990 Reference {
1991 location: SrcSpan::new(152, 204),
1992 kind: ReferenceKind::Qualified,
1993 },
1994 Reference {
1995 location: SrcSpan::new(0, 8),
1996 kind: ReferenceKind::Qualified,
1997 },
1998 ],
1999 ),
2000 ]
2001 .into(),
2002 type_references: [(
2003 ("some_other_module".into(), "TypeVariant".into()),
2004 vec![
2005 Reference {
2006 location: SrcSpan::new(26, 35),
2007 kind: ReferenceKind::Qualified,
2008 },
2009 Reference {
2010 location: SrcSpan::new(152, 204),
2011 kind: ReferenceKind::Unqualified,
2012 },
2013 Reference {
2014 location: SrcSpan::new(0, 8),
2015 kind: ReferenceKind::Definition,
2016 },
2017 ],
2018 )]
2019 .into(),
2020 },
2021 inline_functions: HashMap::new(),
2022 };
2023
2024 assert_eq!(roundtrip(&module), module);
2025}