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