@@ -20,10 +20,126 @@ impl<'hir> LoweringContext<'_, 'hir> {
2020        let  mut  fmt = Cow :: Borrowed ( fmt) ; 
2121        if  self . tcx . sess . opts . unstable_opts . flatten_format_args  { 
2222            fmt = flatten_format_args ( fmt) ; 
23-             fmt = inline_literals ( fmt) ; 
23+             fmt = self . inline_literals ( fmt) ; 
2424        } 
2525        expand_format_args ( self ,  sp,  & fmt,  allow_const) 
2626    } 
27+ 
28+     /// Try to convert a literal into an interned string 
29+      fn  try_inline_lit ( & self ,  lit :  token:: Lit )  -> Option < Symbol >  { 
30+         match  LitKind :: from_token_lit ( lit)  { 
31+             Ok ( LitKind :: Str ( s,  _) )  => Some ( s) , 
32+             Ok ( LitKind :: Int ( n,  ty) )  => { 
33+                 match  ty { 
34+                     // unsuffixed integer literals are assumed to be i32's 
35+                     LitIntType :: Unsuffixed  => { 
36+                         ( n <= i32:: MAX  as  u128 ) . then_some ( Symbol :: intern ( & n. to_string ( ) ) ) 
37+                     } 
38+                     LitIntType :: Signed ( int_ty)  => { 
39+                         let  max_literal = self . int_ty_max ( int_ty) ; 
40+                         ( n <= max_literal) . then_some ( Symbol :: intern ( & n. to_string ( ) ) ) 
41+                     } 
42+                     LitIntType :: Unsigned ( uint_ty)  => { 
43+                         let  max_literal = self . uint_ty_max ( uint_ty) ; 
44+                         ( n <= max_literal) . then_some ( Symbol :: intern ( & n. to_string ( ) ) ) 
45+                     } 
46+                 } 
47+             } 
48+             _ => None , 
49+         } 
50+     } 
51+ 
52+     /// Get the maximum value of int_ty. It is platform-dependent due to the byte size of isize 
53+      fn  int_ty_max ( & self ,  int_ty :  IntTy )  -> u128  { 
54+         match  int_ty { 
55+             IntTy :: Isize  => self . tcx . data_layout . pointer_size . signed_int_max ( )  as  u128 , 
56+             IntTy :: I8  => i8:: MAX  as  u128 , 
57+             IntTy :: I16  => i16:: MAX  as  u128 , 
58+             IntTy :: I32  => i32:: MAX  as  u128 , 
59+             IntTy :: I64  => i64:: MAX  as  u128 , 
60+             IntTy :: I128  => i128:: MAX  as  u128 , 
61+         } 
62+     } 
63+ 
64+     /// Get the maximum value of uint_ty. It is platform-dependent due to the byte size of usize 
65+      fn  uint_ty_max ( & self ,  uint_ty :  UintTy )  -> u128  { 
66+         match  uint_ty { 
67+             UintTy :: Usize  => self . tcx . data_layout . pointer_size . unsigned_int_max ( ) , 
68+             UintTy :: U8  => u8:: MAX  as  u128 , 
69+             UintTy :: U16  => u16:: MAX  as  u128 , 
70+             UintTy :: U32  => u32:: MAX  as  u128 , 
71+             UintTy :: U64  => u64:: MAX  as  u128 , 
72+             UintTy :: U128  => u128:: MAX  as  u128 , 
73+         } 
74+     } 
75+ 
76+     /// Inline literals into the format string. 
77+      /// 
78+      /// Turns 
79+      /// 
80+      /// `format_args!("Hello, {}! {} {}", "World", 123, x)` 
81+      /// 
82+      /// into 
83+      /// 
84+      /// `format_args!("Hello, World! 123 {}", x)`. 
85+      fn  inline_literals < ' fmt > ( & self ,  mut  fmt :  Cow < ' fmt ,  FormatArgs > )  -> Cow < ' fmt ,  FormatArgs >  { 
86+         let  mut  was_inlined = vec ! [ false ;  fmt. arguments. all_args( ) . len( ) ] ; 
87+         let  mut  inlined_anything = false ; 
88+ 
89+         for  i in  0 ..fmt. template . len ( )  { 
90+             let  FormatArgsPiece :: Placeholder ( placeholder)  = & fmt. template [ i]  else  {  continue  } ; 
91+             let  Ok ( arg_index)  = placeholder. argument . index  else  {  continue  } ; 
92+ 
93+             let  mut  literal = None ; 
94+ 
95+             if  let  FormatTrait :: Display  = placeholder. format_trait 
96+                 && placeholder. format_options  == Default :: default ( ) 
97+                 && let  arg = fmt. arguments . all_args ( ) [ arg_index] . expr . peel_parens_and_refs ( ) 
98+                 && let  ExprKind :: Lit ( lit)  = arg. kind 
99+             { 
100+                 literal = self . try_inline_lit ( lit) ; 
101+             } 
102+ 
103+             if  let  Some ( literal)  = literal { 
104+                 // Now we need to mutate the outer FormatArgs. 
105+                 // If this is the first time, this clones the outer FormatArgs. 
106+                 let  fmt = fmt. to_mut ( ) ; 
107+                 // Replace the placeholder with the literal. 
108+                 fmt. template [ i]  = FormatArgsPiece :: Literal ( literal) ; 
109+                 was_inlined[ arg_index]  = true ; 
110+                 inlined_anything = true ; 
111+             } 
112+         } 
113+ 
114+         // Remove the arguments that were inlined. 
115+         if  inlined_anything { 
116+             let  fmt = fmt. to_mut ( ) ; 
117+ 
118+             let  mut  remove = was_inlined; 
119+ 
120+             // Don't remove anything that's still used. 
121+             for_all_argument_indexes ( & mut  fmt. template ,  |index| remove[ * index]  = false ) ; 
122+ 
123+             // Drop all the arguments that are marked for removal. 
124+             let  mut  remove_it = remove. iter ( ) ; 
125+             fmt. arguments . all_args_mut ( ) . retain ( |_| remove_it. next ( )  != Some ( & true ) ) ; 
126+ 
127+             // Calculate the mapping of old to new indexes for the remaining arguments. 
128+             let  index_map:  Vec < usize >  = remove
129+                 . into_iter ( ) 
130+                 . scan ( 0 ,  |i,  remove| { 
131+                     let  mapped = * i; 
132+                     * i += !remove as  usize ; 
133+                     Some ( mapped) 
134+                 } ) 
135+                 . collect ( ) ; 
136+ 
137+             // Correct the indexes that refer to arguments that have shifted position. 
138+             for_all_argument_indexes ( & mut  fmt. template ,  |index| * index = index_map[ * index] ) ; 
139+         } 
140+ 
141+         fmt
142+     } 
27143} 
28144
29145/// Flattens nested `format_args!()` into one. 
@@ -103,82 +219,6 @@ fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
103219    fmt
104220} 
105221
106- /// Inline literals into the format string. 
107- /// 
108- /// Turns 
109- /// 
110- /// `format_args!("Hello, {}! {} {}", "World", 123, x)` 
111- /// 
112- /// into 
113- /// 
114- /// `format_args!("Hello, World! 123 {}", x)`. 
115- fn  inline_literals ( mut  fmt :  Cow < ' _ ,  FormatArgs > )  -> Cow < ' _ ,  FormatArgs >  { 
116-     let  mut  was_inlined = vec ! [ false ;  fmt. arguments. all_args( ) . len( ) ] ; 
117-     let  mut  inlined_anything = false ; 
118- 
119-     for  i in  0 ..fmt. template . len ( )  { 
120-         let  FormatArgsPiece :: Placeholder ( placeholder)  = & fmt. template [ i]  else  {  continue  } ; 
121-         let  Ok ( arg_index)  = placeholder. argument . index  else  {  continue  } ; 
122- 
123-         let  mut  literal = None ; 
124- 
125-         if  let  FormatTrait :: Display  = placeholder. format_trait 
126-             && placeholder. format_options  == Default :: default ( ) 
127-             && let  arg = fmt. arguments . all_args ( ) [ arg_index] . expr . peel_parens_and_refs ( ) 
128-             && let  ExprKind :: Lit ( lit)  = arg. kind 
129-         { 
130-             if  let  token:: LitKind :: Str  | token:: LitKind :: StrRaw ( _)  = lit. kind 
131-                 && let  Ok ( LitKind :: Str ( s,  _) )  = LitKind :: from_token_lit ( lit) 
132-             { 
133-                 literal = Some ( s) ; 
134-             }  else  if  let  token:: LitKind :: Integer  = lit. kind 
135-                 && let  Ok ( LitKind :: Int ( n,  _) )  = LitKind :: from_token_lit ( lit) 
136-             { 
137-                 literal = Some ( Symbol :: intern ( & n. to_string ( ) ) ) ; 
138-             } 
139-         } 
140- 
141-         if  let  Some ( literal)  = literal { 
142-             // Now we need to mutate the outer FormatArgs. 
143-             // If this is the first time, this clones the outer FormatArgs. 
144-             let  fmt = fmt. to_mut ( ) ; 
145-             // Replace the placeholder with the literal. 
146-             fmt. template [ i]  = FormatArgsPiece :: Literal ( literal) ; 
147-             was_inlined[ arg_index]  = true ; 
148-             inlined_anything = true ; 
149-         } 
150-     } 
151- 
152-     // Remove the arguments that were inlined. 
153-     if  inlined_anything { 
154-         let  fmt = fmt. to_mut ( ) ; 
155- 
156-         let  mut  remove = was_inlined; 
157- 
158-         // Don't remove anything that's still used. 
159-         for_all_argument_indexes ( & mut  fmt. template ,  |index| remove[ * index]  = false ) ; 
160- 
161-         // Drop all the arguments that are marked for removal. 
162-         let  mut  remove_it = remove. iter ( ) ; 
163-         fmt. arguments . all_args_mut ( ) . retain ( |_| remove_it. next ( )  != Some ( & true ) ) ; 
164- 
165-         // Calculate the mapping of old to new indexes for the remaining arguments. 
166-         let  index_map:  Vec < usize >  = remove
167-             . into_iter ( ) 
168-             . scan ( 0 ,  |i,  remove| { 
169-                 let  mapped = * i; 
170-                 * i += !remove as  usize ; 
171-                 Some ( mapped) 
172-             } ) 
173-             . collect ( ) ; 
174- 
175-         // Correct the indexes that refer to arguments that have shifted position. 
176-         for_all_argument_indexes ( & mut  fmt. template ,  |index| * index = index_map[ * index] ) ; 
177-     } 
178- 
179-     fmt
180- } 
181- 
182222#[ derive( Copy ,  Clone ,  Debug ,  Hash ,  PartialEq ,  Eq ) ]  
183223enum  ArgumentType  { 
184224    Format ( FormatTrait ) , 
0 commit comments