@@ -11,6 +11,7 @@ use std::str::FromStr;
11
11
12
12
use anyhow:: Context as _;
13
13
use cargo_util:: paths;
14
+ use cargo_util_schemas:: core:: PartialVersion ;
14
15
use cargo_util_schemas:: manifest:: RustVersion ;
15
16
use indexmap:: IndexSet ;
16
17
use itertools:: Itertools ;
@@ -615,52 +616,74 @@ fn get_latest_dependency(
615
616
} ) ?;
616
617
617
618
if gctx. cli_unstable ( ) . msrv_policy && honor_rust_version {
618
- fn parse_msrv ( comp : & RustVersion ) -> ( u64 , u64 , u64 ) {
619
- ( comp. major , comp. minor . unwrap_or ( 0 ) , comp. patch . unwrap_or ( 0 ) )
620
- }
619
+ let ( req_msrv, is_msrv) = spec
620
+ . rust_version ( )
621
+ . cloned ( )
622
+ . map ( |msrv| CargoResult :: Ok ( ( msrv. clone ( ) , true ) ) )
623
+ . unwrap_or_else ( || {
624
+ let rustc = gctx. load_global_rustc ( None ) ?;
625
+
626
+ // Remove any pre-release identifiers for easier comparison
627
+ let current_version = & rustc. version ;
628
+ let untagged_version = RustVersion :: try_from ( PartialVersion {
629
+ major : current_version. major ,
630
+ minor : Some ( current_version. minor ) ,
631
+ patch : Some ( current_version. patch ) ,
632
+ pre : None ,
633
+ build : None ,
634
+ } )
635
+ . unwrap ( ) ;
636
+ Ok ( ( untagged_version, false ) )
637
+ } ) ?;
621
638
622
- if let Some ( req_msrv) = spec. rust_version ( ) . map ( parse_msrv) {
623
- let msrvs = possibilities
624
- . iter ( )
625
- . map ( |s| ( s, s. rust_version ( ) . map ( parse_msrv) ) )
626
- . collect :: < Vec < _ > > ( ) ;
627
-
628
- // Find the latest version of the dep which has a compatible rust-version. To
629
- // determine whether or not one rust-version is compatible with another, we
630
- // compare the lowest possible versions they could represent, and treat
631
- // candidates without a rust-version as compatible by default.
632
- let ( latest_msrv, _) = msrvs
633
- . iter ( )
634
- . filter ( |( _, v) | v. map ( |msrv| req_msrv >= msrv) . unwrap_or ( true ) )
635
- . last ( )
636
- . ok_or_else ( || {
637
- // Failing that, try to find the highest version with the lowest
638
- // rust-version to report to the user.
639
- let lowest_candidate = msrvs
640
- . iter ( )
641
- . min_set_by_key ( |( _, v) | v)
642
- . iter ( )
643
- . map ( |( s, _) | s)
644
- . max_by_key ( |s| s. version ( ) ) ;
645
- rust_version_incompat_error (
646
- & dependency. name ,
647
- spec. rust_version ( ) . unwrap ( ) ,
648
- lowest_candidate. copied ( ) ,
639
+ let msrvs = possibilities
640
+ . iter ( )
641
+ . map ( |s| ( s, s. rust_version ( ) ) )
642
+ . collect :: < Vec < _ > > ( ) ;
643
+
644
+ // Find the latest version of the dep which has a compatible rust-version. To
645
+ // determine whether or not one rust-version is compatible with another, we
646
+ // compare the lowest possible versions they could represent, and treat
647
+ // candidates without a rust-version as compatible by default.
648
+ let latest_msrv = latest_compatible ( & msrvs, & req_msrv) . ok_or_else ( || {
649
+ let name = spec. name ( ) ;
650
+ let dep_name = & dependency. name ;
651
+ let latest_version = latest. version ( ) ;
652
+ let latest_msrv = latest
653
+ . rust_version ( )
654
+ . expect ( "as `None` are compatible, we can't be here" ) ;
655
+ if is_msrv {
656
+ anyhow:: format_err!(
657
+ "\
658
+ no version of crate `{dep_name}` can maintain {name}'s rust-version of {req_msrv}
659
+ help: pass `--ignore-rust-version` to select {dep_name}@{latest_version} which requires rustc {latest_msrv}"
649
660
)
650
- } ) ?;
651
-
652
- if latest_msrv. version ( ) < latest. version ( ) {
661
+ } else {
662
+ anyhow:: format_err!(
663
+ "\
664
+ no version of crate `{dep_name}` is compatible with rustc {req_msrv}
665
+ help: pass `--ignore-rust-version` to select {dep_name}@{latest_version} which requires rustc {latest_msrv}"
666
+ )
667
+ }
668
+ } ) ?;
669
+
670
+ if latest_msrv. version ( ) < latest. version ( ) {
671
+ let latest_version = latest. version ( ) ;
672
+ let latest_rust_version = latest. rust_version ( ) . unwrap ( ) ;
673
+ let name = spec. name ( ) ;
674
+ if is_msrv {
653
675
gctx. shell ( ) . warn ( format_args ! (
654
- "ignoring `{dependency}@{latest_version}` (which has a rust-version of \
655
- {latest_rust_version}) to satisfy this package's rust-version of \
656
- {rust_version} (use `--ignore-rust-version` to override)",
657
- latest_version = latest. version( ) ,
658
- latest_rust_version = latest. rust_version( ) . unwrap( ) ,
659
- rust_version = spec. rust_version( ) . unwrap( ) ,
676
+ "\
677
+ ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_version}) to maintain {name}'s rust-version of {req_msrv}",
678
+ ) ) ?;
679
+ } else {
680
+ gctx. shell ( ) . warn ( format_args ! (
681
+ "\
682
+ ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_version}) as it is incompatible with rustc {req_msrv}",
660
683
) ) ?;
661
-
662
- latest = latest_msrv;
663
684
}
685
+
686
+ latest = latest_msrv;
664
687
}
665
688
}
666
689
@@ -673,29 +696,20 @@ fn get_latest_dependency(
673
696
}
674
697
}
675
698
676
- fn rust_version_incompat_error (
677
- dep : & str ,
678
- rust_version : & RustVersion ,
679
- lowest_rust_version : Option < & Summary > ,
680
- ) -> anyhow:: Error {
681
- let mut error_msg = format ! (
682
- "could not find version of crate `{dep}` that satisfies this package's rust-version of \
683
- {rust_version}\n \
684
- help: use `--ignore-rust-version` to override this behavior"
685
- ) ;
686
-
687
- if let Some ( lowest) = lowest_rust_version {
688
- // rust-version must be present for this candidate since it would have been selected as
689
- // compatible previously if it weren't.
690
- let version = lowest. version ( ) ;
691
- let rust_version = lowest. rust_version ( ) . unwrap ( ) ;
692
- error_msg. push_str ( & format ! (
693
- "\n note: the lowest rust-version available for `{dep}` is {rust_version}, used in \
694
- version {version}"
695
- ) ) ;
696
- }
697
-
698
- anyhow:: format_err!( error_msg)
699
+ /// Of MSRV-compatible summaries, find the highest version
700
+ ///
701
+ /// Assumptions:
702
+ /// - `msrvs` is sorted by version
703
+ fn latest_compatible < ' s > (
704
+ msrvs : & [ ( & ' s Summary , Option < & RustVersion > ) ] ,
705
+ req_msrv : & RustVersion ,
706
+ ) -> Option < & ' s Summary > {
707
+ msrvs
708
+ . iter ( )
709
+ . filter ( |( _, v) | v. as_ref ( ) . map ( |msrv| req_msrv >= * msrv) . unwrap_or ( true ) )
710
+ . map ( |( s, _) | s)
711
+ . last ( )
712
+ . copied ( )
699
713
}
700
714
701
715
fn select_package (
0 commit comments