@@ -1363,12 +1363,12 @@ impl<'gctx> Workspace<'gctx> {
1363
1363
}
1364
1364
}
1365
1365
1366
- fn report_unknown_features_error (
1366
+ fn missing_feature_spelling_suggestions (
1367
1367
& self ,
1368
- specs : & [ PackageIdSpec ] ,
1368
+ selected_members : & [ & Package ] ,
1369
1369
cli_features : & CliFeatures ,
1370
1370
found_features : & BTreeSet < FeatureValue > ,
1371
- ) -> CargoResult < ( ) > {
1371
+ ) -> Vec < String > {
1372
1372
// Keeps track of which features were contained in summary of `member` to suggest similar features in errors
1373
1373
let mut summary_features: Vec < InternedString > = Default :: default ( ) ;
1374
1374
@@ -1387,10 +1387,7 @@ impl<'gctx> Workspace<'gctx> {
1387
1387
let mut optional_dependency_names_per_member: BTreeMap < & Package , BTreeSet < InternedString > > =
1388
1388
Default :: default ( ) ;
1389
1389
1390
- for member in self
1391
- . members ( )
1392
- . filter ( |m| specs. iter ( ) . any ( |spec| spec. matches ( m. package_id ( ) ) ) )
1393
- {
1390
+ for & member in selected_members {
1394
1391
// Only include features this member defines.
1395
1392
let summary = member. summary ( ) ;
1396
1393
@@ -1428,7 +1425,7 @@ impl<'gctx> Workspace<'gctx> {
1428
1425
edit_distance ( a. as_str ( ) , b. as_str ( ) , 3 ) . is_some ( )
1429
1426
} ;
1430
1427
1431
- let suggestions : Vec < _ > = cli_features
1428
+ cli_features
1432
1429
. features
1433
1430
. difference ( found_features)
1434
1431
. map ( |feature| match feature {
@@ -1522,27 +1519,86 @@ impl<'gctx> Workspace<'gctx> {
1522
1519
} )
1523
1520
. sorted ( )
1524
1521
. take ( 5 )
1525
- . collect ( ) ;
1522
+ . collect ( )
1523
+ }
1526
1524
1525
+ fn report_unknown_features_error (
1526
+ & self ,
1527
+ specs : & [ PackageIdSpec ] ,
1528
+ cli_features : & CliFeatures ,
1529
+ found_features : & BTreeSet < FeatureValue > ,
1530
+ ) -> CargoResult < ( ) > {
1527
1531
let unknown: Vec < _ > = cli_features
1528
1532
. features
1529
1533
. difference ( found_features)
1530
1534
. map ( |feature| feature. to_string ( ) )
1531
1535
. sorted ( )
1532
1536
. collect ( ) ;
1533
1537
1534
- if suggestions. is_empty ( ) {
1535
- bail ! (
1536
- "none of the selected packages contains these features: {}" ,
1538
+ let ( selected_members, unselected_members) : ( Vec < _ > , Vec < _ > ) = self
1539
+ . members ( )
1540
+ . partition ( |member| specs. iter ( ) . any ( |spec| spec. matches ( member. package_id ( ) ) ) ) ;
1541
+
1542
+ let missing_packages_with_the_features = unselected_members
1543
+ . into_iter ( )
1544
+ . filter ( |member| {
1545
+ unknown
1546
+ . iter ( )
1547
+ . any ( |feature| member. summary ( ) . features ( ) . contains_key ( & * * feature) )
1548
+ } )
1549
+ . map ( |m| m. name ( ) )
1550
+ . collect_vec ( ) ;
1551
+
1552
+ let these_features = if unknown. len ( ) == 1 {
1553
+ "this feature"
1554
+ } else {
1555
+ "these features"
1556
+ } ;
1557
+ let mut msg = if let [ singular] = & selected_members[ ..] {
1558
+ format ! (
1559
+ "the package '{}' does not contain {these_features}: {}" ,
1560
+ singular. name( ) ,
1537
1561
unknown. join( ", " )
1538
- ) ;
1562
+ )
1539
1563
} else {
1540
- bail ! (
1541
- "none of the selected packages contains these features: {}, did you mean: {}?" ,
1542
- unknown. join( ", " ) ,
1543
- suggestions. join( ", " )
1564
+ let names = selected_members. iter ( ) . map ( |m| m. name ( ) ) . join ( ", " ) ;
1565
+ format ! ( "none of the selected packages contains {these_features}: {}\n selected packages: {names}" , unknown. join( ", " ) )
1566
+ } ;
1567
+
1568
+ use std:: fmt:: Write ;
1569
+ if !missing_packages_with_the_features. is_empty ( ) {
1570
+ write ! (
1571
+ & mut msg,
1572
+ "\n help: package{} with the missing feature{}: {}" ,
1573
+ if missing_packages_with_the_features. len( ) != 1 {
1574
+ "s"
1575
+ } else {
1576
+ ""
1577
+ } ,
1578
+ if unknown. len( ) != 1 { "s" } else { "" } ,
1579
+ missing_packages_with_the_features. join( ", " )
1580
+ ) ?;
1581
+ } else {
1582
+ let suggestions = self . missing_feature_spelling_suggestions (
1583
+ & selected_members,
1584
+ cli_features,
1585
+ found_features,
1544
1586
) ;
1587
+ if !suggestions. is_empty ( ) {
1588
+ write ! (
1589
+ & mut msg,
1590
+ "\n help: there {}: {}" ,
1591
+ if suggestions. len( ) == 1 {
1592
+ "is a similarly named feature"
1593
+ } else {
1594
+ "are similarly named features"
1595
+ } ,
1596
+ suggestions. join( ", " )
1597
+ ) ?;
1598
+ }
1545
1599
}
1600
+
1601
+ bail ! ( "{msg}" )
1546
1602
}
1547
1603
1548
1604
/// New command-line feature selection behavior with resolver = "2" or the
0 commit comments