@@ -1853,13 +1853,7 @@ fn load_toml_config(
18531853 } else {
18541854 toml_path. clone ( )
18551855 } ) ;
1856- (
1857- get_toml ( & toml_path) . unwrap_or_else ( |e| {
1858- eprintln ! ( "ERROR: Failed to parse '{}': {e}" , toml_path. display( ) ) ;
1859- exit ! ( 2 ) ;
1860- } ) ,
1861- path,
1862- )
1856+ ( get_toml ( & toml_path) . unwrap_or_else ( |e| bad_config ( & toml_path, e) ) , path)
18631857 } else {
18641858 ( TomlConfig :: default ( ) , None )
18651859 }
@@ -1892,10 +1886,8 @@ fn postprocess_toml(
18921886 . unwrap ( )
18931887 . join ( include_path) ;
18941888
1895- let included_toml = get_toml ( & include_path) . unwrap_or_else ( |e| {
1896- eprintln ! ( "ERROR: Failed to parse '{}': {e}" , include_path. display( ) ) ;
1897- exit ! ( 2 ) ;
1898- } ) ;
1889+ let included_toml =
1890+ get_toml ( & include_path) . unwrap_or_else ( |e| bad_config ( & include_path, e) ) ;
18991891 toml. merge (
19001892 Some ( include_path) ,
19011893 & mut Default :: default ( ) ,
@@ -2398,3 +2390,54 @@ pub(crate) fn read_file_by_commit<'a>(
23982390 git. arg ( "show" ) . arg ( format ! ( "{commit}:{}" , file. to_str( ) . unwrap( ) ) ) ;
23992391 git. run_capture_stdout ( dwn_ctx. exec_ctx ) . stdout ( )
24002392}
2393+
2394+ fn bad_config ( toml_path : & Path , e : toml:: de:: Error ) -> ! {
2395+ eprintln ! ( "ERROR: Failed to parse '{}': {e}" , toml_path. display( ) ) ;
2396+ let e_s = e. to_string ( ) ;
2397+ if e_s. contains ( "unknown field" )
2398+ && let Some ( field_name) = e_s. split ( "`" ) . nth ( 1 )
2399+ && let sections = find_correct_section_for_field ( field_name)
2400+ && !sections. is_empty ( )
2401+ {
2402+ if sections. len ( ) == 1 {
2403+ let section = sections[ 0 ] ;
2404+ if section == "<nesting error>" {
2405+ eprintln ! ( "hint: section name `{field_name}` used as a key within a section" ) ;
2406+ } else if section == "<top level>" {
2407+ eprintln ! ( "hint: try using `{field_name}` as a top level key" ) ;
2408+ } else {
2409+ eprintln ! ( "hint: try moving `{field_name}` to the `{section}` section" ) ;
2410+ }
2411+ } else {
2412+ eprintln ! (
2413+ "hint: try moving `{field_name}` to one of the following sections: {sections:?}"
2414+ ) ;
2415+ }
2416+ }
2417+
2418+ exit ! ( 2 ) ;
2419+ }
2420+
2421+ fn find_correct_section_for_field ( field_name : & str ) -> Vec < & ' static str > {
2422+ let sections = [ "<top level>" , "build" , "install" , "llvm" , "gcc" , "rust" , "dist" ] ;
2423+ if sections. contains ( & field_name) {
2424+ return vec ! [ "<nesting error>" ] ;
2425+ }
2426+ sections
2427+ . iter ( )
2428+ . enumerate ( )
2429+ . filter_map ( |( i, section_name) | {
2430+ let dummy_config_str = if i == 0 {
2431+ format ! ( "{field_name} = 0\n " )
2432+ } else {
2433+ format ! ( "{section_name}.{field_name} = 0\n " )
2434+ } ;
2435+ let is_unknown_field = toml:: from_str :: < toml:: Value > ( & dummy_config_str)
2436+ . and_then ( TomlConfig :: deserialize)
2437+ . err ( )
2438+ . is_some_and ( |e| e. to_string ( ) . contains ( "unknown field" ) ) ;
2439+ if is_unknown_field { None } else { Some ( section_name) }
2440+ } )
2441+ . copied ( )
2442+ . collect ( )
2443+ }
0 commit comments