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

Configure Feed

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

Warn about unsafe integer values on JavaScript

+788 -48
+20
CHANGELOG.md
··· 187 187 188 188 ([Surya Rose](https://github.com/GearsDatapacks)) 189 189 190 + - When targeting JavaScript the compiler now emits a warning for integer literals 191 + and constants that lie outside JavaScript's safe integer range: 192 + 193 + ```txt 194 + warning: Int is outside the safe range on JavaScript 195 + ┌─ /Users/richard/Desktop/int_test/src/int_test.gleam:1:15 196 + 197 + 1 │ pub const i = 9_007_199_254_740_992 198 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer on JavaScript 199 + 200 + This integer value is too large to be represented accurately by 201 + JavaScript's number type. To avoid this warning integer values must be in 202 + the range -(2^53 - 1) - (2^53 - 1). 203 + 204 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 205 + properties for more information. 206 + ``` 207 + 208 + ([Richard Viney](https://github.com/richard-viney)) 209 + 190 210 ### Formatter 191 211 192 212 - The formatter no longer removes the first argument from a function
+3 -3
Cargo.lock
··· 875 875 "itertools", 876 876 "lsp-server", 877 877 "lsp-types", 878 + "num-bigint", 878 879 "pathdiff", 879 880 "petgraph", 880 881 "pretty_assertions", ··· 1414 1415 1415 1416 [[package]] 1416 1417 name = "num-bigint" 1417 - version = "0.4.4" 1418 + version = "0.4.6" 1418 1419 source = "registry+https://github.com/rust-lang/crates.io-index" 1419 - checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" 1420 + checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 1420 1421 dependencies = [ 1421 - "autocfg", 1422 1422 "num-integer", 1423 1423 "num-traits", 1424 1424 ]
+2
compiler-core/Cargo.toml
··· 44 44 unicode-segmentation = "1.12.0" 45 45 # Bijective (bi-directional) hashmap 46 46 bimap = "0.6.3" 47 + # Parsing of arbitrary width int values 48 + num-bigint = "0.4.6" 47 49 async-trait.workspace = true 48 50 base16.workspace = true 49 51 bytes.workspace = true
+2
compiler-core/src/ast.rs
··· 22 22 use std::sync::Arc; 23 23 24 24 use ecow::EcoString; 25 + use num_bigint::BigInt; 25 26 #[cfg(test)] 26 27 use pretty_assertions::assert_eq; 27 28 use vec1::Vec1; ··· 1678 1679 Int { 1679 1680 location: SrcSpan, 1680 1681 value: EcoString, 1682 + int_value: BigInt, 1681 1683 }, 1682 1684 1683 1685 Float {
+1
compiler-core/src/ast/constant.rs
··· 10 10 Int { 11 11 location: SrcSpan, 12 12 value: EcoString, 13 + int_value: BigInt, 13 14 }, 14 15 15 16 Float {
+17
compiler-core/src/ast/tests.rs
··· 223 223 let int1 = TypedExpr::Int { 224 224 location: SrcSpan { start: 14, end: 15 }, 225 225 value: "1".into(), 226 + int_value: 1.into(), 226 227 type_: type_::int(), 227 228 }; 228 229 ··· 267 268 location: SrcSpan { start: 1, end: 2 }, 268 269 type_: type_::int(), 269 270 value: "1".into(), 271 + int_value: 1.into(), 270 272 }; 271 273 let int2 = TypedExpr::Int { 272 274 location: SrcSpan { start: 4, end: 5 }, 273 275 type_: type_::int(), 274 276 value: "2".into(), 277 + int_value: 2.into(), 275 278 }; 276 279 let int3 = TypedExpr::Int { 277 280 location: SrcSpan { start: 7, end: 8 }, 278 281 type_: type_::int(), 279 282 value: "3".into(), 283 + int_value: 3.into(), 280 284 }; 281 285 282 286 assert_eq!(list.find_node(0), Some(Located::Expression(list))); ··· 300 304 location: SrcSpan { start: 2, end: 3 }, 301 305 type_: type_::int(), 302 306 value: "1".into(), 307 + int_value: 1.into(), 303 308 }; 304 309 let int2 = TypedExpr::Int { 305 310 location: SrcSpan { start: 5, end: 6 }, 306 311 type_: type_::int(), 307 312 value: "2".into(), 313 + int_value: 2.into(), 308 314 }; 309 315 let int3 = TypedExpr::Int { 310 316 location: SrcSpan { start: 8, end: 9 }, 311 317 type_: type_::int(), 312 318 value: "3".into(), 319 + int_value: 3.into(), 313 320 }; 314 321 315 322 assert_eq!(tuple.find_node(0), Some(Located::Expression(tuple))); ··· 345 352 let int = TypedExpr::Int { 346 353 location: SrcSpan { start: 2, end: 3 }, 347 354 value: "1".into(), 355 + int_value: 1.into(), 348 356 type_: type_::int(), 349 357 }; 350 358 ··· 386 394 let int = TypedExpr::Int { 387 395 location: SrcSpan { start: 7, end: 8 }, 388 396 value: "1".into(), 397 + int_value: 1.into(), 389 398 type_: type_::int(), 390 399 }; 391 400 ··· 405 414 let retrn = TypedExpr::Int { 406 415 location: SrcSpan { start: 11, end: 12 }, 407 416 value: "1".into(), 417 + int_value: 1.into(), 408 418 type_: type_::int(), 409 419 }; 410 420 411 421 let arg1 = TypedExpr::Int { 412 422 location: SrcSpan { start: 15, end: 16 }, 413 423 value: "1".into(), 424 + int_value: 1.into(), 414 425 type_: type_::int(), 415 426 }; 416 427 417 428 let arg2 = TypedExpr::Int { 418 429 location: SrcSpan { start: 18, end: 19 }, 419 430 value: "2".into(), 431 + int_value: 2.into(), 420 432 type_: type_::int(), 421 433 }; 422 434 ··· 443 455 let int = TypedExpr::Int { 444 456 location: SrcSpan { start: 12, end: 13 }, 445 457 value: "3".into(), 458 + int_value: 3.into(), 446 459 type_: type_::int(), 447 460 }; 448 461 ··· 462 475 let int = TypedExpr::Int { 463 476 location: SrcSpan { start: 27, end: 28 }, 464 477 value: "4".into(), 478 + int_value: 4.into(), 465 479 type_: type_::int(), 466 480 }; 467 481 ··· 486 500 let int1 = TypedExpr::Int { 487 501 location: SrcSpan { start: 6, end: 7 }, 488 502 value: "1".into(), 503 + int_value: 1.into(), 489 504 type_: type_::int(), 490 505 }; 491 506 492 507 let int2 = TypedExpr::Int { 493 508 location: SrcSpan { start: 9, end: 10 }, 494 509 value: "2".into(), 510 + int_value: 2.into(), 495 511 type_: type_::int(), 496 512 }; 497 513 498 514 let int3 = TypedExpr::Int { 499 515 location: SrcSpan { start: 23, end: 24 }, 500 516 value: "3".into(), 517 + int_value: 3.into(), 501 518 type_: type_::int(), 502 519 }; 503 520
+1
compiler-core/src/ast/typed.rs
··· 9 9 location: SrcSpan, 10 10 type_: Arc<Type>, 11 11 value: EcoString, 12 + int_value: BigInt, 12 13 }, 13 14 14 15 Float {
+1
compiler-core/src/ast/untyped.rs
··· 7 7 Int { 8 8 location: SrcSpan, 9 9 value: EcoString, 10 + int_value: BigInt, 10 11 }, 11 12 12 13 Float {
+6 -1
compiler-core/src/ast/visit.rs
··· 604 604 location, 605 605 type_, 606 606 value, 607 + int_value: _, 607 608 } => v.visit_typed_expr_int(location, type_, value), 608 609 TypedExpr::Float { 609 610 location, ··· 1099 1100 V: Visit<'a> + ?Sized, 1100 1101 { 1101 1102 match pattern { 1102 - Pattern::Int { location, value } => v.visit_typed_pattern_int(location, value), 1103 + Pattern::Int { 1104 + location, 1105 + value, 1106 + int_value: _, 1107 + } => v.visit_typed_pattern_int(location, value), 1103 1108 Pattern::Float { location, value } => v.visit_typed_pattern_float(location, value), 1104 1109 Pattern::String { location, value } => v.visit_typed_pattern_string(location, value), 1105 1110 Pattern::Variable {
+44 -9
compiler-core/src/ast_folder.rs
··· 1 1 use ecow::EcoString; 2 + use num_bigint::BigInt; 2 3 use vec1::Vec1; 3 4 4 5 use crate::{ ··· 240 241 fn update_expr(&mut self, e: UntypedExpr) -> UntypedExpr { 241 242 match e { 242 243 UntypedExpr::Var { location, name } => self.fold_var(location, name), 243 - UntypedExpr::Int { location, value } => self.fold_int(location, value), 244 + UntypedExpr::Int { 245 + location, 246 + value, 247 + int_value, 248 + } => self.fold_int(location, value, int_value), 244 249 UntypedExpr::Float { location, value } => self.fold_float(location, value), 245 250 UntypedExpr::String { location, value } => self.fold_string(location, value), 246 251 ··· 639 644 } 640 645 } 641 646 642 - fn fold_int(&mut self, location: SrcSpan, value: EcoString) -> UntypedExpr { 643 - UntypedExpr::Int { location, value } 647 + fn fold_int(&mut self, location: SrcSpan, value: EcoString, int_value: BigInt) -> UntypedExpr { 648 + UntypedExpr::Int { 649 + location, 650 + value, 651 + int_value, 652 + } 644 653 } 645 654 646 655 fn fold_float(&mut self, location: SrcSpan, value: EcoString) -> UntypedExpr { ··· 843 852 /// You probably don't want to override this method. 844 853 fn update_constant(&mut self, m: UntypedConstant) -> UntypedConstant { 845 854 match m { 846 - Constant::Int { location, value } => self.fold_constant_int(location, value), 855 + Constant::Int { 856 + location, 857 + value, 858 + int_value, 859 + } => self.fold_constant_int(location, value, int_value), 847 860 848 861 Constant::Float { location, value } => self.fold_constant_float(location, value), 849 862 ··· 892 905 } 893 906 } 894 907 895 - fn fold_constant_int(&mut self, location: SrcSpan, value: EcoString) -> UntypedConstant { 896 - Constant::Int { location, value } 908 + fn fold_constant_int( 909 + &mut self, 910 + location: SrcSpan, 911 + value: EcoString, 912 + int_value: BigInt, 913 + ) -> UntypedConstant { 914 + Constant::Int { 915 + location, 916 + value, 917 + int_value, 918 + } 897 919 } 898 920 899 921 fn fold_constant_float(&mut self, location: SrcSpan, value: EcoString) -> UntypedConstant { ··· 1077 1099 /// You probably don't want to override this method. 1078 1100 fn update_pattern(&mut self, m: UntypedPattern) -> UntypedPattern { 1079 1101 match m { 1080 - Pattern::Int { location, value } => self.fold_pattern_int(location, value), 1102 + Pattern::Int { 1103 + location, 1104 + value, 1105 + int_value, 1106 + } => self.fold_pattern_int(location, value, int_value), 1081 1107 1082 1108 Pattern::Float { location, value } => self.fold_pattern_float(location, value), 1083 1109 ··· 1151 1177 } 1152 1178 } 1153 1179 1154 - fn fold_pattern_int(&mut self, location: SrcSpan, value: EcoString) -> UntypedPattern { 1155 - Pattern::Int { location, value } 1180 + fn fold_pattern_int( 1181 + &mut self, 1182 + location: SrcSpan, 1183 + value: EcoString, 1184 + int_value: BigInt, 1185 + ) -> UntypedPattern { 1186 + Pattern::Int { 1187 + location, 1188 + value, 1189 + int_value, 1190 + } 1156 1191 } 1157 1192 1158 1193 fn fold_pattern_float(&mut self, location: SrcSpan, value: EcoString) -> UntypedPattern {
+3
compiler-core/src/exhaustiveness/pattern_tests.rs
··· 11 11 let input = TypedPattern::Int { 12 12 location: SrcSpan::default(), 13 13 value: "123".into(), 14 + int_value: 123.into(), 14 15 }; 15 16 let id = patterns.register(&input); 16 17 assert_eq!( ··· 94 95 location: SrcSpan::default(), 95 96 pattern: Box::new(TypedPattern::Int { 96 97 value: "123".into(), 98 + int_value: 123.into(), 97 99 location: SrcSpan::default(), 98 100 }), 99 101 }; ··· 124 126 elems: vec![ 125 127 TypedPattern::Int { 126 128 value: "123".into(), 129 + int_value: 123.into(), 127 130 location: SrcSpan::default(), 128 131 }, 129 132 TypedPattern::Float {
+6 -1
compiler-core/src/javascript/expression.rs
··· 328 328 location: _, 329 329 type_: _, 330 330 value, 331 + int_value: _, 331 332 } => value.parse().unwrap_or(0), 332 333 _ => 0, 333 334 }; ··· 1510 1511 let size = match size { 1511 1512 Some(Opt::Size { value: size, .. }) => { 1512 1513 let size_int = match *size.clone() { 1513 - Constant::Int { location: _, value } => value.parse().unwrap_or(0), 1514 + Constant::Int { 1515 + location: _, 1516 + value, 1517 + int_value: _, 1518 + } => value.parse().unwrap_or(0), 1514 1519 _ => 0, 1515 1520 }; 1516 1521 if size_int > 0 && size_int % 8 != 0 {
+1
compiler-core/src/metadata/module_decoder.rs
··· 262 262 Constant::Int { 263 263 location: Default::default(), 264 264 value: value.into(), 265 + int_value: crate::parse::parse_int_value(value).expect("int value to parse as bigint"), 265 266 } 266 267 } 267 268
+11
compiler-core/src/metadata/tests.rs
··· 75 75 value: Box::new(Constant::Int { 76 76 location: Default::default(), 77 77 value: "1".into(), 78 + int_value: 1.into(), 78 79 }), 79 80 options: vec![option], 80 81 type_: type_::int(), ··· 834 835 let module = constant_module(Constant::Int { 835 836 location: Default::default(), 836 837 value: "100".into(), 838 + int_value: 100.into(), 837 839 }); 838 840 839 841 assert_eq!(roundtrip(&module), module); ··· 867 869 Constant::Int { 868 870 location: Default::default(), 869 871 value: "1".into(), 872 + int_value: 1.into(), 870 873 }, 871 874 Constant::Float { 872 875 location: Default::default(), ··· 878 881 Constant::Int { 879 882 location: Default::default(), 880 883 value: "1".into(), 884 + int_value: 1.into(), 881 885 }, 882 886 Constant::Float { 883 887 location: Default::default(), ··· 900 904 Constant::Int { 901 905 location: Default::default(), 902 906 value: "1".into(), 907 + int_value: 1.into(), 903 908 }, 904 909 Constant::Int { 905 910 location: Default::default(), 906 911 value: "2".into(), 912 + int_value: 2.into(), 907 913 }, 908 914 Constant::Int { 909 915 location: Default::default(), 910 916 value: "3".into(), 917 + int_value: 3.into(), 911 918 }, 912 919 ], 913 920 }); ··· 938 945 value: Constant::Int { 939 946 location: Default::default(), 940 947 value: "1".into(), 948 + int_value: 1.into(), 941 949 }, 942 950 }, 943 951 ], ··· 954 962 let one_original = Constant::Int { 955 963 location: Default::default(), 956 964 value: "1".into(), 965 + int_value: 1.into(), 957 966 }; 958 967 959 968 let one = Constant::Var { ··· 1084 1093 value: Box::new(Constant::Int { 1085 1094 location: Default::default(), 1086 1095 value: "1".into(), 1096 + int_value: 1.into(), 1087 1097 }), 1088 1098 short_form: false, 1089 1099 }); ··· 1097 1107 value: Box::new(Constant::Int { 1098 1108 location: Default::default(), 1099 1109 value: "1".into(), 1110 + int_value: 1.into(), 1100 1111 }), 1101 1112 short_form: true, 1102 1113 });
+65 -14
compiler-core/src/parse.rs
··· 76 76 use ecow::EcoString; 77 77 use error::{LexicalError, ParseError, ParseErrorType}; 78 78 use lexer::{LexResult, Spanned}; 79 + use num_bigint::BigInt; 79 80 use std::cmp::Ordering; 80 81 use std::collections::VecDeque; 81 82 use std::str::FromStr; ··· 491 492 value, 492 493 } 493 494 } 494 - Some((start, Token::Int { value }, end)) => { 495 + Some((start, Token::Int { value, int_value }, end)) => { 495 496 self.advance(); 496 497 UntypedExpr::Int { 497 498 location: SrcSpan { start, end }, 498 499 value, 500 + int_value, 499 501 } 500 502 } 501 503 ··· 780 782 // field access 781 783 match self.tok0.take() { 782 784 // tuple access 783 - Some((_, Token::Int { value }, end)) => { 785 + Some(( 786 + _, 787 + Token::Int { 788 + value, 789 + int_value: _, 790 + }, 791 + end, 792 + )) => { 784 793 self.advance(); 785 794 let v = value.replace("_", ""); 786 795 if let Ok(index) = u64::from_str(&v) { ··· 1199 1208 }, 1200 1209 } 1201 1210 } 1202 - Some((start, Token::Int { value }, end)) => { 1211 + Some((start, Token::Int { value, int_value }, end)) => { 1203 1212 self.advance(); 1204 1213 Pattern::Int { 1205 1214 location: SrcSpan { start, end }, 1206 1215 value, 1216 + int_value, 1207 1217 } 1208 1218 } 1209 1219 Some((start, Token::Float { value }, end)) => { ··· 1554 1564 }; 1555 1565 1556 1566 match self.next_tok() { 1557 - Some((_, Token::Int { value }, int_e)) => { 1567 + Some(( 1568 + _, 1569 + Token::Int { 1570 + value, 1571 + int_value: _, 1572 + }, 1573 + int_e, 1574 + )) => { 1558 1575 let v = value.replace("_", ""); 1559 1576 if let Ok(index) = u64::from_str(&v) { 1560 1577 unit = ClauseGuard::TupleIndex { ··· 2664 2681 })) 2665 2682 } 2666 2683 2667 - Some((start, Token::Int { value }, end)) => { 2684 + Some((start, Token::Int { value, int_value }, end)) => { 2668 2685 self.advance(); 2669 2686 Ok(Some(Constant::Int { 2670 2687 value, 2688 + int_value, 2671 2689 location: SrcSpan { start, end }, 2672 2690 })) 2673 2691 } ··· 2954 2972 &mut self, 2955 2973 value_parser: &impl Fn(&mut Self) -> Result<Option<A>, ParseError>, 2956 2974 arg_parser: &impl Fn(&mut Self) -> Result<A, ParseError>, 2957 - to_int_segment: &impl Fn(EcoString, u32, u32) -> A, 2975 + to_int_segment: &impl Fn(EcoString, BigInt, u32, u32) -> A, 2958 2976 ) -> Result<Option<BitArraySegment<A, ()>>, ParseError> 2959 2977 where 2960 2978 A: HasLocation + std::fmt::Debug, ··· 2995 3013 fn parse_bit_array_option<A: std::fmt::Debug>( 2996 3014 &mut self, 2997 3015 arg_parser: &impl Fn(&mut Self) -> Result<A, ParseError>, 2998 - to_int_segment: &impl Fn(EcoString, u32, u32) -> A, 3016 + to_int_segment: &impl Fn(EcoString, BigInt, u32, u32) -> A, 2999 3017 ) -> Result<Option<BitArrayOption<A>>, ParseError> { 3000 3018 match self.next_tok() { 3001 3019 // named segment ··· 3051 3069 } 3052 3070 } 3053 3071 // int segment 3054 - Some((start, Token::Int { value }, end)) => Ok(Some(BitArrayOption::Size { 3072 + Some((start, Token::Int { value, int_value }, end)) => Ok(Some(BitArrayOption::Size { 3055 3073 location: SrcSpan { start, end }, 3056 - value: Box::new(to_int_segment(value, start, end)), 3074 + value: Box::new(to_int_segment(value, int_value, start, end)), 3057 3075 short_form: true, 3058 3076 })), 3059 3077 // invalid ··· 3072 3090 constructor: None, 3073 3091 type_: (), 3074 3092 }), 3075 - Some((start, Token::Int { value }, end)) => Ok(Pattern::Int { 3093 + Some((start, Token::Int { value, int_value }, end)) => Ok(Pattern::Int { 3076 3094 location: SrcSpan { start, end }, 3077 3095 value, 3096 + int_value, 3078 3097 }), 3079 3098 _ => self.next_tok_unexpected(vec!["A variable name or an integer".into()]), 3080 3099 } ··· 3082 3101 3083 3102 fn expect_const_int(&mut self) -> Result<UntypedConstant, ParseError> { 3084 3103 match self.next_tok() { 3085 - Some((start, Token::Int { value }, end)) => Ok(Constant::Int { 3104 + Some((start, Token::Int { value, int_value }, end)) => Ok(Constant::Int { 3086 3105 location: SrcSpan { start, end }, 3087 3106 value, 3107 + int_value, 3088 3108 }), 3089 3109 _ => self.next_tok_unexpected(vec!["A variable name or an integer".into()]), 3090 3110 } ··· 3894 3914 // BitArrays in patterns, guards, and expressions have a very similar structure 3895 3915 // but need specific types. These are helpers for that. There is probably a 3896 3916 // rustier way to do this :) 3897 - fn bit_array_pattern_int(value: EcoString, start: u32, end: u32) -> UntypedPattern { 3917 + fn bit_array_pattern_int( 3918 + value: EcoString, 3919 + int_value: BigInt, 3920 + start: u32, 3921 + end: u32, 3922 + ) -> UntypedPattern { 3898 3923 Pattern::Int { 3899 3924 location: SrcSpan { start, end }, 3900 3925 value, 3926 + int_value, 3901 3927 } 3902 3928 } 3903 3929 3904 - fn bit_array_expr_int(value: EcoString, start: u32, end: u32) -> UntypedExpr { 3930 + fn bit_array_expr_int(value: EcoString, int_value: BigInt, start: u32, end: u32) -> UntypedExpr { 3905 3931 UntypedExpr::Int { 3906 3932 location: SrcSpan { start, end }, 3907 3933 value, 3934 + int_value, 3908 3935 } 3909 3936 } 3910 3937 3911 - fn bit_array_const_int(value: EcoString, start: u32, end: u32) -> UntypedConstant { 3938 + fn bit_array_const_int( 3939 + value: EcoString, 3940 + int_value: BigInt, 3941 + start: u32, 3942 + end: u32, 3943 + ) -> UntypedConstant { 3912 3944 Constant::Int { 3913 3945 location: SrcSpan { start, end }, 3914 3946 value, 3947 + int_value, 3915 3948 } 3916 3949 } 3917 3950 ··· 4042 4075 types: Vec<UnqualifiedImport>, 4043 4076 values: Vec<UnqualifiedImport>, 4044 4077 } 4078 + 4079 + /// Parses an Int value to a bigint. 4080 + /// 4081 + pub fn parse_int_value(value: &str) -> Option<BigInt> { 4082 + let (radix, value) = if let Some(value) = value.strip_prefix("0x") { 4083 + (16, value) 4084 + } else if let Some(value) = value.strip_prefix("0o") { 4085 + (8, value) 4086 + } else if let Some(value) = value.strip_prefix("0b") { 4087 + (2, value) 4088 + } else { 4089 + (10, value) 4090 + }; 4091 + 4092 + let value = value.trim_start_matches('_'); 4093 + 4094 + BigInt::parse_bytes(value.as_bytes(), radix) 4095 + }
+4
compiler-core/src/parse/lexer.rs
··· 565 565 }) 566 566 } else { 567 567 let value = format!("{prefix}{num}"); 568 + let int_value = super::parse_int_value(&value).expect("int value to parse as bigint"); 568 569 let end_pos = self.get_pos(); 569 570 Ok(( 570 571 start_pos, 571 572 Token::Int { 572 573 value: value.into(), 574 + int_value, 573 575 }, 574 576 end_pos, 575 577 )) ··· 621 623 end_pos, 622 624 ) 623 625 } else { 626 + let int_value = super::parse_int_value(&value).expect("int value to parse as bigint"); 624 627 let end_pos = self.get_pos(); 625 628 ( 626 629 start_pos, 627 630 Token::Int { 628 631 value: value.into(), 632 + int_value, 629 633 }, 630 634 end_pos, 631 635 )
+3
compiler-core/src/parse/snapshots/gleam_core__parse__tests__arithmetic_in_guards.snap
··· 16 16 end: 7, 17 17 }, 18 18 value: "2", 19 + int_value: 2, 19 20 }, 20 21 Int { 21 22 location: SrcSpan { ··· 23 24 end: 10, 24 25 }, 25 26 value: "3", 27 + int_value: 3, 26 28 }, 27 29 ], 28 30 clauses: [ ··· 85 87 end: 35, 86 88 }, 87 89 value: "1", 90 + int_value: 1, 88 91 }, 89 92 ), 90 93 },
+1
compiler-core/src/parse/snapshots/gleam_core__parse__tests__bare_expression.snap
··· 10 10 end: 1, 11 11 }, 12 12 value: "1", 13 + int_value: 1, 13 14 }, 14 15 ), 15 16 ]
+1
compiler-core/src/parse/snapshots/gleam_core__parse__tests__block_of_one.snap
··· 17 17 end: 3, 18 18 }, 19 19 value: "1", 20 + int_value: 1, 20 21 }, 21 22 ), 22 23 ],
+2
compiler-core/src/parse/snapshots/gleam_core__parse__tests__block_of_two.snap
··· 17 17 end: 3, 18 18 }, 19 19 value: "1", 20 + int_value: 1, 20 21 }, 21 22 ), 22 23 Expression( ··· 26 27 end: 5, 27 28 }, 28 29 value: "2", 30 + int_value: 2, 29 31 }, 30 32 ), 31 33 ],
+1
compiler-core/src/parse/snapshots/gleam_core__parse__tests__deeply_nested_tuples.snap
··· 39 39 end: 20, 40 40 }, 41 41 value: "4", 42 + int_value: 4, 42 43 }, 43 44 ], 44 45 },
+1
compiler-core/src/parse/snapshots/gleam_core__parse__tests__deeply_nested_tuples_no_block.snap
··· 39 39 end: 20, 40 40 }, 41 41 value: "4", 42 + int_value: 4, 42 43 }, 43 44 ], 44 45 },
+2
compiler-core/src/parse/snapshots/gleam_core__parse__tests__nested_block.snap
··· 17 17 end: 3, 18 18 }, 19 19 value: "1", 20 + int_value: 1, 20 21 }, 21 22 ), 22 23 Expression( ··· 54 55 end: 17, 55 56 }, 56 57 value: "3", 58 + int_value: 3, 57 59 }, 58 60 ), 59 61 ],
+2
compiler-core/src/parse/snapshots/gleam_core__parse__tests__nested_tuples.snap
··· 27 27 end: 16, 28 28 }, 29 29 value: "5", 30 + int_value: 5, 30 31 }, 31 32 Int { 32 33 location: SrcSpan { ··· 34 35 end: 19, 35 36 }, 36 37 value: "6", 38 + int_value: 6, 37 39 }, 38 40 ], 39 41 },
+2
compiler-core/src/parse/snapshots/gleam_core__parse__tests__nested_tuples_no_block.snap
··· 27 27 end: 16, 28 28 }, 29 29 value: "5", 30 + int_value: 5, 30 31 }, 31 32 Int { 32 33 location: SrcSpan { ··· 34 35 end: 19, 35 36 }, 36 37 value: "6", 38 + int_value: 6, 37 39 }, 38 40 ], 39 41 },
+1
compiler-core/src/parse/snapshots/gleam_core__parse__tests__with_let_binding3.snap
··· 21 21 end: 19, 22 22 }, 23 23 value: "2", 24 + int_value: 2, 24 25 }, 25 26 ], 26 27 tail: None,
+1
compiler-core/src/parse/snapshots/gleam_core__parse__tests__with_let_binding3_and_annotation.snap
··· 21 21 end: 30, 22 22 }, 23 23 value: "2", 24 + int_value: 2, 24 25 }, 25 26 ], 26 27 tail: None,
+16 -2
compiler-core/src/parse/tests.rs
··· 1179 1179 assert_eq!( 1180 1180 make_tokenizer("1\n\n2\n").collect_vec(), 1181 1181 [ 1182 - Ok((0, Token::Int { value: "1".into() }, 1)), 1182 + Ok(( 1183 + 0, 1184 + Token::Int { 1185 + value: "1".into(), 1186 + int_value: 1.into() 1187 + }, 1188 + 1 1189 + )), 1183 1190 Ok((1, Token::NewLine, 2)), 1184 1191 Ok((2, Token::NewLine, 3)), 1185 - Ok((3, Token::Int { value: "2".into() }, 4)), 1192 + Ok(( 1193 + 3, 1194 + Token::Int { 1195 + value: "2".into(), 1196 + int_value: 2.into() 1197 + }, 1198 + 4 1199 + )), 1186 1200 Ok((4, Token::NewLine, 5)) 1187 1201 ] 1188 1202 );
+7 -3
compiler-core/src/parse/token.rs
··· 1 + use num_bigint::BigInt; 1 2 use std::fmt; 2 3 3 4 use ecow::EcoString; ··· 7 8 Name { name: EcoString }, 8 9 UpName { name: EcoString }, 9 10 DiscardName { name: EcoString }, 10 - Int { value: EcoString }, 11 + Int { value: EcoString, int_value: BigInt }, 11 12 Float { value: EcoString }, 12 13 String { value: EcoString }, 13 14 CommentDoc { content: EcoString }, ··· 202 203 Token::Name { name } | Token::UpName { name } | Token::DiscardName { name } => { 203 204 name.as_str() 204 205 } 205 - Token::Int { value } | Token::Float { value } | Token::String { value } => { 206 - value.as_str() 206 + Token::Int { 207 + value, 208 + int_value: _, 207 209 } 210 + | Token::Float { value } 211 + | Token::String { value } => value.as_str(), 208 212 Token::AmperAmper => "&&", 209 213 Token::As => "as", 210 214 Token::Assert => "assert",
+9 -1
compiler-core/src/type_/error.rs
··· 839 839 wrongfully_allowed_version: Version, 840 840 feature_kind: FeatureKind, 841 841 }, 842 + 843 + /// When targeting JavaScript and an `Int` value is specified that lies 844 + /// outside the range `Number.MIN_SAFE_INTEGER` - `Number.MAX_SAFE_INTEGER`. 845 + /// 846 + JavaScriptIntUnsafe { 847 + location: SrcSpan, 848 + }, 842 849 } 843 850 844 851 #[derive(Debug, Eq, Copy, PartialEq, Clone, serde::Serialize, serde::Deserialize)] ··· 1025 1032 | Warning::TodoOrPanicUsedAsFunction { location, .. } 1026 1033 | Warning::UnreachableCodeAfterPanic { location, .. } 1027 1034 | Warning::RedundantPipeFunctionCapture { location, .. } 1028 - | Warning::FeatureRequiresHigherGleamVersion { location, .. } => *location, 1035 + | Warning::FeatureRequiresHigherGleamVersion { location, .. } 1036 + | Warning::JavaScriptIntUnsafe { location, .. } => *location, 1029 1037 } 1030 1038 } 1031 1039
+39 -5
compiler-core/src/type_/expression.rs
··· 17 17 use id_arena::Arena; 18 18 use im::hashmap; 19 19 use itertools::Itertools; 20 + use num_bigint::BigInt; 20 21 use vec1::Vec1; 21 22 22 23 #[derive(Clone, Copy, Debug, Eq, PartialOrd, Ord, PartialEq, Serialize)] ··· 309 310 UntypedExpr::Var { location, name, .. } => self.infer_var(name, location), 310 311 311 312 UntypedExpr::Int { 312 - location, value, .. 313 - } => Ok(self.infer_int(value, location)), 313 + location, 314 + value, 315 + int_value, 316 + .. 317 + } => { 318 + self.check_javascript_int_safety(&int_value, location); 319 + Ok(self.infer_int(value, int_value, location)) 320 + } 314 321 315 322 UntypedExpr::Block { 316 323 statements, ··· 490 497 } 491 498 } 492 499 493 - fn infer_int(&mut self, value: EcoString, location: SrcSpan) -> TypedExpr { 500 + fn infer_int(&mut self, value: EcoString, int_value: BigInt, location: SrcSpan) -> TypedExpr { 494 501 TypedExpr::Int { 495 502 location, 496 503 value, 504 + int_value, 497 505 type_: int(), 498 506 } 499 507 } ··· 2620 2628 fn infer_const_value(&mut self, value: UntypedConstant) -> Result<TypedConstant, Error> { 2621 2629 match value { 2622 2630 Constant::Int { 2623 - location, value, .. 2624 - } => Ok(Constant::Int { location, value }), 2631 + location, 2632 + value, 2633 + int_value, 2634 + } => { 2635 + self.check_javascript_int_safety(&int_value, location); 2636 + Ok(Constant::Int { 2637 + location, 2638 + value, 2639 + int_value, 2640 + }) 2641 + } 2625 2642 2626 2643 Constant::Float { 2627 2644 location, value, .. ··· 3601 3618 3602 3619 if minimum_required_version > self.minimum_required_version { 3603 3620 self.minimum_required_version = minimum_required_version; 3621 + } 3622 + } 3623 + 3624 + /// When targeting JavaScript, adds a warning if the given Int value is outside the range of 3625 + /// safe integers as defined by Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER. 3626 + /// 3627 + fn check_javascript_int_safety(&mut self, int_value: &BigInt, location: SrcSpan) { 3628 + if self.environment.target != Target::JavaScript { 3629 + return; 3630 + } 3631 + 3632 + let js_min_safe_integer = -9007199254740991i64; 3633 + let js_max_safe_integer = 9007199254740991i64; 3634 + 3635 + if *int_value < js_min_safe_integer.into() || *int_value > js_max_safe_integer.into() { 3636 + self.problems 3637 + .warning(Warning::JavaScriptIntUnsafe { location }); 3604 3638 } 3605 3639 } 3606 3640 }
+10 -2
compiler-core/src/type_/pattern.rs
··· 428 428 }) 429 429 } 430 430 431 - Pattern::Int { location, value } => { 431 + Pattern::Int { 432 + location, 433 + value, 434 + int_value, 435 + } => { 432 436 unify(type_, int()).map_err(|e| convert_unify_error(e, location))?; 433 - Ok(Pattern::Int { location, value }) 437 + Ok(Pattern::Int { 438 + location, 439 + value, 440 + int_value, 441 + }) 434 442 } 435 443 436 444 Pattern::Float { location, value } => {
+33 -6
compiler-core/src/type_/tests.rs
··· 214 214 fn get_warnings( 215 215 src: &str, 216 216 deps: Vec<DependencyModule<'_>>, 217 + target: Target, 217 218 gleam_version: Option<Range<Version>>, 218 219 ) -> Vec<crate::warning::Warning> { 219 220 let warnings = VectorWarningEmitterIO::default(); ··· 222 223 src, 223 224 Some(Rc::new(warnings.clone())), 224 225 deps, 225 - Target::Erlang, 226 + target, 226 227 TargetSupport::NotEnforced, 227 228 gleam_version, 228 229 ) ··· 233 234 fn get_printed_warnings( 234 235 src: &str, 235 236 deps: Vec<DependencyModule<'_>>, 237 + target: Target, 236 238 gleam_version: Option<Range<Version>>, 237 239 ) -> String { 238 - print_warnings(get_warnings(src, deps, gleam_version)) 240 + print_warnings(get_warnings(src, deps, target, gleam_version)) 239 241 } 240 242 241 243 fn print_warnings(warnings: Vec<crate::warning::Warning>) -> String { ··· 254 256 vec![ 255 257 $(("thepackage", $name, $module_src)),* 256 258 ], 259 + crate::build::Target::Erlang, 257 260 None 258 261 ); 259 262 ··· 269 272 #[macro_export] 270 273 macro_rules! assert_warning { 271 274 ($src:expr) => { 272 - let warning = $crate::type_::tests::get_printed_warnings($src, vec![], None); 275 + let warning = $crate::type_::tests::get_printed_warnings($src, vec![], crate::build::Target::Erlang, None); 273 276 assert!(!warning.is_empty()); 274 277 let output = format!("----- SOURCE CODE\n{}\n\n----- WARNING\n{}", $src, warning); 275 278 insta::assert_snapshot!(insta::internals::AutoName, output, $src); ··· 279 282 let warning = $crate::type_::tests::get_printed_warnings( 280 283 $src, 281 284 vec![$(("thepackage", $name, $module_src)),*], 285 + crate::build::Target::Erlang, 282 286 None 283 287 ); 284 288 assert!(!warning.is_empty()); ··· 290 294 let warning = $crate::type_::tests::get_printed_warnings( 291 295 $src, 292 296 vec![$(($package, $name, $module_src)),*], 297 + crate::build::Target::Erlang, 293 298 None 294 299 ); 295 300 assert!(!warning.is_empty()); ··· 299 304 } 300 305 301 306 #[macro_export] 307 + macro_rules! assert_js_warning { 308 + ($src:expr) => { 309 + let warning = $crate::type_::tests::get_printed_warnings( 310 + $src, 311 + vec![], 312 + crate::build::Target::JavaScript, 313 + None, 314 + ); 315 + assert!(!warning.is_empty()); 316 + let output = format!("----- SOURCE CODE\n{}\n\n----- WARNING\n{}", $src, warning); 317 + insta::assert_snapshot!(insta::internals::AutoName, output, $src); 318 + }; 319 + } 320 + 321 + #[macro_export] 302 322 macro_rules! assert_warnings_with_gleam_version { 303 323 ($gleam_version:expr, $src:expr$(,)?) => { 304 - let warning = 305 - $crate::type_::tests::get_printed_warnings($src, vec![], Some($gleam_version)); 324 + let warning = $crate::type_::tests::get_printed_warnings( 325 + $src, 326 + vec![], 327 + crate::build::Target::Erlang, 328 + Some($gleam_version), 329 + ); 306 330 assert!(!warning.is_empty()); 307 331 let output = format!("----- SOURCE CODE\n{}\n\n----- WARNING\n{}", $src, warning); 308 332 insta::assert_snapshot!(insta::internals::AutoName, output, $src); ··· 312 336 #[macro_export] 313 337 macro_rules! assert_no_warnings { 314 338 ($src:expr $(,)?) => { 315 - let warnings = $crate::type_::tests::get_warnings($src, vec![], None); 339 + let warnings = $crate::type_::tests::get_warnings($src, vec![], crate::build::Target::Erlang, None); 316 340 assert_eq!(warnings, vec![]); 317 341 }; 318 342 ($(($package:expr, $name:expr, $module_src:literal)),+, $src:expr $(,)?) => { 319 343 let warnings = $crate::type_::tests::get_warnings( 320 344 $src, 321 345 vec![$(($package, $name, $module_src)),*], 346 + crate::build::Target::Erlang, 322 347 None, 323 348 ); 324 349 assert_eq!(warnings, vec![]); ··· 582 607 fn field_map_reorder_test() { 583 608 let int = |value: &str| UntypedExpr::Int { 584 609 value: value.into(), 610 + int_value: crate::parse::parse_int_value(value).unwrap(), 585 611 location: SrcSpan { start: 0, end: 0 }, 586 612 }; 587 613 ··· 2582 2608 literal: Constant::Int { 2583 2609 location: Default::default(), 2584 2610 value: "1".into(), 2611 + int_value: 1.into(), 2585 2612 }, 2586 2613 implementations: Implementations { 2587 2614 gleam: true,
+28
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_binary.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go() {\n [\n 0b11111111111111111111111111111111111111111111111111110,\n 0b11111111111111111111111111111111111111111111111111111,\n 0b100000000000000000000000000000000000000000000000000000,\n ]\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go() { 8 + [ 9 + 0b11111111111111111111111111111111111111111111111111110, 10 + 0b11111111111111111111111111111111111111111111111111111, 11 + 0b100000000000000000000000000000000000000000000000000000, 12 + ] 13 + } 14 + 15 + 16 + ----- WARNING 17 + warning: Int is outside JavaScript's safe integer range 18 + ┌─ /src/warning/wrn.gleam:6:5 19 + 20 + 6 │ 0b100000000000000000000000000000000000000000000000000000, 21 + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 22 + 23 + This integer value is too large to be represented accurately by 24 + JavaScript's number type. To avoid this warning integer values must be in 25 + the range -(2^53 - 1) - (2^53 - 1). 26 + 27 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 28 + properties for more information.
+44
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_decimal.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go() {\n [\n 9_007_199_254_740_990,\n 9_007_199_254_740_991,\n 9_007_199_254_740_992,\n -9_007_199_254_740_990,\n -9_007_199_254_740_991,\n -9_007_199_254_740_992,\n ]\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go() { 8 + [ 9 + 9_007_199_254_740_990, 10 + 9_007_199_254_740_991, 11 + 9_007_199_254_740_992, 12 + -9_007_199_254_740_990, 13 + -9_007_199_254_740_991, 14 + -9_007_199_254_740_992, 15 + ] 16 + } 17 + 18 + 19 + ----- WARNING 20 + warning: Int is outside JavaScript's safe integer range 21 + ┌─ /src/warning/wrn.gleam:6:5 22 + 23 + 6 │ 9_007_199_254_740_992, 24 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 25 + 26 + This integer value is too large to be represented accurately by 27 + JavaScript's number type. To avoid this warning integer values must be in 28 + the range -(2^53 - 1) - (2^53 - 1). 29 + 30 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 31 + properties for more information. 32 + 33 + warning: Int is outside JavaScript's safe integer range 34 + ┌─ /src/warning/wrn.gleam:9:5 35 + 36 + 9 │ -9_007_199_254_740_992, 37 + │ ^^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 38 + 39 + This integer value is too large to be represented accurately by 40 + JavaScript's number type. To avoid this warning integer values must be in 41 + the range -(2^53 - 1) - (2^53 - 1). 42 + 43 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 44 + properties for more information.
+28
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_hex.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go() {\n [\n 0x1FFFFFFFFFFFFE,\n 0x1FFFFFFFFFFFFF,\n 0x20000000000000,\n ]\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go() { 8 + [ 9 + 0x1FFFFFFFFFFFFE, 10 + 0x1FFFFFFFFFFFFF, 11 + 0x20000000000000, 12 + ] 13 + } 14 + 15 + 16 + ----- WARNING 17 + warning: Int is outside JavaScript's safe integer range 18 + ┌─ /src/warning/wrn.gleam:6:5 19 + 20 + 6 │ 0x20000000000000, 21 + │ ^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 22 + 23 + This integer value is too large to be represented accurately by 24 + JavaScript's number type. To avoid this warning integer values must be in 25 + the range -(2^53 - 1) - (2^53 - 1). 26 + 27 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 28 + properties for more information.
+20
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_in_const.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: pub const i = 9_007_199_254_740_992 4 + --- 5 + ----- SOURCE CODE 6 + pub const i = 9_007_199_254_740_992 7 + 8 + ----- WARNING 9 + warning: Int is outside JavaScript's safe integer range 10 + ┌─ /src/warning/wrn.gleam:1:15 11 + 12 + 1 │ pub const i = 9_007_199_254_740_992 13 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 14 + 15 + This integer value is too large to be represented accurately by 16 + JavaScript's number type. To avoid this warning integer values must be in 17 + the range -(2^53 - 1) - (2^53 - 1). 18 + 19 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 20 + properties for more information.
+20
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_in_const_tuple.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "pub const i = #(9_007_199_254_740_992)" 4 + --- 5 + ----- SOURCE CODE 6 + pub const i = #(9_007_199_254_740_992) 7 + 8 + ----- WARNING 9 + warning: Int is outside JavaScript's safe integer range 10 + ┌─ /src/warning/wrn.gleam:1:17 11 + 12 + 1 │ pub const i = #(9_007_199_254_740_992) 13 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 14 + 15 + This integer value is too large to be represented accurately by 16 + JavaScript's number type. To avoid this warning integer values must be in 17 + the range -(2^53 - 1) - (2^53 - 1). 18 + 19 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 20 + properties for more information.
+24
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_in_tuple.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go() {\n #(9_007_199_254_740_992)\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go() { 8 + #(9_007_199_254_740_992) 9 + } 10 + 11 + 12 + ----- WARNING 13 + warning: Int is outside JavaScript's safe integer range 14 + ┌─ /src/warning/wrn.gleam:3:5 15 + 16 + 3 │ #(9_007_199_254_740_992) 17 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 18 + 19 + This integer value is too large to be represented accurately by 20 + JavaScript's number type. To avoid this warning integer values must be in 21 + the range -(2^53 - 1) - (2^53 - 1). 22 + 23 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 24 + properties for more information.
+28
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_octal.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go() {\n [\n 0o377777777777777776,\n 0o377777777777777777,\n 0o400000000000000000,\n ]\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go() { 8 + [ 9 + 0o377777777777777776, 10 + 0o377777777777777777, 11 + 0o400000000000000000, 12 + ] 13 + } 14 + 15 + 16 + ----- WARNING 17 + warning: Int is outside JavaScript's safe integer range 18 + ┌─ /src/warning/wrn.gleam:6:5 19 + 20 + 6 │ 0o400000000000000000, 21 + │ ^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 22 + 23 + This integer value is too large to be represented accurately by 24 + JavaScript's number type. To avoid this warning integer values must be in 25 + the range -(2^53 - 1) - (2^53 - 1). 26 + 27 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 28 + properties for more information.
+24
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_in_bit_array.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go() {\n <<9_007_199_254_740_992:64>>\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go() { 8 + <<9_007_199_254_740_992:64>> 9 + } 10 + 11 + 12 + ----- WARNING 13 + warning: Int is outside JavaScript's safe integer range 14 + ┌─ /src/warning/wrn.gleam:3:5 15 + 16 + 3 │ <<9_007_199_254_740_992:64>> 17 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 18 + 19 + This integer value is too large to be represented accurately by 20 + JavaScript's number type. To avoid this warning integer values must be in 21 + the range -(2^53 - 1) - (2^53 - 1). 22 + 23 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 24 + properties for more information.
+22
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_in_const_bit_array.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub const i = <<9_007_199_254_740_992:64>>\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub const i = <<9_007_199_254_740_992:64>> 8 + 9 + 10 + ----- WARNING 11 + warning: Int is outside JavaScript's safe integer range 12 + ┌─ /src/warning/wrn.gleam:2:17 13 + 14 + 2 │ pub const i = <<9_007_199_254_740_992:64>> 15 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 16 + 17 + This integer value is too large to be represented accurately by 18 + JavaScript's number type. To avoid this warning integer values must be in 19 + the range -(2^53 - 1) - (2^53 - 1). 20 + 21 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 22 + properties for more information.
+40
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_size_in_bit_array.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub fn go() {\n [\n <<0:9_007_199_254_740_992>>,\n <<0:size(9_007_199_254_740_992)>>,\n ]\n}\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub fn go() { 8 + [ 9 + <<0:9_007_199_254_740_992>>, 10 + <<0:size(9_007_199_254_740_992)>>, 11 + ] 12 + } 13 + 14 + 15 + ----- WARNING 16 + warning: Int is outside JavaScript's safe integer range 17 + ┌─ /src/warning/wrn.gleam:4:9 18 + 19 + 4 │ <<0:9_007_199_254_740_992>>, 20 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 21 + 22 + This integer value is too large to be represented accurately by 23 + JavaScript's number type. To avoid this warning integer values must be in 24 + the range -(2^53 - 1) - (2^53 - 1). 25 + 26 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 27 + properties for more information. 28 + 29 + warning: Int is outside JavaScript's safe integer range 30 + ┌─ /src/warning/wrn.gleam:5:14 31 + 32 + 5 │ <<0:size(9_007_199_254_740_992)>>, 33 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 34 + 35 + This integer value is too large to be represented accurately by 36 + JavaScript's number type. To avoid this warning integer values must be in 37 + the range -(2^53 - 1) - (2^53 - 1). 38 + 39 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 40 + properties for more information.
+38
compiler-core/src/type_/tests/snapshots/gleam_core__type___tests__warnings__javascript_unsafe_int_segment_size_in_const_bit_array.snap
··· 1 + --- 2 + source: compiler-core/src/type_/tests/warnings.rs 3 + expression: "\npub const ints = [\n <<0:9_007_199_254_740_992>>,\n <<0:size(9_007_199_254_740_992)>>,\n]\n" 4 + --- 5 + ----- SOURCE CODE 6 + 7 + pub const ints = [ 8 + <<0:9_007_199_254_740_992>>, 9 + <<0:size(9_007_199_254_740_992)>>, 10 + ] 11 + 12 + 13 + ----- WARNING 14 + warning: Int is outside JavaScript's safe integer range 15 + ┌─ /src/warning/wrn.gleam:3:7 16 + 17 + 3 │ <<0:9_007_199_254_740_992>>, 18 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 19 + 20 + This integer value is too large to be represented accurately by 21 + JavaScript's number type. To avoid this warning integer values must be in 22 + the range -(2^53 - 1) - (2^53 - 1). 23 + 24 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 25 + properties for more information. 26 + 27 + warning: Int is outside JavaScript's safe integer range 28 + ┌─ /src/warning/wrn.gleam:4:12 29 + 30 + 4 │ <<0:size(9_007_199_254_740_992)>>, 31 + │ ^^^^^^^^^^^^^^^^^^^^^ This is not a safe integer value on JavaScript 32 + 33 + This integer value is too large to be represented accurately by 34 + JavaScript's number type. To avoid this warning integer values must be in 35 + the range -(2^53 - 1) - (2^53 - 1). 36 + 37 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 38 + properties for more information.
+131 -1
compiler-core/src/type_/tests/warnings.rs
··· 1 1 use super::*; 2 2 use crate::{ 3 - assert_no_warnings, assert_warning, assert_warnings_with_gleam_version, 3 + assert_js_warning, assert_no_warnings, assert_warning, assert_warnings_with_gleam_version, 4 4 assert_warnings_with_imports, 5 5 }; 6 6 ··· 2459 2459 ", 2460 2460 ); 2461 2461 } 2462 + 2463 + #[test] 2464 + fn javascript_unsafe_int_decimal() { 2465 + assert_js_warning!( 2466 + r#" 2467 + pub fn go() { 2468 + [ 2469 + 9_007_199_254_740_990, 2470 + 9_007_199_254_740_991, 2471 + 9_007_199_254_740_992, 2472 + -9_007_199_254_740_990, 2473 + -9_007_199_254_740_991, 2474 + -9_007_199_254_740_992, 2475 + ] 2476 + } 2477 + "# 2478 + ); 2479 + } 2480 + 2481 + #[test] 2482 + fn javascript_unsafe_int_binary() { 2483 + assert_js_warning!( 2484 + r#" 2485 + pub fn go() { 2486 + [ 2487 + 0b11111111111111111111111111111111111111111111111111110, 2488 + 0b11111111111111111111111111111111111111111111111111111, 2489 + 0b100000000000000000000000000000000000000000000000000000, 2490 + ] 2491 + } 2492 + "# 2493 + ); 2494 + } 2495 + 2496 + #[test] 2497 + fn javascript_unsafe_int_octal() { 2498 + assert_js_warning!( 2499 + r#" 2500 + pub fn go() { 2501 + [ 2502 + 0o377777777777777776, 2503 + 0o377777777777777777, 2504 + 0o400000000000000000, 2505 + ] 2506 + } 2507 + "# 2508 + ); 2509 + } 2510 + 2511 + #[test] 2512 + fn javascript_unsafe_int_hex() { 2513 + assert_js_warning!( 2514 + r#" 2515 + pub fn go() { 2516 + [ 2517 + 0x1FFFFFFFFFFFFE, 2518 + 0x1FFFFFFFFFFFFF, 2519 + 0x20000000000000, 2520 + ] 2521 + } 2522 + "# 2523 + ); 2524 + } 2525 + 2526 + #[test] 2527 + fn javascript_unsafe_int_in_tuple() { 2528 + assert_js_warning!( 2529 + r#" 2530 + pub fn go() { 2531 + #(9_007_199_254_740_992) 2532 + } 2533 + "# 2534 + ); 2535 + } 2536 + 2537 + #[test] 2538 + fn javascript_unsafe_int_segment_in_bit_array() { 2539 + assert_js_warning!( 2540 + r#" 2541 + pub fn go() { 2542 + <<9_007_199_254_740_992:64>> 2543 + } 2544 + "# 2545 + ); 2546 + } 2547 + 2548 + #[test] 2549 + fn javascript_unsafe_int_segment_size_in_bit_array() { 2550 + assert_js_warning!( 2551 + r#" 2552 + pub fn go() { 2553 + [ 2554 + <<0:9_007_199_254_740_992>>, 2555 + <<0:size(9_007_199_254_740_992)>>, 2556 + ] 2557 + } 2558 + "# 2559 + ); 2560 + } 2561 + 2562 + #[test] 2563 + fn javascript_unsafe_int_in_const() { 2564 + assert_js_warning!(r#"pub const i = 9_007_199_254_740_992"#); 2565 + } 2566 + 2567 + #[test] 2568 + fn javascript_unsafe_int_in_const_tuple() { 2569 + assert_js_warning!(r#"pub const i = #(9_007_199_254_740_992)"#); 2570 + } 2571 + 2572 + #[test] 2573 + fn javascript_unsafe_int_segment_in_const_bit_array() { 2574 + assert_js_warning!( 2575 + r#" 2576 + pub const i = <<9_007_199_254_740_992:64>> 2577 + "# 2578 + ); 2579 + } 2580 + 2581 + #[test] 2582 + fn javascript_unsafe_int_segment_size_in_const_bit_array() { 2583 + assert_js_warning!( 2584 + r#" 2585 + pub const ints = [ 2586 + <<0:9_007_199_254_740_992>>, 2587 + <<0:size(9_007_199_254_740_992)>>, 2588 + ] 2589 + "# 2590 + ); 2591 + }
+23
compiler-core/src/warning.rs
··· 1061 1061 }), 1062 1062 } 1063 1063 } 1064 + 1065 + type_::Warning::JavaScriptIntUnsafe { location } => Diagnostic { 1066 + title: "Int is outside JavaScript's safe integer range".into(), 1067 + text: wrap( 1068 + "This integer value is too large to be represented accurately by \ 1069 + JavaScript's number type. To avoid this warning integer values must be in the range \ 1070 + -(2^53 - 1) - (2^53 - 1). 1071 + 1072 + See JavaScript's Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER properties for more \ 1073 + information.", 1074 + ), 1075 + hint: None, 1076 + level: diagnostic::Level::Warning, 1077 + location: Some(Location { 1078 + path: path.to_path_buf(), 1079 + src: src.clone(), 1080 + label: diagnostic::Label { 1081 + text: Some("This is not a safe integer value on JavaScript".into()), 1082 + span: *location, 1083 + }, 1084 + extra_labels: Vec::new(), 1085 + }), 1086 + }, 1064 1087 }, 1065 1088 } 1066 1089 }