@@ -15,6 +15,7 @@ use cargo_util_schemas::manifest::{RustVersion, StringOrBool};
1515use  itertools:: Itertools ; 
1616use  lazycell:: LazyCell ; 
1717use  pathdiff:: diff_paths; 
18+ use  toml_edit:: ImDocument ; 
1819use  url:: Url ; 
1920
2021use  crate :: core:: compiler:: { CompileKind ,  CompileTarget } ; 
@@ -29,6 +30,7 @@ use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, Worksp
2930use  crate :: sources:: { CRATES_IO_INDEX ,  CRATES_IO_REGISTRY } ; 
3031use  crate :: util:: errors:: { CargoResult ,  ManifestError } ; 
3132use  crate :: util:: interning:: InternedString ; 
33+ use  crate :: util:: lints:: { get_span,  rel_cwd_manifest_path} ; 
3234use  crate :: util:: { self ,  context:: ConfigRelativePath ,  GlobalContext ,  IntoUrl ,  OptVersionReq } ; 
3335
3436mod  embedded; 
@@ -1459,7 +1461,14 @@ fn to_real_manifest(
14591461        // need to check whether `dep_name` is stripped as unused dependency 
14601462        if  let  Err ( ref  err)  = summary { 
14611463            if  let  Some ( missing_dep)  = err. downcast_ref :: < MissingDependencyError > ( )  { 
1462-                 check_weak_optional_dep_unused ( & original_toml,  missing_dep) ?; 
1464+                 missing_dep_diagnostic ( 
1465+                     missing_dep, 
1466+                     & original_toml, 
1467+                     & document, 
1468+                     & contents, 
1469+                     manifest_file, 
1470+                     gctx, 
1471+                 ) ?; 
14631472            } 
14641473        } 
14651474        summary?
@@ -1570,37 +1579,83 @@ fn to_real_manifest(
15701579    Ok ( manifest) 
15711580} 
15721581
1573- fn  check_weak_optional_dep_unused ( 
1574-     original_toml :  & TomlManifest , 
1582+ fn  missing_dep_diagnostic ( 
15751583    missing_dep :  & MissingDependencyError , 
1584+     orig_toml :  & TomlManifest , 
1585+     document :  & ImDocument < String > , 
1586+     contents :  & str , 
1587+     manifest_file :  & Path , 
1588+     gctx :  & GlobalContext , 
15761589)  -> CargoResult < ( ) >  { 
1577-     if  missing_dep. weak_optional  { 
1578-         // dev-dependencies are not allowed to be optional 
1590+     let  dep_name = missing_dep. dep_name ; 
1591+     let  manifest_path = rel_cwd_manifest_path ( manifest_file,  gctx) ; 
1592+     let  feature_value_span =
1593+         get_span ( & document,  & [ "features" ,  missing_dep. feature . as_str ( ) ] ,  true ) . unwrap ( ) ; 
1594+ 
1595+     let  title = format ! ( 
1596+         "feature `{}` includes `{}`, but `{}` is not a dependency" , 
1597+         missing_dep. feature,  missing_dep. feature_value,  & dep_name
1598+     ) ; 
1599+     let  help = format ! ( "enable the dependency with `dep:{dep_name}`" ) ; 
1600+     let  info_label = format ! ( 
1601+         "`{}` is an unused optional dependency since no feature enables it" , 
1602+         & dep_name
1603+     ) ; 
1604+     let  message = Level :: Error . title ( & title) ; 
1605+     let  snippet = Snippet :: source ( & contents) 
1606+         . origin ( & manifest_path) 
1607+         . fold ( true ) 
1608+         . annotation ( Level :: Error . span ( feature_value_span. start ..feature_value_span. end ) ) ; 
1609+     let  message = if  missing_dep. weak_optional  { 
15791610        let  mut  orig_deps = vec ! [ 
1580-             original_toml. dependencies. as_ref( ) , 
1581-             original_toml. build_dependencies. as_ref( ) , 
1611+             ( 
1612+                 orig_toml. dependencies. as_ref( ) , 
1613+                 vec![ DepKind :: Normal . kind_table( ) ] , 
1614+             ) , 
1615+             ( 
1616+                 orig_toml. build_dependencies. as_ref( ) , 
1617+                 vec![ DepKind :: Build . kind_table( ) ] , 
1618+             ) , 
15821619        ] ; 
1583-         for  ( _ ,  platform)  in  original_toml . target . iter ( ) . flatten ( )  { 
1584-             orig_deps. extend ( vec ! [ 
1620+         for  ( name ,  platform)  in  orig_toml . target . iter ( ) . flatten ( )  { 
1621+             orig_deps. push ( ( 
15851622                platform. dependencies . as_ref ( ) , 
1623+                 vec ! [ "target" ,  name,  DepKind :: Normal . kind_table( ) ] , 
1624+             ) ) ; 
1625+             orig_deps. push ( ( 
15861626                platform. build_dependencies . as_ref ( ) , 
1587-             ] ) ; 
1627+                 vec ! [ "target" ,  name,  DepKind :: Normal . kind_table( ) ] , 
1628+             ) ) ; 
15881629        } 
1589-         for  deps in  orig_deps { 
1630+ 
1631+         if  let  Some ( ( _,  toml_path) )  = orig_deps. iter ( ) . find ( |( deps,  _) | { 
15901632            if  let  Some ( deps)  = deps { 
1591-                 if  deps. keys ( ) . any ( |p| * p. as_str ( )  == * missing_dep. dep_name )  { 
1592-                     bail ! ( 
1593-                             "feature `{feature}` includes `{feature_value}`, but missing `dep:{dep_name}` to activate it" , 
1594-                             feature = missing_dep. feature, 
1595-                             feature_value = missing_dep. feature_value, 
1596-                             dep_name = missing_dep. dep_name, 
1597-                         ) 
1598-                 } 
1633+                 deps. keys ( ) . any ( |p| * p. as_str ( )  == * dep_name) 
1634+             }  else  { 
1635+                 false 
15991636            } 
1637+         } )  { 
1638+             let  toml_path = toml_path
1639+                 . iter ( ) 
1640+                 . map ( |s| * s) 
1641+                 . chain ( std:: iter:: once ( dep_name. as_str ( ) ) ) 
1642+                 . collect :: < Vec < _ > > ( ) ; 
1643+             let  dep_span = get_span ( & document,  & toml_path,  false ) . unwrap ( ) ; 
1644+ 
1645+             message
1646+                 . snippet ( snippet. annotation ( Level :: Warning . span ( dep_span) . label ( & info_label) ) ) 
1647+                 . footer ( Level :: Help . title ( & help) ) 
1648+         }  else  { 
1649+             message. snippet ( snippet) 
16001650        } 
1601-     } 
1651+     }  else  { 
1652+         message. snippet ( snippet) 
1653+     } ; 
16021654
1603-     Ok ( ( ) ) 
1655+     if  let  Err ( err)  = gctx. shell ( ) . print_message ( message)  { 
1656+         return  Err ( err. into ( ) ) ; 
1657+     } 
1658+     Err ( AlreadyPrintedError :: new ( anyhow ! ( "" ) . into ( ) ) . into ( ) ) 
16041659} 
16051660
16061661fn  to_virtual_manifest ( 
0 commit comments