Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

fix detection of integer segments over the safe js limit

+84 -45
+8
CHANGELOG.md
··· 218 218 patterns and guards of a case arm. 219 219 ([Giacomo Cavalieri](https://github.com/giacomocavalieri)) 220 220 221 + - Fixed a bug where the compiler would not warn for integers over the safe 222 + JavaScript limit in `BitArray` segments with a unit option. 223 + ([Giacomo Cavalieri](https://github.com/giacomocavalieri)) 224 + 225 + - Fixed a bug where the compiler would incorrectly warn for integers over the 226 + safe JavaScript limit in `BitArray` byte segments that aren't integers. 227 + ([Giacomo Cavalieri](https://github.com/giacomocavalieri)) 228 + 221 229 - Fixed a bug where enabling `javascript.typescript_declarations` or 222 230 `javascript.source_maps` wouldn't generate their additional files unless the 223 231 build directory was manually deleted. The compiler now automatically rebuilds
+19 -41
compiler-core/src/type_/pattern.rs
··· 494 494 .expect("The function always returns Ok"); 495 495 496 496 self.check_pattern_segment_size_expression(&options); 497 - self.check_matched_int_is_in_js_bounds(segment.value.as_ref(), &options); 498 497 499 498 let segment_type = match bit_array::type_options_for_pattern( 500 499 &options, ··· 640 639 | Pattern::Invalid { .. } => {} 641 640 }; 642 641 643 - BitArraySegment { 642 + let typed_segment = BitArraySegment { 644 643 location: segment.location, 645 644 value: Box::new(typed_value), 646 645 options, 647 646 type_, 648 - } 647 + }; 648 + 649 + self.check_matched_int_is_in_js_bounds(&typed_segment); 650 + 651 + typed_segment 649 652 } 650 653 651 654 /// When we have an assignment or a case expression we unify the pattern with the ··· 1532 1535 /// That's the maximum size of ints on the JS target, matching on anything 1533 1536 /// bigger would result in the number being truncated. 1534 1537 /// 1535 - fn check_matched_int_is_in_js_bounds( 1536 - &mut self, 1537 - pattern: &UntypedPattern, 1538 - options: &[BitArrayOption<TypedPattern>], 1539 - ) { 1538 + fn check_matched_int_is_in_js_bounds(&mut self, segment: &TypedPatternBitArraySegment) { 1540 1539 // This only makes sense to check on the js target 1541 1540 // And if the segment actually defines a variable that would end up 1542 - // being truncated. 1543 - if self.environment.target != Target::JavaScript { 1541 + // being truncated and that is an integer! 1542 + if self.environment.target != Target::JavaScript || !segment.type_.is_int() { 1544 1543 return; 1545 1544 } 1546 - let (Pattern::Assign { .. } | Pattern::Variable { .. }) = pattern else { 1547 - return; 1548 - }; 1549 - 1550 - // We need to check if there's an explicit size value for the segment. 1551 - let Some((location, size_value)) = options.iter().find_map(|option| match option { 1552 - BitArrayOption::Size { 1553 - value, location, .. 1554 - } => Some((location, value)), 1555 - 1556 - BitArrayOption::Bytes { .. } 1557 - | BitArrayOption::Int { .. } 1558 - | BitArrayOption::Float { .. } 1559 - | BitArrayOption::Bits { .. } 1560 - | BitArrayOption::Utf8 { .. } 1561 - | BitArrayOption::Utf16 { .. } 1562 - | BitArrayOption::Utf32 { .. } 1563 - | BitArrayOption::Utf8Codepoint { .. } 1564 - | BitArrayOption::Utf16Codepoint { .. } 1565 - | BitArrayOption::Utf32Codepoint { .. } 1566 - | BitArrayOption::Signed { .. } 1567 - | BitArrayOption::Unsigned { .. } 1568 - | BitArrayOption::Big { .. } 1569 - | BitArrayOption::Little { .. } 1570 - | BitArrayOption::Native { .. } 1571 - | BitArrayOption::Unit { .. } => None, 1572 - }) else { 1545 + let (Pattern::Assign { .. } | Pattern::Variable { .. }) = segment.value.as_ref() else { 1573 1546 return; 1574 1547 }; 1575 1548 1576 1549 // The size must be a compile time known number, otherwise there's not 1577 1550 // much we can tell about it. 1578 - let Pattern::BitArraySize(size) = size_value.as_ref() else { 1551 + let Some(Pattern::BitArraySize(size)) = segment.size() else { 1579 1552 return; 1580 1553 }; 1554 + 1555 + // We need to check if there's an explicit size value for the segment. 1581 1556 let Some(size) = size.compile_time_number() else { 1582 1557 return; 1583 1558 }; 1559 + 1560 + let unit = segment.unit(); 1561 + let bits = size.clone() * unit; 1584 1562 1585 1563 // If the size is above the JS limit we raise a warning. 1586 - if size > BigInt::from(52) { 1564 + if bits > BigInt::from(52) { 1587 1565 self.problems.warning(Warning::JavaScriptBitArrayUnsafeInt { 1588 - location: *location, 1589 - size, 1566 + location: segment.location, 1567 + size: bits, 1590 1568 }); 1591 1569 } 1592 1570 }
+2 -2
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_match_on_integer_over_js_limit.snap
··· 12 12 13 13 ----- WARNING 14 14 warning: Truncated bit array segment 15 - ┌─ /src/warning/wrn.gleam:3:18 15 + ┌─ /src/warning/wrn.gleam:3:11 16 16 17 17 3 │ let <<number:123>> = x 18 - │ ^^^ 18 + │ ^^^^^^^^^^ 19 19 20 20 This segment is a 123-bit long int, but on the JavaScript target numbers 21 21 have at most 52 bits. It would be truncated to its first 52 bits.
+2 -2
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_match_on_integer_over_js_limit_1.snap
··· 14 14 15 15 ----- WARNING 16 16 warning: Truncated bit array segment 17 - ┌─ /src/warning/wrn.gleam:4:9 17 + ┌─ /src/warning/wrn.gleam:4:7 18 18 19 19 4 │ <<n:size(53)>> -> n 20 - │ ^^^^^^^^ 20 + │ ^^^^^^^^^^ 21 21 22 22 This segment is a 53-bit long int, but on the JavaScript target numbers 23 23 have at most 52 bits. It would be truncated to its first 52 bits.
+25
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__bit_array_match_on_integer_over_js_limit_with_unit.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go(x: BitArray) {\n case x {\n <<n:2-unit(250)>> -> n\n _ -> 1\n }\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go(x: BitArray) { 8 + case x { 9 + <<n:2-unit(250)>> -> n 10 + _ -> 1 11 + } 12 + } 13 + 14 + 15 + ----- WARNING 16 + warning: Truncated bit array segment 17 + ┌─ /src/warning/wrn.gleam:4:7 18 + 19 + 4 │ <<n:2-unit(250)>> -> n 20 + │ ^^^^^^^^^^^^^ 21 + 22 + This segment is a 500-bit long int, but on the JavaScript target numbers 23 + have at most 52 bits. It would be truncated to its first 52 bits. 24 + 25 + Hint: Did you mean to use the `bytes` segment option?
+28
compiler-core/src/type_/tests/warnings.rs
··· 4962 4962 ); 4963 4963 } 4964 4964 4965 + #[test] 4966 + fn bit_array_match_on_integer_over_js_limit_with_unit() { 4967 + assert_js_warning!( 4968 + " 4969 + pub fn go(x: BitArray) { 4970 + case x { 4971 + <<n:2-unit(250)>> -> n 4972 + _ -> 1 4973 + } 4974 + } 4975 + " 4976 + ); 4977 + } 4978 + 4979 + #[test] 4980 + fn bit_array_match_on_bytes_does_not_complain_about_integer_size() { 4981 + assert_js_no_warnings!( 4982 + " 4983 + pub fn go(x: BitArray) { 4984 + case x { 4985 + <<n:150-bytes>> -> n 4986 + _ -> <<>> 4987 + } 4988 + } 4989 + " 4990 + ); 4991 + } 4992 + 4965 4993 // https://github.com/gleam-lang/gleam/issues/5599 4966 4994 #[test] 4967 4995 fn bit_array_size_constant() {