33use proc_macro2:: { Span , TokenStream } ;
44use quote:: { format_ident, quote} ;
55use syn:: {
6- braced,
6+ braced, parenthesized ,
77 parse:: { End , Parse } ,
88 parse_quote,
99 punctuated:: Punctuated ,
1010 spanned:: Spanned ,
11- token, Attribute , Block , Expr , ExprCall , ExprPath , Ident , Path , Token , Type ,
11+ token, Attribute , Block , Expr , ExprCall , ExprPath , Ident , Index , LitInt , Member , Path , Token ,
12+ Type ,
1213} ;
1314
1415use crate :: diagnostics:: { DiagCtxt , ErrorGuaranteed } ;
@@ -17,7 +18,7 @@ pub(crate) struct Initializer {
1718 attrs : Vec < InitializerAttribute > ,
1819 this : Option < This > ,
1920 path : Path ,
20- brace_token : token :: Brace ,
21+ close_span : Span ,
2122 fields : Punctuated < InitializerField , Token ! [ , ] > ,
2223 rest : Option < ( Token ! [ ..] , Expr ) > ,
2324 error : Option < ( Token ! [ ?] , Type ) > ,
@@ -34,13 +35,18 @@ struct InitializerField {
3435 kind : InitializerKind ,
3536}
3637
38+ struct TupleInitializerField {
39+ attrs : Vec < Attribute > ,
40+ value : Expr ,
41+ }
42+
3743enum InitializerKind {
3844 Value {
39- ident : Ident ,
45+ member : Member ,
4046 value : Option < ( Token ! [ : ] , Expr ) > ,
4147 } ,
4248 Init {
43- ident : Ident ,
49+ member : Member ,
4450 _left_arrow_token : Token ! [ <-] ,
4551 value : Expr ,
4652 } ,
@@ -52,14 +58,28 @@ enum InitializerKind {
5258}
5359
5460impl InitializerKind {
55- fn ident ( & self ) -> Option < & Ident > {
61+ fn member ( & self ) -> Option < & Member > {
5662 match self {
57- Self :: Value { ident , .. } | Self :: Init { ident , .. } => Some ( ident ) ,
63+ Self :: Value { member , .. } | Self :: Init { member , .. } => Some ( member ) ,
5864 Self :: Code { .. } => None ,
5965 }
6066 }
6167}
6268
69+ fn member_ident ( member : & Member ) -> Ident {
70+ match member {
71+ Member :: Named ( ident) => ident. clone ( ) ,
72+ Member :: Unnamed ( Index { index, .. } ) => format_ident ! ( "_{index}" ) ,
73+ }
74+ }
75+
76+ fn member_binding ( member : & Member ) -> Option < Ident > {
77+ match member {
78+ Member :: Named ( ident) => Some ( ident. clone ( ) ) ,
79+ Member :: Unnamed ( _) => None ,
80+ }
81+ }
82+
6383enum InitializerAttribute {
6484 DefaultError ( DefaultErrorAttribute ) ,
6585}
@@ -73,7 +93,7 @@ pub(crate) fn expand(
7393 attrs,
7494 this,
7595 path,
76- brace_token ,
96+ close_span ,
7797 fields,
7898 rest,
7999 error,
@@ -96,7 +116,7 @@ pub(crate) fn expand(
96116 } else if let Some ( default_error) = default_error {
97117 syn:: parse_str ( default_error) . unwrap ( )
98118 } else {
99- dcx. error ( brace_token . span . close ( ) , "expected `? <type>` after `}` " ) ;
119+ dcx. error ( close_span , "expected `? <type>` after initializer " ) ;
100120 parse_quote ! ( :: core:: convert:: Infallible )
101121 }
102122 } ,
@@ -229,9 +249,9 @@ fn init_fields(
229249 cfgs
230250 } ;
231251
232- let ident = match kind {
233- InitializerKind :: Value { ident , .. } => ident ,
234- InitializerKind :: Init { ident , .. } => ident ,
252+ let member = match kind {
253+ InitializerKind :: Value { member , .. } => member ,
254+ InitializerKind :: Init { member , .. } => member ,
235255 InitializerKind :: Code { block, .. } => {
236256 res. extend ( quote ! {
237257 #( #attrs) *
@@ -241,27 +261,38 @@ fn init_fields(
241261 continue ;
242262 }
243263 } ;
264+ let ident = member_ident ( member) ;
244265
245266 let slot = if pinned {
246- quote ! {
247- // SAFETY:
248- // - `slot` is valid and properly aligned.
249- // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned.
250- // - `make_field_check` prevents `#ident` from being used twice, therefore
251- // `(*slot).#ident` is exclusively accessed and has not been initialized.
252- ( unsafe { #data. #ident( #slot) } )
267+ match member {
268+ Member :: Named ( _) => quote ! {
269+ // SAFETY:
270+ // - `slot` is valid and properly aligned.
271+ // - `make_field_check` checks that the field is properly aligned.
272+ // - `make_field_check` prevents the field from being used twice, therefore
273+ // it is exclusively accessed and has not been initialized.
274+ ( unsafe { #data. #ident( #slot) } )
275+ } ,
276+ Member :: Unnamed ( _) => quote ! {
277+ // SAFETY:
278+ // - `slot` is valid and properly aligned.
279+ // - `make_field_check` checks that the field is properly aligned.
280+ // - `make_field_check` prevents the field from being used twice, therefore
281+ // it is exclusively accessed and has not been initialized.
282+ ( unsafe { #data. #member. slot( & raw mut ( * #slot) . #member) } )
283+ } ,
253284 }
254285 } else {
255286 quote ! {
256287 // For `init!()` macro, everything is unpinned.
257288 // SAFETY:
258- // - `&raw mut (*slot).#ident` is valid.
259- // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned.
260- // - `make_field_check` prevents `#ident` from being used twice, therefore
261- // `(*slot).#ident` is exclusively accessed and has not been initialized.
289+ // - The field pointer is valid.
290+ // - `make_field_check` checks that the field is properly aligned.
291+ // - `make_field_check` prevents the field from being used twice, therefore
292+ // it is exclusively accessed and has not been initialized.
262293 ( unsafe {
263294 :: pin_init:: __internal:: Slot :: <:: pin_init:: __internal:: Unpinned , _>:: new(
264- & raw mut ( * #slot) . #ident
295+ & raw mut ( * #slot) . #member
265296 )
266297 } )
267298 }
@@ -271,7 +302,7 @@ fn init_fields(
271302 let guard = format_ident ! ( "__{ident}_guard" , span = Span :: mixed_site( ) ) ;
272303
273304 let init = match kind {
274- InitializerKind :: Value { ident , value } => {
305+ InitializerKind :: Value { value , .. } => {
275306 let value = value
276307 . as_ref ( )
277308 . map ( |( _, value) | quote ! ( #value) )
@@ -291,13 +322,18 @@ fn init_fields(
291322 }
292323 InitializerKind :: Code { .. } => unreachable ! ( ) ,
293324 } ;
325+ let binding = member_binding ( member) . map ( |ident| {
326+ quote ! {
327+ #( #cfgs) *
328+ #[ allow( unused_variables) ]
329+ let #ident = #guard. let_binding( ) ;
330+ }
331+ } ) ;
294332
295333 res. extend ( quote ! {
296334 #init
297335
298- #( #cfgs) *
299- #[ allow( unused_variables) ]
300- let #ident = #guard. let_binding( ) ;
336+ #binding
301337 } ) ;
302338
303339 guards. push ( guard) ;
@@ -322,9 +358,9 @@ fn make_field_check(
322358) -> TokenStream {
323359 let field_attrs: Vec < _ > = fields
324360 . iter ( )
325- . filter_map ( |f| f. kind . ident ( ) . map ( |_| & f. attrs ) )
361+ . filter_map ( |f| f. kind . member ( ) . map ( |_| & f. attrs ) )
326362 . collect ( ) ;
327- let field_name: Vec < _ > = fields. iter ( ) . filter_map ( |f| f. kind . ident ( ) ) . collect ( ) ;
363+ let field_name: Vec < _ > = fields. iter ( ) . filter_map ( |f| f. kind . member ( ) ) . collect ( ) ;
328364 let zeroing_trailer = match init_kind {
329365 InitKind :: Normal => None ,
330366 InitKind :: Zeroing => Some ( quote ! {
@@ -360,36 +396,73 @@ fn make_field_check(
360396 }
361397}
362398
363- impl Parse for Initializer {
364- fn parse ( input : syn:: parse:: ParseStream < ' _ > ) -> syn:: Result < Self > {
365- let attrs = input. call ( Attribute :: parse_outer) ?;
366- let this = input. peek ( Token ! [ & ] ) . then ( || input. parse ( ) ) . transpose ( ) ?;
367- let path = input. parse ( ) ?;
368- let content;
369- let brace_token = braced ! ( content in input) ;
370- let mut fields = Punctuated :: new ( ) ;
371- loop {
399+ type InitFields = Punctuated < InitializerField , Token ! [ , ] > ;
400+ type InitRest = Option < ( Token ! [ ..] , Expr ) > ;
401+
402+ fn parse_brace_initializer (
403+ input : syn:: parse:: ParseStream < ' _ > ,
404+ ) -> syn:: Result < ( Span , InitFields , InitRest ) > {
405+ let content;
406+ let brace_token = braced ! ( content in input) ;
407+ let mut fields = Punctuated :: new ( ) ;
408+ loop {
409+ let lh = content. lookahead1 ( ) ;
410+ if lh. peek ( End ) || lh. peek ( Token ! [ ..] ) {
411+ break ;
412+ } else if lh. peek ( Ident ) || lh. peek ( LitInt ) || lh. peek ( Token ! [ _] ) || lh. peek ( Token ! [ #] ) {
413+ fields. push_value ( content. parse ( ) ?) ;
372414 let lh = content. lookahead1 ( ) ;
373- if lh. peek ( End ) || lh . peek ( Token ! [ .. ] ) {
415+ if lh. peek ( End ) {
374416 break ;
375- } else if lh. peek ( Ident ) || lh. peek ( Token ! [ _] ) || lh. peek ( Token ! [ #] ) {
376- fields. push_value ( content. parse ( ) ?) ;
377- let lh = content. lookahead1 ( ) ;
378- if lh. peek ( End ) {
379- break ;
380- } else if lh. peek ( Token ! [ , ] ) {
381- fields. push_punct ( content. parse ( ) ?) ;
382- } else {
383- return Err ( lh. error ( ) ) ;
384- }
417+ } else if lh. peek ( Token ! [ , ] ) {
418+ fields. push_punct ( content. parse ( ) ?) ;
385419 } else {
386420 return Err ( lh. error ( ) ) ;
387421 }
422+ } else {
423+ return Err ( lh. error ( ) ) ;
388424 }
389- let rest = content
390- . peek ( Token ! [ ..] )
391- . then ( || Ok :: < _ , syn:: Error > ( ( content. parse ( ) ?, content. parse ( ) ?) ) )
392- . transpose ( ) ?;
425+ }
426+ let rest = content
427+ . peek ( Token ! [ ..] )
428+ . then ( || Ok :: < _ , syn:: Error > ( ( content. parse ( ) ?, content. parse ( ) ?) ) )
429+ . transpose ( ) ?;
430+ Ok ( ( brace_token. span . close ( ) , fields, rest) )
431+ }
432+
433+ fn parse_paren_initializer ( input : syn:: parse:: ParseStream < ' _ > ) -> syn:: Result < ( Span , InitFields ) > {
434+ let content;
435+ let paren_token = parenthesized ! ( content in input) ;
436+ let tuple_fields = content. parse_terminated ( TupleInitializerField :: parse, Token ! [ , ] ) ?;
437+ let mut fields = Punctuated :: new ( ) ;
438+ for ( index, tuple_field) in tuple_fields. into_iter ( ) . enumerate ( ) {
439+ fields. push ( InitializerField {
440+ attrs : tuple_field. attrs ,
441+ kind : InitializerKind :: Value {
442+ member : Member :: Unnamed ( Index {
443+ index : index as u32 ,
444+ span : tuple_field. value . span ( ) ,
445+ } ) ,
446+ value : Some ( ( Token ! [ : ] ( tuple_field. value . span ( ) ) , tuple_field. value ) ) ,
447+ } ,
448+ } ) ;
449+ }
450+ Ok ( ( paren_token. span . close ( ) , fields) )
451+ }
452+
453+ impl Parse for Initializer {
454+ fn parse ( input : syn:: parse:: ParseStream < ' _ > ) -> syn:: Result < Self > {
455+ let attrs = input. call ( Attribute :: parse_outer) ?;
456+ let this = input. peek ( Token ! [ & ] ) . then ( || input. parse ( ) ) . transpose ( ) ?;
457+ let path = input. parse ( ) ?;
458+ let ( close_span, fields, rest) = if input. peek ( token:: Brace ) {
459+ parse_brace_initializer ( input) ?
460+ } else if input. peek ( token:: Paren ) {
461+ let ( close_span, fields) = parse_paren_initializer ( input) ?;
462+ ( close_span, fields, None )
463+ } else {
464+ return Err ( input. error ( "expected curly braces or parentheses" ) ) ;
465+ } ;
393466 let error = input
394467 . peek ( Token ! [ ?] )
395468 . then ( || Ok :: < _ , syn:: Error > ( ( input. parse ( ) ?, input. parse ( ) ?) ) )
@@ -409,7 +482,7 @@ impl Parse for Initializer {
409482 attrs,
410483 this,
411484 path,
412- brace_token ,
485+ close_span ,
413486 fields,
414487 rest,
415488 error,
@@ -452,22 +525,43 @@ impl Parse for InitializerKind {
452525 _colon_token : input. parse ( ) ?,
453526 block : input. parse ( ) ?,
454527 } )
455- } else if lh. peek ( Ident ) {
456- let ident = input. parse ( ) ?;
528+ } else if lh. peek ( Ident ) || lh. peek ( LitInt ) {
529+ let member = if lh. peek ( Ident ) {
530+ Member :: Named ( input. parse ( ) ?)
531+ } else {
532+ let lit: LitInt = input. parse ( ) ?;
533+ let index: u32 = lit. base10_parse ( ) . map_err ( |_| {
534+ syn:: Error :: new (
535+ lit. span ( ) ,
536+ "tuple field index must be a non-negative integer" ,
537+ )
538+ } ) ?;
539+ Member :: Unnamed ( Index {
540+ index,
541+ span : lit. span ( ) ,
542+ } )
543+ } ;
457544 let lh = input. lookahead1 ( ) ;
458545 if lh. peek ( Token ! [ <-] ) {
459546 Ok ( Self :: Init {
460- ident ,
547+ member ,
461548 _left_arrow_token : input. parse ( ) ?,
462549 value : input. parse ( ) ?,
463550 } )
464551 } else if lh. peek ( Token ! [ : ] ) {
465552 Ok ( Self :: Value {
466- ident ,
553+ member ,
467554 value : Some ( ( input. parse ( ) ?, input. parse ( ) ?) ) ,
468555 } )
469556 } else if lh. peek ( Token ! [ , ] ) || lh. peek ( End ) {
470- Ok ( Self :: Value { ident, value : None } )
557+ if matches ! ( member, Member :: Unnamed ( _) ) {
558+ Err ( lh. error ( ) )
559+ } else {
560+ Ok ( Self :: Value {
561+ member,
562+ value : None ,
563+ } )
564+ }
471565 } else {
472566 Err ( lh. error ( ) )
473567 }
@@ -476,3 +570,18 @@ impl Parse for InitializerKind {
476570 }
477571 }
478572}
573+
574+ impl Parse for TupleInitializerField {
575+ fn parse ( input : syn:: parse:: ParseStream < ' _ > ) -> syn:: Result < Self > {
576+ let attrs = input. call ( Attribute :: parse_outer) ?;
577+ if input. peek ( Token ! [ <-] ) {
578+ return Err ( input. error (
579+ "`<-` is not supported in tuple constructor syntax; use braces with indices, e.g. `Type { 0 <- init, 1: value }`" ,
580+ ) ) ;
581+ }
582+ Ok ( Self {
583+ attrs,
584+ value : input. parse ( ) ?,
585+ } )
586+ }
587+ }
0 commit comments