@@ -11,6 +11,7 @@ use std::str::FromStr;
1111
1212use anyhow:: Context as _;
1313use cargo_util:: paths;
14+ use cargo_util_schemas:: core:: PartialVersion ;
1415use cargo_util_schemas:: manifest:: RustVersion ;
1516use indexmap:: IndexSet ;
1617use itertools:: Itertools ;
@@ -615,52 +616,74 @@ fn get_latest_dependency(
615616 } ) ?;
616617
617618 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+ } ) ?;
621638
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}"
649660 )
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 {
653675 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}",
660683 ) ) ?;
661-
662- latest = latest_msrv;
663684 }
685+
686+ latest = latest_msrv;
664687 }
665688 }
666689
@@ -673,29 +696,20 @@ fn get_latest_dependency(
673696 }
674697}
675698
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 ( )
699713}
700714
701715fn select_package (
0 commit comments