⭐️ A friendly language for building type-safe, scalable systems!

Upgrade pubgrub version.

This commit updates the pubgrub and hexpm dependency version. It also
makes sure that version ranges are parsed on creation rather than use to
improve error handling.

authored by Sebastian Bugge and committed by Louis Pilfold 7340d0af f8b83c76

+84 -27
Cargo.lock
··· 226 226 "nom", 227 227 "num-traits", 228 228 "rusticata-macros", 229 - "thiserror", 229 + "thiserror 1.0.69", 230 230 "time", 231 231 ] 232 232 ··· 687 687 dependencies = [ 688 688 "cfg-if", 689 689 "crossbeam-utils", 690 - "hashbrown", 690 + "hashbrown 0.14.3", 691 691 "lock_api", 692 692 "once_cell", 693 693 "parking_lot_core", ··· 927 927 source = "registry+https://github.com/rust-lang/crates.io-index" 928 928 checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" 929 929 dependencies = [ 930 - "thiserror", 930 + "thiserror 1.0.69", 931 931 ] 932 932 933 933 [[package]] ··· 1191 1191 "strum", 1192 1192 "tar", 1193 1193 "termcolor", 1194 - "thiserror", 1194 + "thiserror 1.0.69", 1195 1195 "toml", 1196 1196 "tracing", 1197 1197 "unicode-segmentation", ··· 1238 1238 version = "0.14.3" 1239 1239 source = "registry+https://github.com/rust-lang/crates.io-index" 1240 1240 checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 1241 + 1242 + [[package]] 1243 + name = "hashbrown" 1244 + version = "0.15.3" 1245 + source = "registry+https://github.com/rust-lang/crates.io-index" 1246 + checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" 1241 1247 1242 1248 [[package]] 1243 1249 name = "heck" ··· 1253 1259 1254 1260 [[package]] 1255 1261 name = "hexpm" 1256 - version = "3.3.0" 1262 + version = "4.1.0" 1257 1263 source = "registry+https://github.com/rust-lang/crates.io-index" 1258 - checksum = "0d4ea53d065cbbcc44f7a5f1814ae2c526d934c5344b97caf2953125aea28e79" 1264 + checksum = "4f62182f03cb6894803f78f69dd22720bb9ed5ee6f7e5a64034c67a043e72f81" 1259 1265 dependencies = [ 1260 1266 "base16", 1261 1267 "bytes", ··· 1270 1276 "ring", 1271 1277 "serde", 1272 1278 "serde_json", 1273 - "thiserror", 1279 + "thiserror 1.0.69", 1274 1280 "url", 1275 1281 "x509-parser", 1276 1282 ] ··· 1428 1434 "log", 1429 1435 "serde", 1430 1436 "serde_derive", 1431 - "thiserror", 1437 + "thiserror 1.0.69", 1432 1438 "unic-langid", 1433 1439 ] 1434 1440 ··· 1448 1454 "log", 1449 1455 "parking_lot", 1450 1456 "rust-embed", 1451 - "thiserror", 1457 + "thiserror 1.0.69", 1452 1458 "unic-langid", 1453 1459 "walkdir", 1454 1460 ] ··· 1688 1694 1689 1695 [[package]] 1690 1696 name = "indexmap" 1691 - version = "2.2.6" 1697 + version = "2.9.0" 1692 1698 source = "registry+https://github.com/rust-lang/crates.io-index" 1693 - checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 1699 + checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 1694 1700 dependencies = [ 1695 1701 "equivalent", 1696 - "hashbrown", 1702 + "hashbrown 0.15.3", 1697 1703 ] 1698 1704 1699 1705 [[package]] ··· 2208 2214 ] 2209 2215 2210 2216 [[package]] 2217 + name = "priority-queue" 2218 + version = "2.3.1" 2219 + source = "registry+https://github.com/rust-lang/crates.io-index" 2220 + checksum = "ef08705fa1589a1a59aa924ad77d14722cb0cd97b67dd5004ed5f4a4873fce8d" 2221 + dependencies = [ 2222 + "autocfg", 2223 + "equivalent", 2224 + "indexmap", 2225 + ] 2226 + 2227 + [[package]] 2211 2228 name = "proc-macro-error-attr2" 2212 2229 version = "2.0.0" 2213 2230 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2301 2318 2302 2319 [[package]] 2303 2320 name = "pubgrub" 2304 - version = "0.2.1" 2321 + version = "0.3.0" 2305 2322 source = "registry+https://github.com/rust-lang/crates.io-index" 2306 - checksum = "cdd14552ad5f5d743a323c10d576f26822a044355d6601f377d813ece46f38fd" 2323 + checksum = "3f5df7e552bc7edd075f5783a87fbfc21d6a546e32c16985679c488c18192d83" 2307 2324 dependencies = [ 2308 - "rustc-hash 1.1.0", 2309 - "thiserror", 2325 + "indexmap", 2326 + "log", 2327 + "priority-queue", 2328 + "rustc-hash 2.0.0", 2329 + "thiserror 2.0.12", 2330 + "version-ranges", 2310 2331 ] 2311 2332 2312 2333 [[package]] ··· 2339 2360 "quinn-udp", 2340 2361 "rustc-hash 1.1.0", 2341 2362 "rustls", 2342 - "thiserror", 2363 + "thiserror 1.0.69", 2343 2364 "tokio", 2344 2365 "tracing", 2345 2366 ] ··· 2356 2377 "rustc-hash 2.0.0", 2357 2378 "rustls", 2358 2379 "slab", 2359 - "thiserror", 2380 + "thiserror 1.0.69", 2360 2381 "tinyvec", 2361 2382 "tracing", 2362 2383 ] ··· 2492 2513 dependencies = [ 2493 2514 "getrandom 0.2.15", 2494 2515 "libredox", 2495 - "thiserror", 2516 + "thiserror 1.0.69", 2496 2517 ] 2497 2518 2498 2519 [[package]] ··· 3171 3192 source = "registry+https://github.com/rust-lang/crates.io-index" 3172 3193 checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 3173 3194 dependencies = [ 3174 - "thiserror-impl", 3195 + "thiserror-impl 1.0.69", 3196 + ] 3197 + 3198 + [[package]] 3199 + name = "thiserror" 3200 + version = "2.0.12" 3201 + source = "registry+https://github.com/rust-lang/crates.io-index" 3202 + checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 3203 + dependencies = [ 3204 + "thiserror-impl 2.0.12", 3175 3205 ] 3176 3206 3177 3207 [[package]] ··· 3179 3209 version = "1.0.69" 3180 3210 source = "registry+https://github.com/rust-lang/crates.io-index" 3181 3211 checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 3212 + dependencies = [ 3213 + "proc-macro2", 3214 + "quote", 3215 + "syn 2.0.101", 3216 + ] 3217 + 3218 + [[package]] 3219 + name = "thiserror-impl" 3220 + version = "2.0.12" 3221 + source = "registry+https://github.com/rust-lang/crates.io-index" 3222 + checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 3182 3223 dependencies = [ 3183 3224 "proc-macro2", 3184 3225 "quote", ··· 3288 3329 3289 3330 [[package]] 3290 3331 name = "toml_datetime" 3291 - version = "0.6.8" 3332 + version = "0.6.9" 3292 3333 source = "registry+https://github.com/rust-lang/crates.io-index" 3293 - checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 3334 + checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" 3294 3335 3295 3336 [[package]] 3296 3337 name = "toml_edit" 3297 - version = "0.22.20" 3338 + version = "0.22.26" 3298 3339 source = "registry+https://github.com/rust-lang/crates.io-index" 3299 - checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" 3340 + checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" 3300 3341 dependencies = [ 3301 3342 "indexmap", 3302 3343 "toml_datetime", 3344 + "toml_write", 3303 3345 "winnow", 3304 3346 ] 3347 + 3348 + [[package]] 3349 + name = "toml_write" 3350 + version = "0.1.1" 3351 + source = "registry+https://github.com/rust-lang/crates.io-index" 3352 + checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" 3305 3353 3306 3354 [[package]] 3307 3355 name = "tower" ··· 3557 3605 version = "1.12.1" 3558 3606 source = "registry+https://github.com/rust-lang/crates.io-index" 3559 3607 checksum = "eab68b56840f69efb0fefbe3ab6661499217ffdc58e2eef7c3f6f69835386322" 3608 + 3609 + [[package]] 3610 + name = "version-ranges" 3611 + version = "0.1.1" 3612 + source = "registry+https://github.com/rust-lang/crates.io-index" 3613 + checksum = "f8d079415ceb2be83fc355adbadafe401307d5c309c7e6ade6638e6f9f42f42d" 3614 + dependencies = [ 3615 + "smallvec", 3616 + ] 3560 3617 3561 3618 [[package]] 3562 3619 name = "version_check" ··· 3999 4056 4000 4057 [[package]] 4001 4058 name = "winnow" 4002 - version = "0.6.26" 4059 + version = "0.7.9" 4003 4060 source = "registry+https://github.com/rust-lang/crates.io-index" 4004 - checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" 4061 + checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" 4005 4062 dependencies = [ 4006 4063 "memchr", 4007 4064 ] ··· 4052 4109 "nom", 4053 4110 "oid-registry", 4054 4111 "rusticata-macros", 4055 - "thiserror", 4112 + "thiserror 1.0.69", 4056 4113 "time", 4057 4114 ] 4058 4115
+2 -2
Cargo.toml
··· 29 29 # Enum trait impl macros 30 30 strum = { version = "0", features = ["derive"] } 31 31 # Hex package manager client 32 - hexpm = "3.3" 32 + hexpm = "4" 33 33 # Creation of tar file archives 34 34 tar = "0" 35 35 # gzip compression ··· 61 61 insta = { version = "1", features = ["glob"] } 62 62 # A transitive dependency needed to compile into wasm32-unknown-unknown 63 63 # See https://docs.rs/getrandom/latest/getrandom/index.html#webassembly-support 64 - getrandom = { version = "0", features = ["js"] } 64 + getrandom = { version = "0.2", features = ["js"] }
+1 -1
compiler-cli/Cargo.toml
··· 36 36 # Open generated docs in browser 37 37 opener = "0" 38 38 # Pubgrub dependency resolution algorithm 39 - pubgrub = "0" 39 + pubgrub = "0.3" 40 40 41 41 camino = { workspace = true, features = ["serde1"] } 42 42 async-trait.workspace = true
+18 -24
compiler-cli/src/dependencies.rs
··· 15 15 Error, Result, 16 16 build::{Mode, Target, Telemetry}, 17 17 config::PackageConfig, 18 - dependency, 18 + dependency::{self, PackageFetchError}, 19 19 error::{FileIoAction, FileKind, ShellCommandFailureReason, StandardIoAction}, 20 20 hex::{self, HEXPM_PUBLIC_KEY}, 21 21 io::{HttpClient as _, TarUnpacker, WrappedReader}, ··· 314 314 pub fn parse_gleam_add_specifier(package: &str) -> Result<(EcoString, Requirement)> { 315 315 let Some((package, version)) = package.split_once('@') else { 316 316 // Default to the latest version available. 317 - return Ok((package.into(), Requirement::hex(">= 0.0.0"))); 317 + return Ok(( 318 + package.into(), 319 + Requirement::hex(">= 0.0.0").expect("'>= 0.0.0' should be a valid pubgrub range"), 320 + )); 318 321 }; 319 322 320 323 // Parse the major and minor from the provided semantic version. ··· 357 360 ), 358 361 }); 359 362 } 360 - }; 363 + }?; 361 364 362 365 Ok((package.into(), requirement)) 363 366 } ··· 958 961 match provided.get(&package_name) { 959 962 Some(package) if package.source == package_source => { 960 963 // This package has already been provided from this source, return the version 961 - let version = hexpm::version::Range::new(format!("== {}", &package.version)); 964 + let version = hexpm::version::Range::new(format!("== {}", &package.version)) 965 + .expect("== {version} should be a valid range"); 962 966 return Ok(version); 963 967 } 964 968 Some(package) => { ··· 1006 1010 } 1007 1011 let _ = parents.pop(); 1008 1012 // Add the package to the provided packages dictionary 1009 - let version = hexpm::version::Range::new(format!("== {}", &config.version)); 1013 + let version = hexpm::version::Range::new(format!("== {}", &config.version)) 1014 + .expect("== {version} should be a valid range"); 1010 1015 let _ = provided.insert( 1011 1016 config.name, 1012 1017 ProvidedPackage { ··· 1160 1165 } 1161 1166 1162 1167 impl dependency::PackageFetcher for PackageFetcher { 1163 - fn get_dependencies( 1164 - &self, 1165 - package: &str, 1166 - ) -> Result<Rc<hexpm::Package>, Box<dyn std::error::Error>> { 1168 + fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError> { 1167 1169 { 1168 1170 let runtime_cache = self.runtime_cache.borrow(); 1169 1171 let result = runtime_cache.get(package); ··· 1179 1181 let response = self 1180 1182 .runtime 1181 1183 .block_on(self.http.send(request)) 1182 - .map_err(Box::new)?; 1184 + .map_err(PackageFetchError::fetch_error)?; 1183 1185 1184 - match hexpm::get_package_response(response, HEXPM_PUBLIC_KEY) { 1185 - Ok(pkg) => { 1186 - let pkg = Rc::new(pkg); 1187 - let pkg_ref = Rc::clone(&pkg); 1188 - self.cache_package(package, pkg); 1189 - Ok(pkg_ref) 1190 - } 1191 - Err(e) => match e { 1192 - hexpm::ApiError::NotFound => { 1193 - Err(format!("I couldn't find a package called `{}`", package).into()) 1194 - } 1195 - _ => Err(e.into()), 1196 - }, 1197 - } 1186 + let pkg = hexpm::get_package_response(response, HEXPM_PUBLIC_KEY) 1187 + .map_err(PackageFetchError::from)?; 1188 + let pkg = Rc::new(pkg); 1189 + let pkg_ref = Rc::clone(&pkg); 1190 + self.cache_package(package, pkg); 1191 + Ok(pkg_ref) 1198 1192 } 1199 1193 }
+49 -61
compiler-cli/src/dependencies/tests.rs
··· 320 320 #[test] 321 321 fn parse_gleam_add_specifier_default() { 322 322 let provided = "some_package"; 323 - let expected = ">= 0.0.0"; 323 + let expected = Requirement::hex(">= 0.0.0").unwrap(); 324 324 let (package, version) = parse_gleam_add_specifier(provided).unwrap(); 325 - match &version { 326 - Requirement::Hex { version: v } => { 327 - assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}"); 328 - } 329 - _ => assert!(false, "failed hexpm version parse: {provided}"), 330 - } 331 - assert_eq!(version, Requirement::hex(expected)); 325 + assert_eq!(version, expected); 332 326 assert_eq!("some_package", package); 333 327 } 334 328 335 329 #[test] 336 330 fn parse_gleam_add_specifier_major_only() { 337 331 let provided = "wobble@1"; 338 - let expected = ">= 1.0.0 and < 2.0.0"; 332 + let expected = Requirement::hex(">= 1.0.0 and < 2.0.0").unwrap(); 339 333 let (package, version) = parse_gleam_add_specifier(provided).unwrap(); 340 - match &version { 341 - Requirement::Hex { version: v } => { 342 - assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}"); 343 - } 344 - _ => assert!(false, "failed hexpm version parse: {provided}"), 345 - } 346 - assert_eq!(version, Requirement::hex(expected)); 334 + assert_eq!(version, expected); 347 335 assert_eq!("wobble", package); 348 336 } 349 337 350 338 #[test] 351 339 fn parse_gleam_add_specifier_major_and_minor() { 352 340 let provided = "wibble@1.2"; 353 - let expected = ">= 1.2.0 and < 2.0.0"; 341 + let expected = Requirement::hex(">= 1.2.0 and < 2.0.0").unwrap(); 354 342 let (package, version) = parse_gleam_add_specifier(provided).unwrap(); 355 - match &version { 356 - Requirement::Hex { version: v } => { 357 - assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}"); 358 - } 359 - _ => assert!(false, "failed hexpm version parse: {provided}"), 360 - } 361 - assert_eq!(version, Requirement::hex(expected)); 343 + assert_eq!(version, expected); 362 344 assert_eq!("wibble", package); 363 345 } 364 346 365 347 #[test] 366 348 fn parse_gleam_add_specifier_major_minor_and_patch() { 367 349 let provided = "bobble@1.2.3"; 368 - let expected = "1.2.3"; 350 + let expected = Requirement::hex("1.2.3").unwrap(); 369 351 let (package, version) = parse_gleam_add_specifier(provided).unwrap(); 370 - match &version { 371 - Requirement::Hex { version: v } => { 372 - assert!(v.to_pubgrub().is_ok(), "failed pubgrub parse: {v}"); 373 - } 374 - _ => assert!(false, "failed hexpm version parse: {provided}"), 375 - } 376 - assert_eq!(version, Requirement::hex(expected)); 352 + assert_eq!(version, expected); 377 353 assert_eq!("bobble", package); 378 354 } 379 355 ··· 533 509 &mut provided, 534 510 &mut vec!["root".into(), "subpackage".into()], 535 511 ); 536 - assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into()))); 512 + assert_eq!( 513 + result, 514 + Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap()) 515 + ); 537 516 538 517 let result = provide_local_package( 539 518 "hello_world".into(), ··· 543 522 &mut provided, 544 523 &mut vec!["root".into(), "subpackage".into()], 545 524 ); 546 - assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into()))); 525 + assert_eq!( 526 + result, 527 + Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap()) 528 + ); 547 529 } 548 530 549 531 #[test] ··· 558 540 &mut provided, 559 541 &mut vec!["root".into(), "subpackage".into()], 560 542 ); 561 - assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into()))); 543 + assert_eq!( 544 + result, 545 + Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap()) 546 + ); 562 547 563 548 let result = provide_package( 564 549 "hello_world".into(), ··· 592 577 &mut provided, 593 578 &mut vec!["root".into(), "subpackage".into()], 594 579 ); 595 - assert_eq!(result, Ok(hexpm::version::Range::new("== 0.1.0".into()))); 580 + assert_eq!( 581 + result, 582 + Ok(hexpm::version::Range::new("== 0.1.0".into()).unwrap()) 583 + ); 596 584 let package = provided.get("hello_world").unwrap().clone(); 597 585 match package.source { 598 586 ProvidedPackageSource::Local { path } => { ··· 634 622 requirements: [ 635 623 ( 636 624 "req_1".into(), 637 - hexpm::version::Range::new("~> 1.0.0".into()), 625 + hexpm::version::Range::new("~> 1.0.0".into()).unwrap(), 638 626 ), 639 627 ( 640 628 "req_2".into(), 641 - hexpm::version::Range::new("== 1.0.0".into()), 629 + hexpm::version::Range::new("== 1.0.0".into()).unwrap(), 642 630 ), 643 631 ] 644 632 .into(), ··· 656 644 ( 657 645 "req_1".into(), 658 646 hexpm::Dependency { 659 - requirement: hexpm::version::Range::new("~> 1.0.0".into()), 647 + requirement: hexpm::version::Range::new("~> 1.0.0".into()).unwrap(), 660 648 optional: false, 661 649 app: None, 662 650 repository: None, ··· 665 653 ( 666 654 "req_2".into(), 667 655 hexpm::Dependency { 668 - requirement: hexpm::version::Range::new("== 1.0.0".into()), 656 + requirement: hexpm::version::Range::new("== 1.0.0".into()).unwrap(), 669 657 optional: false, 670 658 app: None, 671 659 repository: None, ··· 693 681 requirements: [ 694 682 ( 695 683 "req_1".into(), 696 - hexpm::version::Range::new("~> 1.0.0".into()), 684 + hexpm::version::Range::new("~> 1.0.0".into()).unwrap(), 697 685 ), 698 686 ( 699 687 "req_2".into(), 700 - hexpm::version::Range::new("== 1.0.0".into()), 688 + hexpm::version::Range::new("== 1.0.0".into()).unwrap(), 701 689 ), 702 690 ] 703 691 .into(), ··· 715 703 ( 716 704 "req_1".into(), 717 705 hexpm::Dependency { 718 - requirement: hexpm::version::Range::new("~> 1.0.0".into()), 706 + requirement: hexpm::version::Range::new("~> 1.0.0".into()).unwrap(), 719 707 optional: false, 720 708 app: None, 721 709 repository: None, ··· 724 712 ( 725 713 "req_2".into(), 726 714 hexpm::Dependency { 727 - requirement: hexpm::version::Range::new("== 1.0.0".into()), 715 + requirement: hexpm::version::Range::new("== 1.0.0".into()).unwrap(), 728 716 optional: false, 729 717 app: None, 730 718 repository: None, ··· 751 739 requirements: [ 752 740 ( 753 741 "req_1".into(), 754 - hexpm::version::Range::new("~> 1.0.0".into()), 742 + hexpm::version::Range::new("~> 1.0.0".into()).unwrap(), 755 743 ), 756 744 ( 757 745 "req_2".into(), 758 - hexpm::version::Range::new("== 1.0.0".into()), 746 + hexpm::version::Range::new("== 1.0.0".into()).unwrap(), 759 747 ), 760 748 ] 761 749 .into(), ··· 789 777 requirements: [ 790 778 ( 791 779 "req_1".into(), 792 - hexpm::version::Range::new("~> 1.0.0".into()), 780 + hexpm::version::Range::new("~> 1.0.0".into()).unwrap(), 793 781 ), 794 782 ( 795 783 "req_2".into(), 796 - hexpm::version::Range::new("== 1.0.0".into()), 784 + hexpm::version::Range::new("== 1.0.0".into()).unwrap(), 797 785 ), 798 786 ] 799 787 .into(), ··· 875 863 ( 876 864 name, 877 865 Requirement::Hex { 878 - version: hexpm::version::Range::new(range.into()), 866 + version: hexpm::version::Range::new(range.into()).unwrap(), 879 867 }, 880 868 ) 881 869 }) ··· 1219 1207 #[test] 1220 1208 fn test_remove_do_nothing() { 1221 1209 let config = package_config( 1222 - HashMap::from([("a".into(), Requirement::hex("~>1"))]), 1223 - HashMap::from([("b".into(), Requirement::hex("~>2"))]), 1210 + HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]), 1211 + HashMap::from([("b".into(), Requirement::hex("~>2.0").unwrap())]), 1224 1212 ); 1225 1213 1226 1214 let mut manifest = Manifest { 1227 1215 requirements: HashMap::from([ 1228 - ("a".into(), Requirement::hex("~>1")), 1229 - ("b".into(), Requirement::hex("~>2")), 1216 + ("a".into(), Requirement::hex("~>1.0").unwrap()), 1217 + ("b".into(), Requirement::hex("~>2.0").unwrap()), 1230 1218 ]), 1231 1219 packages: vec![ 1232 1220 manifest_package("a", "1.0.0", vec![]), ··· 1247 1235 let config = package_config(HashMap::new(), HashMap::new()); 1248 1236 1249 1237 let mut manifest = Manifest { 1250 - requirements: HashMap::from([("a".into(), Requirement::hex("~>1"))]), 1238 + requirements: HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]), 1251 1239 packages: vec![manifest_package("a", "1.0.0", vec![])], 1252 1240 }; 1253 1241 ··· 1262 1250 let config = package_config(HashMap::new(), HashMap::new()); 1263 1251 1264 1252 let mut manifest = Manifest { 1265 - requirements: HashMap::from([("a".into(), Requirement::hex("~>1"))]), 1253 + requirements: HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]), 1266 1254 packages: vec![ 1267 1255 manifest_package("a", "1.0.0", vec!["b".into()]), 1268 1256 manifest_package("b", "1.2.3", vec!["c".into()]), ··· 1279 1267 #[test] 1280 1268 fn test_remove_package_with_shared_transitive_dependencies() { 1281 1269 let config = package_config( 1282 - HashMap::from([("a".into(), Requirement::hex("~>1"))]), 1270 + HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]), 1283 1271 HashMap::new(), 1284 1272 ); 1285 1273 1286 1274 let mut manifest = Manifest { 1287 1275 requirements: HashMap::from([ 1288 - ("a".into(), Requirement::hex("~>1")), 1289 - ("b".into(), Requirement::hex("~>1")), 1276 + ("a".into(), Requirement::hex("~>1.0").unwrap()), 1277 + ("b".into(), Requirement::hex("~>1.0").unwrap()), 1290 1278 ]), 1291 1279 packages: vec![ 1292 1280 manifest_package("a", "1.0.0", vec!["c".into()]), ··· 1311 1299 #[test] 1312 1300 fn test_remove_package_that_is_also_a_transitive_dependency() { 1313 1301 let config = package_config( 1314 - HashMap::from([("a".into(), Requirement::hex("~>1"))]), 1302 + HashMap::from([("a".into(), Requirement::hex("~>1.0").unwrap())]), 1315 1303 HashMap::new(), 1316 1304 ); 1317 1305 1318 1306 let mut manifest = Manifest { 1319 1307 requirements: HashMap::from([ 1320 - ("a".into(), Requirement::hex("~>1")), 1321 - ("b".into(), Requirement::hex("~>1")), 1308 + ("a".into(), Requirement::hex("~>1.0").unwrap()), 1309 + ("b".into(), Requirement::hex("~>1.0").unwrap()), 1322 1310 ]), 1323 1311 packages: vec![ 1324 1312 manifest_package("a", "1.0.0", vec!["b".into(), "c".into()]),
+3 -4
compiler-cli/src/publish.rs
··· 335 335 // inferred lower bound could be lower. 336 336 let minimum_required_version = 337 337 std::cmp::max(minimum_required_version, Version::new(1, 0, 0)); 338 - let inferred_version_range = 339 - pubgrub::range::Range::higher_than(minimum_required_version); 338 + let inferred_version_range = pubgrub::Range::higher_than(minimum_required_version); 340 339 config.gleam_version = Some(GleamVersion::from_pubgrub(inferred_version_range)); 341 340 } 342 341 // Otherwise we need to check that the annotated version range is ··· 699 698 let version = "1.2.3".try_into().unwrap(); 700 699 let homepage = "https://gleam.run".parse().unwrap(); 701 700 let github = "https://github.com/lpil/myapp".parse().unwrap(); 702 - let req1 = Range::new("~> 1.2.3 or >= 5.0.0".into()); 703 - let req2 = Range::new("~> 1.2".into()); 701 + let req1 = Range::new("~> 1.2.3 or >= 5.0.0".into()).unwrap(); 702 + let req2 = Range::new("~> 1.2".into()).unwrap(); 704 703 let meta = ReleaseMetadata { 705 704 name: "myapp", 706 705 version: &version,
+1 -1
compiler-core/Cargo.toml
··· 31 31 # Checksums 32 32 xxhash-rust = { version = "0", features = ["xxh3"] } 33 33 # Pubgrub dependency resolution algorithm 34 - pubgrub = "0" 34 + pubgrub = "0.3" 35 35 # Used for converting absolute path to relative path 36 36 pathdiff = { version = "0", features = ["camino"] } 37 37 # Memory arena using ids rather than references
+1 -1
compiler-core/src/analyse.rs
··· 214 214 .package_config 215 215 .gleam_version 216 216 .clone() 217 - .map(|version| version.as_pubgrub()), 217 + .map(|version| version.into()), 218 218 current_module: self.module_name.clone(), 219 219 target: self.target, 220 220 importable_modules: self.importable_modules,
+1 -1
compiler-core/src/build/project_compiler.rs
··· 24 24 use ecow::EcoString; 25 25 use hexpm::version::Version; 26 26 use itertools::Itertools; 27 - use pubgrub::range::Range; 27 + use pubgrub::Range; 28 28 use std::{ 29 29 cmp, 30 30 collections::{HashMap, HashSet},
+62 -53
compiler-core/src/config.rs
··· 9 9 use camino::{Utf8Path, Utf8PathBuf}; 10 10 use ecow::EcoString; 11 11 use globset::{Glob, GlobSetBuilder}; 12 - use hexpm::version::{self, Version}; 12 + use hexpm::version::{self, LowestVersion, Version}; 13 13 use http::Uri; 14 14 use serde::ser::SerializeSeq; 15 15 use serde::{Deserialize, Serialize}; ··· 80 80 } 81 81 82 82 #[derive(Debug, PartialEq, Clone)] 83 - pub struct GleamVersion { 84 - pubgrub: pubgrub::range::Range<Version>, 85 - hex: version::Range, 83 + pub struct GleamVersion(version::Range); 84 + impl From<version::Range> for GleamVersion { 85 + fn from(range: version::Range) -> Self { 86 + Self(range) 87 + } 88 + } 89 + 90 + impl From<GleamVersion> for version::Range { 91 + fn from(gleam_version: GleamVersion) -> Self { 92 + gleam_version.0 93 + } 94 + } 95 + 96 + impl From<GleamVersion> for pubgrub::Range<Version> { 97 + fn from(gleam_version: GleamVersion) -> Self { 98 + gleam_version.0.into() 99 + } 86 100 } 87 101 88 102 impl GleamVersion { 89 - pub fn from_pubgrub(range: pubgrub::range::Range<Version>) -> Self { 90 - Self { 91 - hex: version::Range::new(range.to_string()), 92 - pubgrub: range, 93 - } 103 + pub fn from_pubgrub(range: pubgrub::Range<Version>) -> Self { 104 + let range: version::Range = range.into(); 105 + range.into() 94 106 } 95 107 96 - pub fn as_pubgrub(&self) -> pubgrub::range::Range<Version> { 97 - self.pubgrub.clone() 108 + pub fn as_pubgrub(&self) -> &pubgrub::Range<Version> { 109 + self.0.to_pubgrub() 98 110 } 99 111 100 112 pub fn new(spec: String) -> Result<GleamVersion> { 101 - let hex = version::Range::new(spec.to_string()); 102 - let pubgrub = hex.to_pubgrub().map_err(|e| Error::InvalidVersionFormat { 103 - input: spec, 104 - error: e.to_string(), 105 - })?; 106 - 107 - Ok(Self { pubgrub, hex }) 113 + let hex = 114 + version::Range::new(spec.to_string()).map_err(|e| Error::InvalidVersionFormat { 115 + input: spec, 116 + error: e.to_string(), 117 + })?; 118 + Ok(hex.into()) 108 119 } 109 120 110 121 pub fn lowest_version(&self) -> Option<Version> { 111 - self.pubgrub.lowest_version() 122 + self.as_pubgrub().lowest_version() 112 123 } 113 124 114 125 pub fn hex(&self) -> &version::Range { 115 - &self.hex 126 + &self.0 116 127 } 117 128 } 118 129 ··· 162 173 S: serde::Serializer, 163 174 { 164 175 match gleam_gersion { 165 - Some(version) => serializer.serialize_str(&version.hex.to_string()), 176 + Some(version) => serializer.serialize_str(&version.hex().to_string()), 166 177 None => serializer.serialize_none(), 167 178 } 168 179 } ··· 173 184 { 174 185 match Deserialize::deserialize(deserialiser)? { 175 186 Some(range_string) => { 176 - let hex = version::Range::new(range_string); 177 - let pubgrub = hex.clone().to_pubgrub().map_err(serde::de::Error::custom)?; 178 - 179 - Ok(Some(GleamVersion { hex, pubgrub })) 187 + let hex = version::Range::new(range_string).map_err(serde::de::Error::custom)?; 188 + Ok(Some(hex.into())) 180 189 } 181 190 None => Ok(None), 182 191 } ··· 272 281 // with the current compiler version 273 282 pub fn check_gleam_compatibility(&self) -> Result<(), Error> { 274 283 if let Some(version) = &self.gleam_version { 275 - let range = &version.pubgrub; 284 + let range = version.as_pubgrub(); 276 285 let compiler_version = 277 286 Version::parse(COMPILER_VERSION).expect("Parse compiler semantic version"); 278 287 ··· 296 305 fn locked_no_manifest() { 297 306 let mut config = PackageConfig::default(); 298 307 config.dependencies = [ 299 - ("prod1".into(), Requirement::hex("~> 1.0")), 300 - ("prod2".into(), Requirement::hex("~> 2.0")), 308 + ("prod1".into(), Requirement::hex("~> 1.0").unwrap()), 309 + ("prod2".into(), Requirement::hex("~> 2.0").unwrap()), 301 310 ] 302 311 .into(); 303 312 config.dev_dependencies = [ 304 - ("dev1".into(), Requirement::hex("~> 1.0")), 305 - ("dev2".into(), Requirement::hex("~> 2.0")), 313 + ("dev1".into(), Requirement::hex("~> 1.0").unwrap()), 314 + ("dev2".into(), Requirement::hex("~> 2.0").unwrap()), 306 315 ] 307 316 .into(); 308 317 assert_eq!(config.locked(None).unwrap(), [].into()); ··· 312 321 fn locked_no_changes() { 313 322 let mut config = PackageConfig::default(); 314 323 config.dependencies = [ 315 - ("prod1".into(), Requirement::hex("~> 1.0")), 316 - ("prod2".into(), Requirement::hex("~> 2.0")), 324 + ("prod1".into(), Requirement::hex("~> 1.0").unwrap()), 325 + ("prod2".into(), Requirement::hex("~> 2.0").unwrap()), 317 326 ] 318 327 .into(); 319 328 config.dev_dependencies = [ 320 - ("dev1".into(), Requirement::hex("~> 1.0")), 321 - ("dev2".into(), Requirement::hex("~> 2.0")), 329 + ("dev1".into(), Requirement::hex("~> 1.0").unwrap()), 330 + ("dev2".into(), Requirement::hex("~> 2.0").unwrap()), 322 331 ] 323 332 .into(); 324 333 let manifest = Manifest { ··· 345 354 #[test] 346 355 fn locked_some_removed() { 347 356 let mut config = PackageConfig::default(); 348 - config.dependencies = [("prod1".into(), Requirement::hex("~> 1.0"))].into(); 349 - config.dev_dependencies = [("dev2".into(), Requirement::hex("~> 2.0"))].into(); 357 + config.dependencies = [("prod1".into(), Requirement::hex("~> 1.0").unwrap())].into(); 358 + config.dev_dependencies = [("dev2".into(), Requirement::hex("~> 2.0").unwrap())].into(); 350 359 let manifest = Manifest { 351 360 requirements: config.all_direct_dependencies().unwrap(), 352 361 packages: vec![ ··· 372 381 fn locked_some_changed() { 373 382 let mut config = PackageConfig::default(); 374 383 config.dependencies = [ 375 - ("prod1".into(), Requirement::hex("~> 3.0")), // Does not match manifest 376 - ("prod2".into(), Requirement::hex("~> 2.0")), 384 + ("prod1".into(), Requirement::hex("~> 3.0").unwrap()), // Does not match manifest 385 + ("prod2".into(), Requirement::hex("~> 2.0").unwrap()), 377 386 ] 378 387 .into(); 379 388 config.dev_dependencies = [ 380 - ("dev1".into(), Requirement::hex("~> 3.0")), // Does not match manifest 381 - ("dev2".into(), Requirement::hex("~> 2.0")), 389 + ("dev1".into(), Requirement::hex("~> 3.0").unwrap()), // Does not match manifest 390 + ("dev2".into(), Requirement::hex("~> 2.0").unwrap()), 382 391 ] 383 392 .into(); 384 393 let manifest = Manifest { 385 394 requirements: [ 386 - ("prod1".into(), Requirement::hex("~> 1.0")), 387 - ("prod2".into(), Requirement::hex("~> 2.0")), 388 - ("dev1".into(), Requirement::hex("~> 1.0")), 389 - ("dev2".into(), Requirement::hex("~> 2.0")), 395 + ("prod1".into(), Requirement::hex("~> 1.0").unwrap()), 396 + ("prod2".into(), Requirement::hex("~> 2.0").unwrap()), 397 + ("dev1".into(), Requirement::hex("~> 1.0").unwrap()), 398 + ("dev2".into(), Requirement::hex("~> 2.0").unwrap()), 390 399 ] 391 400 .into(), 392 401 packages: vec![ ··· 412 421 fn locked_nested_are_removed_too() { 413 422 let mut config = PackageConfig::default(); 414 423 config.dependencies = [ 415 - ("1".into(), Requirement::hex("~> 2.0")), // Does not match manifest 416 - ("2".into(), Requirement::hex("~> 1.0")), 424 + ("1".into(), Requirement::hex("~> 2.0").unwrap()), // Does not match manifest 425 + ("2".into(), Requirement::hex("~> 1.0").unwrap()), 417 426 ] 418 427 .into(); 419 428 config.dev_dependencies = [].into(); 420 429 let manifest = Manifest { 421 430 requirements: [ 422 - ("1".into(), Requirement::hex("~> 1.0")), 423 - ("2".into(), Requirement::hex("~> 1.0")), 431 + ("1".into(), Requirement::hex("~> 1.0").unwrap()), 432 + ("2".into(), Requirement::hex("~> 1.0").unwrap()), 424 433 ] 425 434 .into(), 426 435 packages: vec![ ··· 463 472 fn locked_unlock_new() { 464 473 let mut config = PackageConfig::default(); 465 474 config.dependencies = [ 466 - ("1".into(), Requirement::hex("~> 1.0")), 467 - ("2".into(), Requirement::hex("~> 1.0")), 468 - ("3".into(), Requirement::hex("~> 3.0")), // Does not match manifest 475 + ("1".into(), Requirement::hex("~> 1.0").unwrap()), 476 + ("2".into(), Requirement::hex("~> 1.0").unwrap()), 477 + ("3".into(), Requirement::hex("~> 3.0").unwrap()), // Does not match manifest 469 478 ] 470 479 .into(); 471 480 config.dev_dependencies = [].into(); 472 481 let manifest = Manifest { 473 482 requirements: [ 474 - ("1".into(), Requirement::hex("~> 1.0")), 475 - ("2".into(), Requirement::hex("~> 1.0")), 483 + ("1".into(), Requirement::hex("~> 1.0").unwrap()), 484 + ("2".into(), Requirement::hex("~> 1.0").unwrap()), 476 485 ] 477 486 .into(), 478 487 packages: vec![
+1 -1
compiler-core/src/config/stale_package_remover.rs
··· 95 95 let requirements = HashMap::from_iter([( 96 96 "required_package".into(), 97 97 Requirement::Hex { 98 - version: Range::new("1.0.0".into()), 98 + version: Range::new("1.0.0".into()).unwrap(), 99 99 }, 100 100 )]); 101 101 let manifest = Manifest {
+177 -106
compiler-core/src/dependency.rs
··· 1 - use std::{borrow::Borrow, cell::RefCell, collections::HashMap, error::Error as StdError, rc::Rc}; 1 + use std::{cell::RefCell, cmp::Reverse, collections::HashMap, rc::Rc}; 2 2 3 3 use crate::{Error, Result, manifest}; 4 4 5 5 use ecow::EcoString; 6 6 use hexpm::{ 7 7 Dependency, Release, 8 - version::{Range, ResolutionError, Version}, 8 + version::{Range, Version}, 9 9 }; 10 - use pubgrub::{ 11 - solver::{Dependencies, choose_package_with_fewest_versions}, 12 - type_aliases::Map, 13 - }; 10 + use pubgrub::{Dependencies, Map}; 11 + use thiserror::Error; 14 12 15 13 pub type PackageVersions = HashMap<String, Version>; 16 14 17 - type PubgrubRange = pubgrub::range::Range<Version>; 15 + type PubgrubRange = pubgrub::Range<Version>; 18 16 19 17 pub fn resolve_versions<Requirements>( 20 18 package_fetcher: &impl PackageFetcher, ··· 28 26 { 29 27 tracing::info!("resolving_versions"); 30 28 let root_version = Version::new(0, 0, 0); 31 - let requirements = root_dependencies(dependencies, locked) 32 - .map_err(|boxed_error| Error::dependency_resolution_failed(*boxed_error))?; 29 + let requirements = root_dependencies(dependencies, locked)?; 33 30 34 31 // Creating a map of all the required packages that have exact versions specified 35 32 let exact_deps = &requirements ··· 50 47 }], 51 48 }; 52 49 53 - let packages = pubgrub::solver::resolve( 50 + let packages = pubgrub::resolve( 54 51 &DependencyProvider::new(package_fetcher, provided_packages, root, locked, exact_deps), 55 52 root_name.as_str().into(), 56 53 root_version, ··· 136 133 fn root_dependencies<Requirements>( 137 134 base_requirements: Requirements, 138 135 locked: &HashMap<EcoString, Version>, 139 - ) -> Result<HashMap<String, Dependency>, Box<ResolutionError>> 136 + ) -> Result<HashMap<String, Dependency>, Error> 140 137 where 141 138 Requirements: Iterator<Item = (EcoString, Range)>, 142 139 { ··· 150 147 app: None, 151 148 optional: false, 152 149 repository: None, 153 - requirement: Range::new(version.to_string()), 150 + requirement: version.clone().into(), 154 151 }, 155 152 ) 156 153 }) ··· 175 172 // If the version was locked we verify that the requirement is 176 173 // compatible with the locked version. 177 174 Some(locked_version) => { 178 - let compatible = range 179 - .to_pubgrub() 180 - .map_err(|e| { 181 - Box::new(ResolutionError::Failure(format!( 182 - "Failed to parse range {e}" 183 - ))) 184 - })? 185 - .contains(locked_version); 175 + let compatible = range.to_pubgrub().contains(locked_version); 186 176 if !compatible { 187 - return Err(Box::new(ResolutionError::Failure(format!( 188 - "{name} is specified with the requirement `{range}`, \ 177 + return Err(Error::IncompatibleLockedVersion { 178 + error: format!( 179 + "{name} is specified with the requirement `{range}`, \ 189 180 but it is locked to {locked_version}, which is incompatible.", 190 - )))); 181 + ), 182 + }); 191 183 } 192 184 } 193 185 }; ··· 197 189 } 198 190 199 191 pub trait PackageFetcher { 200 - fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, Box<dyn StdError>>; 192 + fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError>; 193 + } 194 + 195 + #[derive(Debug, Error)] 196 + pub enum PackageFetchError { 197 + #[error("{0}")] 198 + ApiError(hexpm::ApiError), 199 + #[error("{0}")] 200 + FetchError(String), 201 + } 202 + impl From<hexpm::ApiError> for PackageFetchError { 203 + fn from(api_error: hexpm::ApiError) -> Self { 204 + Self::ApiError(api_error) 205 + } 206 + } 207 + impl PackageFetchError { 208 + pub fn fetch_error<T: std::error::Error>(err: T) -> Self { 209 + Self::FetchError(err.to_string()) 210 + } 201 211 } 202 212 203 - struct DependencyProvider<'a, T: PackageFetcher> { 213 + #[derive(Debug)] 214 + pub struct DependencyProvider<'a, T: PackageFetcher> { 204 215 packages: RefCell<HashMap<EcoString, hexpm::Package>>, 205 216 remote: &'a T, 206 217 locked: &'a HashMap<EcoString, Version>, ··· 208 219 // We need this because by default pubgrub checks exact version by checking if a version is between the exact 209 220 // and the version 1 bump ahead. That default breaks on prerelease builds since a bump includes the whole patch 210 221 exact_only: &'a HashMap<String, Version>, 211 - optional_dependencies: RefCell<HashMap<EcoString, pubgrub::range::Range<Version>>>, 222 + optional_dependencies: RefCell<HashMap<EcoString, pubgrub::Range<Version>>>, 212 223 } 213 224 214 225 impl<'a, T> DependencyProvider<'a, T> ··· 244 255 // `&self` with interop mutability. 245 256 &self, 246 257 name: &str, 247 - ) -> Result<(), Box<dyn StdError>> { 258 + ) -> Result<(), PackageFetchError> { 248 259 let mut packages = self.packages.borrow_mut(); 249 260 if packages.get(name).is_none() { 250 261 let package = self.remote.get_dependencies(name)?; ··· 266 277 } 267 278 268 279 type PackageName = String; 280 + pub type ResolutionError<'a, T> = pubgrub::PubGrubError<DependencyProvider<'a, T>>; 269 281 270 - impl<T> pubgrub::solver::DependencyProvider<PackageName, Version> for DependencyProvider<'_, T> 282 + impl<T> pubgrub::DependencyProvider for DependencyProvider<'_, T> 271 283 where 272 284 T: PackageFetcher, 273 285 { 274 - fn choose_package_version<Name: Borrow<PackageName>, Ver: Borrow<PubgrubRange>>( 275 - &self, 276 - potential_packages: impl Iterator<Item = (Name, Ver)>, 277 - ) -> Result<(Name, Option<Version>), Box<dyn StdError>> { 278 - let potential_packages: Vec<_> = potential_packages 279 - .map::<Result<_, Box<dyn StdError>>, _>(|pair| { 280 - self.ensure_package_fetched(pair.0.borrow())?; 281 - Ok(pair) 282 - }) 283 - .collect::<Result<_, _>>()?; 284 - let list_available_versions = |name: &PackageName| { 285 - let name = name.as_str(); 286 - let exact_package = self.exact_only.get(name); 287 - self.packages 288 - .borrow() 289 - .get(name) 290 - .cloned() 291 - .into_iter() 292 - .flat_map(move |p| { 293 - p.releases 294 - .into_iter() 295 - // if an exact version of a package is specified then we only want to allow that version as available 296 - .filter(move |release| match exact_package { 297 - Some(ver) => ver == &release.version, 298 - _ => true, 299 - }) 300 - }) 301 - .map(|p| p.version) 302 - }; 303 - Ok(choose_package_with_fewest_versions( 304 - list_available_versions, 305 - potential_packages.into_iter(), 306 - )) 307 - } 308 - 309 286 fn get_dependencies( 310 287 &self, 311 - name: &PackageName, 312 - version: &Version, 313 - ) -> Result<Dependencies<PackageName, Version>, Box<dyn StdError>> { 314 - self.ensure_package_fetched(name)?; 288 + package: &Self::P, 289 + version: &Self::V, 290 + ) -> Result<Dependencies<Self::P, Self::VS, Self::M>, Self::Err> { 291 + self.ensure_package_fetched(package)?; 315 292 let packages = self.packages.borrow(); 316 293 let release = match packages 317 - .get(name.as_str()) 294 + .get(package.as_str()) 318 295 .into_iter() 319 296 .flat_map(|p| p.releases.iter()) 320 297 .find(|r| &r.version == version) 321 298 { 322 299 Some(release) => release, 323 - None => return Ok(Dependencies::Unknown), 300 + None => { 301 + return Ok(Dependencies::Unavailable(format!( 302 + "{package}@{version} is not available" 303 + ))); 304 + } 324 305 }; 325 306 326 307 // Only use retired versions if they have been locked 327 - if release.is_retired() && self.locked.get(name.as_str()) != Some(version) { 328 - return Ok(Dependencies::Unknown); 308 + if release.is_retired() && self.locked.get(package.as_str()) != Some(version) { 309 + return Ok(Dependencies::Unavailable(format!( 310 + "{package}@{version} is retired" 311 + ))); 329 312 } 330 313 331 314 let mut deps: Map<PackageName, PubgrubRange> = Default::default(); 332 315 for (name, d) in &release.requirements { 333 - let mut range = d.requirement.to_pubgrub()?; 316 + let mut range = d.requirement.to_pubgrub().clone(); 334 317 let mut opt_deps = self.optional_dependencies.borrow_mut(); 335 318 // if it's optional and it was not provided yet, store and skip 336 319 if d.optional && !packages.contains_key(name.as_str()) { ··· 350 333 351 334 let _ = deps.insert(name.clone(), range); 352 335 } 353 - Ok(Dependencies::Known(deps)) 336 + Ok(Dependencies::Available(deps)) 337 + } 338 + 339 + fn prioritize( 340 + &self, 341 + package: &Self::P, 342 + range: &Self::VS, 343 + _package_conflicts_counts: &pubgrub::PackageResolutionStatistics, 344 + ) -> Self::Priority { 345 + Reverse( 346 + self.packages 347 + .borrow() 348 + .get(package.as_str()) 349 + .cloned() 350 + .into_iter() 351 + .flat_map(|p| { 352 + p.releases 353 + .into_iter() 354 + .filter(|r| range.contains(&r.version)) 355 + }) 356 + .count(), 357 + ) 358 + } 359 + 360 + fn choose_version( 361 + &self, 362 + package: &Self::P, 363 + range: &Self::VS, 364 + ) -> std::result::Result<Option<Self::V>, Self::Err> { 365 + self.ensure_package_fetched(package)?; 366 + 367 + let exact_package = self.exact_only.get(package); 368 + let potential_versions = self 369 + .packages 370 + .borrow() 371 + .get(package.as_str()) 372 + .cloned() 373 + .into_iter() 374 + .flat_map(move |p| { 375 + p.releases 376 + .into_iter() 377 + // if an exact version of a package is specified then we only want to allow that version as available 378 + .filter_map(move |release| match exact_package { 379 + Some(ver) => (ver == &release.version).then_some(release.version), 380 + _ => Some(release.version), 381 + }) 382 + }) 383 + .filter(|v| range.contains(v)); 384 + match potential_versions.clone().filter(|v| !v.is_pre()).max() { 385 + // Don't resolve to a pre-releaase package unless we *have* to 386 + Some(v) => Ok(Some(v)), 387 + None => Ok(potential_versions.max()), 388 + } 354 389 } 390 + 391 + type P = PackageName; 392 + type V = Version; 393 + type VS = PubgrubRange; 394 + type Priority = Reverse<usize>; 395 + type M = String; 396 + type Err = PackageFetchError; 355 397 } 356 398 357 399 #[cfg(test)] ··· 368 410 } 369 411 370 412 impl PackageFetcher for Remote { 371 - fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, Box<dyn StdError>> { 413 + fn get_dependencies(&self, package: &str) -> Result<Rc<hexpm::Package>, PackageFetchError> { 372 414 self.deps 373 415 .get(package) 374 416 .map(Rc::clone) 375 - .ok_or(Box::new(hexpm::ApiError::NotFound)) 417 + .ok_or(hexpm::ApiError::NotFound.into()) 376 418 } 377 419 } 378 420 ··· 430 472 app: None, 431 473 optional: false, 432 474 repository: None, 433 - requirement: Range::new(">= 0.1.0".into()), 475 + requirement: Range::new(">= 0.1.0".into()).unwrap(), 434 476 }, 435 477 )] 436 478 .into(), ··· 446 488 app: None, 447 489 optional: false, 448 490 repository: None, 449 - requirement: Range::new(">= 0.1.0".into()), 491 + requirement: Range::new(">= 0.1.0".into()).unwrap(), 450 492 }, 451 493 )] 452 494 .into(), ··· 462 504 app: None, 463 505 optional: false, 464 506 repository: None, 465 - requirement: Range::new(">= 0.1.0".into()), 507 + requirement: Range::new(">= 0.1.0".into()).unwrap(), 466 508 }, 467 509 )] 468 510 .into(), ··· 478 520 app: None, 479 521 optional: false, 480 522 repository: None, 481 - requirement: Range::new(">= 0.1.0".into()), 523 + requirement: Range::new(">= 0.1.0".into()).unwrap(), 482 524 }, 483 525 )] 484 526 .into(), ··· 531 573 app: None, 532 574 optional: true, 533 575 repository: None, 534 - requirement: Range::new(">= 0.1.0 and < 0.3.0".into()), 576 + requirement: Range::new(">= 0.1.0 and < 0.3.0".into()).unwrap(), 535 577 }, 536 578 )] 537 579 .into(), ··· 604 646 app: None, 605 647 optional: true, 606 648 repository: None, 607 - requirement: Range::new(range.into()), 649 + requirement: Range::new(range.into()).unwrap(), 608 650 }, 609 651 ) 610 652 }) ··· 627 669 &make_remote(), 628 670 HashMap::new(), 629 671 "app".into(), 630 - vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()))].into_iter(), 672 + vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(), 631 673 &vec![locked_stdlib].into_iter().collect(), 632 674 ) 633 675 .unwrap(); ··· 658 700 &make_remote(), 659 701 HashMap::new(), 660 702 "app".into(), 661 - vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()))].into_iter(), 703 + vec![("gleam_stdlib".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(), 662 704 &vec![].into_iter().collect(), 663 705 ) 664 706 .unwrap(); ··· 676 718 &make_remote(), 677 719 HashMap::new(), 678 720 "app".into(), 679 - vec![("gleam_otp".into(), Range::new("~> 0.1".into()))].into_iter(), 721 + vec![("gleam_otp".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(), 680 722 &vec![].into_iter().collect(), 681 723 ) 682 724 .unwrap(); ··· 697 739 &make_remote(), 698 740 HashMap::new(), 699 741 "app".into(), 700 - vec![("package_with_optional".into(), Range::new("~> 0.1".into()))].into_iter(), 742 + vec![( 743 + "package_with_optional".into(), 744 + Range::new("~> 0.1".into()).unwrap(), 745 + )] 746 + .into_iter(), 701 747 &vec![].into_iter().collect(), 702 748 ) 703 749 .unwrap(); ··· 719 765 HashMap::new(), 720 766 "app".into(), 721 767 vec![ 722 - ("package_with_optional".into(), Range::new("~> 0.1".into())), 723 - ("gleam_stdlib".into(), Range::new("~> 0.1".into())), 768 + ( 769 + "package_with_optional".into(), 770 + Range::new("~> 0.1".into()).unwrap(), 771 + ), 772 + ("gleam_stdlib".into(), Range::new("~> 0.1".into()).unwrap()), 724 773 ] 725 774 .into_iter(), 726 775 &vec![].into_iter().collect(), ··· 747 796 HashMap::new(), 748 797 "app".into(), 749 798 vec![ 750 - ("package_with_optional".into(), Range::new("~> 0.1".into())), 751 - ("gleam_stdlib".into(), Range::new("~> 0.3".into())), 799 + ( 800 + "package_with_optional".into(), 801 + Range::new("~> 0.1".into()).unwrap(), 802 + ), 803 + ("gleam_stdlib".into(), Range::new("~> 0.3".into()).unwrap()), 752 804 ] 753 805 .into_iter(), 754 806 &vec![].into_iter().collect(), ··· 763 815 HashMap::new(), 764 816 "app".into(), 765 817 vec![ 766 - ("package_with_optional".into(), Range::new("~> 0.1".into())), 767 - ("gleam_otp".into(), Range::new("~> 0.1".into())), 818 + ( 819 + "package_with_optional".into(), 820 + Range::new("~> 0.1".into()).unwrap(), 821 + ), 822 + ("gleam_otp".into(), Range::new("~> 0.1".into()).unwrap()), 768 823 ] 769 824 .into_iter(), 770 825 &vec![].into_iter().collect(), ··· 794 849 &make_remote(), 795 850 HashMap::new(), 796 851 "app".into(), 797 - vec![("gleam_otp".into(), Range::new("~> 0.1.0".into()))].into_iter(), 852 + vec![("gleam_otp".into(), Range::new("~> 0.1.0".into()).unwrap())].into_iter(), 798 853 &vec![].into_iter().collect(), 799 854 ) 800 855 .unwrap(); ··· 815 870 &make_remote(), 816 871 HashMap::new(), 817 872 "app".into(), 818 - vec![("package_with_retired".into(), Range::new("> 0.0.0".into()))].into_iter(), 873 + vec![( 874 + "package_with_retired".into(), 875 + Range::new("> 0.0.0".into()).unwrap(), 876 + )] 877 + .into_iter(), 819 878 &vec![].into_iter().collect(), 820 879 ) 821 880 .unwrap(); ··· 837 896 &make_remote(), 838 897 HashMap::new(), 839 898 "app".into(), 840 - vec![("package_with_retired".into(), Range::new("> 0.0.0".into()))].into_iter(), 899 + vec![( 900 + "package_with_retired".into(), 901 + Range::new("> 0.0.0".into()).unwrap(), 902 + )] 903 + .into_iter(), 841 904 &vec![("package_with_retired".into(), Version::new(0, 2, 0))] 842 905 .into_iter() 843 906 .collect(), ··· 861 924 &make_remote(), 862 925 HashMap::new(), 863 926 "app".into(), 864 - vec![("gleam_otp".into(), Range::new("~> 0.3.0-rc1".into()))].into_iter(), 927 + vec![( 928 + "gleam_otp".into(), 929 + Range::new("~> 0.3.0-rc1".into()).unwrap(), 930 + )] 931 + .into_iter(), 865 932 &vec![].into_iter().collect(), 866 933 ) 867 934 .unwrap(); ··· 882 949 &make_remote(), 883 950 HashMap::new(), 884 951 "app".into(), 885 - vec![("gleam_otp".into(), Range::new("0.3.0-rc1".into()))].into_iter(), 952 + vec![("gleam_otp".into(), Range::new("0.3.0-rc1".into()).unwrap())].into_iter(), 886 953 &vec![].into_iter().collect(), 887 954 ) 888 955 .unwrap(); ··· 903 970 &make_remote(), 904 971 HashMap::new(), 905 972 "app".into(), 906 - vec![("unknown".into(), Range::new("~> 0.1".into()))].into_iter(), 973 + vec![("unknown".into(), Range::new("~> 0.1".into()).unwrap())].into_iter(), 907 974 &vec![].into_iter().collect(), 908 975 ) 909 976 .unwrap_err(); ··· 915 982 &make_remote(), 916 983 HashMap::new(), 917 984 "app".into(), 918 - vec![("gleam_stdlib".into(), Range::new("~> 99.0".into()))].into_iter(), 985 + vec![("gleam_stdlib".into(), Range::new("~> 99.0".into()).unwrap())].into_iter(), 919 986 &vec![].into_iter().collect(), 920 987 ) 921 988 .unwrap_err(); ··· 927 994 &make_remote(), 928 995 HashMap::new(), 929 996 "app".into(), 930 - vec![("gleam_stdlib".into(), Range::new("~> 0.1.0".into()))].into_iter(), 997 + vec![( 998 + "gleam_stdlib".into(), 999 + Range::new("~> 0.1.0".into()).unwrap(), 1000 + )] 1001 + .into_iter(), 931 1002 &vec![("gleam_stdlib".into(), Version::new(0, 2, 0))] 932 1003 .into_iter() 933 1004 .collect(), ··· 935 1006 .unwrap_err(); 936 1007 937 1008 match err { 938 - Error::DependencyResolutionFailed(msg) => assert_eq!( 939 - msg, 940 - "An unrecoverable error happened while solving dependencies: gleam_stdlib is specified with the requirement `~> 0.1.0`, but it is locked to 0.2.0, which is incompatible." 1009 + Error::IncompatibleLockedVersion { error } => assert_eq!( 1010 + error, 1011 + "gleam_stdlib is specified with the requirement `~> 0.1.0`, but it is locked to 0.2.0, which is incompatible." 941 1012 ), 942 1013 _ => panic!("wrong error: {err}"), 943 1014 } ··· 949 1020 &make_remote(), 950 1021 HashMap::new(), 951 1022 "app".into(), 952 - vec![("gleam_stdlib".into(), Range::new("0.1.0".into()))].into_iter(), 1023 + vec![("gleam_stdlib".into(), Range::new("0.1.0".into()).unwrap())].into_iter(), 953 1024 &vec![].into_iter().collect(), 954 1025 ) 955 1026 .unwrap(); ··· 986 1057 ( 987 1058 EcoString::from("package_depends_on_indirect_pkg"), 988 1059 requirement::Requirement::Hex { 989 - version: Range::new("> 0.1.0 and <= 1.0.0".into()), 1060 + version: Range::new("> 0.1.0 and <= 1.0.0".into()).unwrap(), 990 1061 }, 991 1062 ), 992 1063 ( 993 1064 EcoString::from("direct_pkg_with_major_version"), 994 1065 requirement::Requirement::Hex { 995 - version: Range::new("> 0.1.0 and <= 2.0.0".into()), 1066 + version: Range::new("> 0.1.0 and <= 2.0.0".into()).unwrap(), 996 1067 }, 997 1068 ), 998 1069 ( 999 1070 EcoString::from("depends_on_old_version_of_direct_pkg"), 1000 1071 requirement::Requirement::Hex { 1001 - version: Range::new("> 0.1.0 and <= 1.0.0".into()), 1072 + version: Range::new("> 0.1.0 and <= 1.0.0".into()).unwrap(), 1002 1073 }, 1003 1074 ), 1004 1075 ]
+36 -27
compiler-core/src/error.rs
··· 1 1 #![allow(clippy::unwrap_used, clippy::expect_used)] 2 2 use crate::build::{Origin, Outcome, Runtime, Target}; 3 + use crate::dependency::{PackageFetcher, ResolutionError}; 3 4 use crate::diagnostic::{Diagnostic, ExtraLabel, Label, Location}; 4 5 use crate::strings::{to_snake_case, to_upper_camel_case}; 5 6 use crate::type_::collapse_links; ··· 12 13 use crate::{ast::BinOp, parse::error::ParseErrorType, type_::Type}; 13 14 use crate::{bit_array, diagnostic::Level, javascript, type_::UnifyErrorSituation}; 14 15 use ecow::EcoString; 15 - use hexpm::version::ResolutionError; 16 16 use itertools::Itertools; 17 - use pubgrub::package::Package; 18 - use pubgrub::report::DerivationTree; 19 - use pubgrub::version::Version; 17 + use pubgrub::Package; 18 + use pubgrub::{DerivationTree, VersionSet}; 20 19 use std::borrow::Cow; 21 20 use std::collections::HashSet; 22 21 use std::fmt::{Debug, Display}; ··· 190 189 191 190 #[error("{input} is not a valid version. {error}")] 192 191 InvalidVersionFormat { input: String, error: String }, 192 + 193 + #[error("incompatible locked version. {error}")] 194 + IncompatibleLockedVersion { error: String }, 193 195 194 196 #[error("project root already exists")] 195 197 ProjectRootAlreadyExist { path: String }, ··· 431 433 Self::TarFinish(error.to_string()) 432 434 } 433 435 434 - pub fn dependency_resolution_failed(error: ResolutionError) -> Error { 435 - fn collect_conflicting_packages<'dt, P: Package, V: Version>( 436 - derivation_tree: &'dt DerivationTree<P, V>, 436 + pub fn dependency_resolution_failed<T: PackageFetcher>(error: ResolutionError<'_, T>) -> Error { 437 + fn collect_conflicting_packages< 438 + 'dt, 439 + P: Package, 440 + VS: VersionSet, 441 + M: Clone + Display + Debug + Eq, 442 + >( 443 + derivation_tree: &'dt DerivationTree<P, VS, M>, 437 444 conflicting_packages: &mut HashSet<&'dt P>, 438 445 ) { 439 446 match derivation_tree { 440 447 DerivationTree::External(external) => match external { 441 - pubgrub::report::External::NotRoot(package, _) => { 448 + pubgrub::External::NotRoot(package, _) => { 442 449 let _ = conflicting_packages.insert(package); 443 450 } 444 - pubgrub::report::External::NoVersions(package, _) => { 451 + pubgrub::External::NoVersions(package, _) => { 445 452 let _ = conflicting_packages.insert(package); 446 453 } 447 - pubgrub::report::External::UnavailableDependencies(package, _) => { 454 + pubgrub::External::Custom(package, _, _) => { 448 455 let _ = conflicting_packages.insert(package); 449 456 } 450 - pubgrub::report::External::FromDependencyOf(package, _, dep_package, _) => { 457 + pubgrub::External::FromDependencyOf(package, _, dep_package, _) => { 451 458 let _ = conflicting_packages.insert(package); 452 459 let _ = conflicting_packages.insert(dep_package); 453 460 } ··· 488 495 "An error occurred while trying to retrieve dependencies of {package}@{version}: {source}", 489 496 ), 490 497 491 - ResolutionError::DependencyOnTheEmptySet { 492 - package, 493 - version, 494 - dependent, 495 - } => format!("{package}@{version} has an impossible dependency on {dependent}",), 496 - 497 - ResolutionError::SelfDependency { package, version } => { 498 - format!("{package}@{version} somehow depends on itself.") 499 - } 500 - 501 - ResolutionError::ErrorChoosingPackageVersion(err) => { 502 - format!("Unable to determine package versions: {err}") 498 + ResolutionError::ErrorChoosingVersion { package, source } => { 499 + format!("An error occured while chosing the version of {package}: {source}",) 503 500 } 504 501 505 502 ResolutionError::ErrorInShouldCancel(err) => { 506 503 format!("Dependency resolution was cancelled. {err}") 507 - } 508 - 509 - ResolutionError::Failure(err) => { 510 - format!("An unrecoverable error happened while solving dependencies: {err}") 511 504 } 512 505 }) 513 506 } ··· 3958 3951 ); 3959 3952 vec![Diagnostic { 3960 3953 title: "Invalid version format".into(), 3954 + text, 3955 + hint: None, 3956 + location: None, 3957 + level: Level::Error, 3958 + }] 3959 + } 3960 + 3961 + Error::IncompatibleLockedVersion { error } => { 3962 + let text = format!( 3963 + "There is an incompatiblity between a version specified in 3964 + manifest.toml and a version range specified in gleam.toml: 3965 + 3966 + {error}" 3967 + ); 3968 + vec![Diagnostic { 3969 + title: "Incompatible locked version".into(), 3961 3970 text, 3962 3971 hint: None, 3963 3972 location: None,
+1 -1
compiler-core/src/javascript/tests/bit_arrays.rs
··· 1 1 use hexpm::version::Version; 2 - use pubgrub::range::Range; 2 + use pubgrub::Range; 3 3 4 4 use crate::{ 5 5 assert_js, assert_js_no_warnings_with_gleam_version, assert_js_warnings_with_gleam_version,
+2 -2
compiler-core/src/language_server/tests.rs
··· 311 311 package.name.clone(), 312 312 match package.source { 313 313 ManifestPackageSource::Hex { .. } => Requirement::Hex { 314 - version: Range::new("1.0.0".into()), 314 + version: Range::new("1.0.0".into()).unwrap(), 315 315 }, 316 316 ManifestPackageSource::Local { ref path } => Requirement::Path { path: path.into() }, 317 317 ManifestPackageSource::Git { ··· 336 336 package.name.clone(), 337 337 match package.source { 338 338 ManifestPackageSource::Hex { .. } => Requirement::Hex { 339 - version: Range::new("1.0.0".into()), 339 + version: Range::new("1.0.0".into()).unwrap(), 340 340 }, 341 341 ManifestPackageSource::Local { ref path } => Requirement::Path { path: path.into() }, 342 342 ManifestPackageSource::Git {
+8 -8
compiler-core/src/manifest.rs
··· 232 232 fn manifest_toml_format() { 233 233 let manifest = Manifest { 234 234 requirements: [ 235 - ("zzz".into(), Requirement::hex("> 0.0.0")), 236 - ("aaa".into(), Requirement::hex("> 0.0.0")), 235 + ("zzz".into(), Requirement::hex("> 0.0.0").unwrap()), 236 + ("aaa".into(), Requirement::hex("> 0.0.0").unwrap()), 237 237 ( 238 238 "awsome_local2".into(), 239 239 Requirement::git("https://github.com/gleam-lang/gleam.git", "bd9fe02f"), ··· 242 242 "awsome_local1".into(), 243 243 Requirement::path("../path/to/package"), 244 244 ), 245 - ("gleam_stdlib".into(), Requirement::hex("~> 0.17")), 246 - ("gleeunit".into(), Requirement::hex("~> 0.1")), 245 + ("gleam_stdlib".into(), Requirement::hex("~> 0.17").unwrap()), 246 + ("gleeunit".into(), Requirement::hex("~> 0.1").unwrap()), 247 247 ] 248 248 .into(), 249 249 packages: vec![ ··· 342 342 fn manifest_toml_format_with_unc() { 343 343 let manifest = Manifest { 344 344 requirements: [ 345 - ("zzz".into(), Requirement::hex("> 0.0.0")), 346 - ("aaa".into(), Requirement::hex("> 0.0.0")), 345 + ("zzz".into(), Requirement::hex("> 0.0.0").unwrap()), 346 + ("aaa".into(), Requirement::hex("> 0.0.0").unwrap()), 347 347 ( 348 348 "awsome_local2".into(), 349 349 Requirement::git("https://github.com/gleam-lang/gleam.git", "main"), ··· 352 352 "awsome_local1".into(), 353 353 Requirement::path("../path/to/package"), 354 354 ), 355 - ("gleam_stdlib".into(), Requirement::hex("~> 0.17")), 356 - ("gleeunit".into(), Requirement::hex("~> 0.1")), 355 + ("gleam_stdlib".into(), Requirement::hex("~> 0.17").unwrap()), 356 + ("gleeunit".into(), Requirement::hex("~> 0.1").unwrap()), 357 357 ] 358 358 .into(), 359 359 packages: vec![
+13 -9
compiler-core/src/requirement.rs
··· 1 1 use std::fmt; 2 2 use std::str::FromStr; 3 3 4 + use crate::Error; 4 5 use crate::error::Result; 5 6 use crate::io::make_relative; 6 7 use camino::{Utf8Path, Utf8PathBuf}; ··· 29 30 } 30 31 31 32 impl Requirement { 32 - pub fn hex(range: &str) -> Requirement { 33 - Requirement::Hex { 34 - version: Range::new(range.to_string()), 35 - } 33 + pub fn hex(range: &str) -> Result<Requirement> { 34 + Ok(Requirement::Hex { 35 + version: Range::new(range.to_string()).map_err(|e| Error::InvalidVersionFormat { 36 + input: range.to_string(), 37 + error: e.to_string(), 38 + })?, 39 + }) 36 40 } 37 41 38 42 pub fn path(path: &str) -> Requirement { ··· 91 95 D: Deserializer<'de>, 92 96 { 93 97 let version = String::deserialize(deserializer)?; 94 - Ok(Range::new(version)) 98 + Range::new(version).map_err(de::Error::custom) 95 99 } 96 100 97 101 #[derive(Debug, Copy, Clone)] 98 102 pub struct Void; 99 103 100 104 impl FromStr for Requirement { 101 - type Err = Void; 105 + type Err = Error; 102 106 103 107 fn from_str(s: &str) -> Result<Self, Self::Err> { 104 - Ok(Requirement::hex(s)) 108 + Requirement::hex(s) 105 109 } 106 110 } 107 111 ··· 153 157 github = { git = "https://github.com/gleam-lang/otp.git", ref = "4d34935" } 154 158 "#; 155 159 let deps: HashMap<String, Requirement> = toml::from_str(toml).unwrap(); 156 - assert_eq!(deps["short"], Requirement::hex("~> 0.5")); 157 - assert_eq!(deps["hex"], Requirement::hex("~> 1.0.0")); 160 + assert_eq!(deps["short"], Requirement::hex("~> 0.5").unwrap()); 161 + assert_eq!(deps["hex"], Requirement::hex("~> 1.0.0").unwrap()); 158 162 assert_eq!(deps["local"], Requirement::path("/path/to/package")); 159 163 assert_eq!( 160 164 deps["github"],
+1 -1
compiler-core/src/type_/environment.rs
··· 1 - use pubgrub::range::Range; 1 + use pubgrub::Range; 2 2 3 3 use crate::{ 4 4 analyse::TargetSupport,
+1 -1
compiler-core/src/type_/expression.rs
··· 18 18 parse::PatternPosition, 19 19 reference::ReferenceKind, 20 20 }; 21 - use hexpm::version::Version; 21 + use hexpm::version::{LowestVersion, Version}; 22 22 use im::hashmap; 23 23 use itertools::Itertools; 24 24 use num_bigint::BigInt;
+1 -1
compiler-core/src/type_/pattern.rs
··· 1 - use hexpm::version::Version; 1 + use hexpm::version::{LowestVersion, Version}; 2 2 use im::hashmap; 3 3 use itertools::Itertools; 4 4 use num_bigint::BigInt;
+1 -1
compiler-core/src/type_/tests.rs
··· 11 11 }; 12 12 use ecow::EcoString; 13 13 use itertools::Itertools; 14 - use pubgrub::range::Range; 14 + use pubgrub::Range; 15 15 use std::rc::Rc; 16 16 use vec1::Vec1; 17 17