@@ -218,42 +218,53 @@ macro_rules! define_Conf {
218218 let mut value_spans = HashMap :: new( ) ;
219219 let mut errors = Vec :: new( ) ;
220220 let mut warnings = Vec :: new( ) ;
221+
222+ // Declare a local variable for each field field available to a configuration file.
221223 $( let mut $name = None ; ) *
224+
222225 // could get `Field` here directly, but get `String` first for diagnostics
223226 while let Some ( name) = map. next_key:: <toml:: Spanned <String >>( ) ? {
224- match Field :: deserialize( name. get_ref( ) . as_str( ) . into_deserializer( ) ) {
227+ let field = match Field :: deserialize( name. get_ref( ) . as_str( ) . into_deserializer( ) ) {
225228 Err ( e) => {
226229 let e: FieldError = e;
227230 errors. push( ConfError :: spanned( self . 0 , e. error, e. suggestion, name. span( ) ) ) ;
231+ continue ;
228232 }
229- $( Ok ( Field :: $name) => {
233+ Ok ( field) => field
234+ } ;
235+
236+ match field {
237+ $( Field :: $name => {
238+ // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning.
230239 $( warnings. push( ConfError :: spanned( self . 0 , format!( "deprecated field `{}`. {}" , name. get_ref( ) , $dep) , None , name. span( ) ) ) ; ) ?
231240 let raw_value = map. next_value:: <toml:: Spanned <toml:: Value >>( ) ?;
232241 let value_span = raw_value. span( ) ;
233- match <$ty>:: deserialize( raw_value. into_inner( ) ) {
234- Err ( e) => errors. push( ConfError :: spanned( self . 0 , e. to_string( ) . replace( '\n' , " " ) . trim( ) , None , value_span) ) ,
235- Ok ( value) => match $name {
236- Some ( _) => {
237- errors. push( ConfError :: spanned( self . 0 , format!( "duplicate field `{}`" , name. get_ref( ) ) , None , name. span( ) ) ) ;
238- }
239- None => {
240- $name = Some ( value) ;
241- value_spans. insert( name. get_ref( ) . as_str( ) . to_string( ) , value_span) ;
242- // $new_conf is the same as one of the defined `$name`s, so
243- // this variable is defined in line 2 of this function.
244- $( match $new_conf {
245- Some ( _) => errors. push( ConfError :: spanned( self . 0 , concat!(
246- "duplicate field `" , stringify!( $new_conf) ,
247- "` (provided as `" , stringify!( $name) , "`)"
248- ) , None , name. span( ) ) ) ,
249- None => $new_conf = $name. clone( ) ,
250- } ) ?
251- } ,
242+ let value = match <$ty>:: deserialize( raw_value. into_inner( ) ) {
243+ Err ( e) => {
244+ errors. push( ConfError :: spanned( self . 0 , e. to_string( ) . replace( '\n' , " " ) . trim( ) , None , value_span) ) ;
245+ continue ;
252246 }
247+ Ok ( value) => value
248+ } ;
249+ // Was this field set previously?
250+ if $name. is_some( ) {
251+ errors. push( ConfError :: spanned( self . 0 , format!( "duplicate field `{}`" , name. get_ref( ) ) , None , name. span( ) ) ) ;
252+ continue ;
253253 }
254+ $name = Some ( value) ;
255+ value_spans. insert( name. get_ref( ) . as_str( ) . to_string( ) , value_span) ;
256+ // If this is a deprecated field, was the new field (`$new_conf`) set previously?
257+ // Note that `$new_conf` is one of the defined `$name`s.
258+ $( match $new_conf {
259+ Some ( _) => errors. push( ConfError :: spanned( self . 0 , concat!(
260+ "duplicate field `" , stringify!( $new_conf) ,
261+ "` (provided as `" , stringify!( $name) , "`)"
262+ ) , None , name. span( ) ) ) ,
263+ None => $new_conf = $name. clone( ) ,
264+ } ) ?
254265 } ) *
255266 // ignore contents of the third_party key
256- Ok ( Field :: third_party) => drop( map. next_value:: <IgnoredAny >( ) )
267+ Field :: third_party => drop( map. next_value:: <IgnoredAny >( ) )
257268 }
258269 }
259270 let conf = Conf { $( $name: $name. unwrap_or_else( defaults:: $name) , ) * } ;
0 commit comments