|
1 | 1 | use super::*; |
2 | 2 | use rustc_ast as ast; |
3 | | -use rustc_ast::visit::{self, Visitor}; |
4 | | -use rustc_ast::{BlockCheckMode, UnsafeSource}; |
5 | | -use rustc_data_structures::fx::FxIndexSet; |
6 | | -use rustc_span::{sym, symbol::kw}; |
7 | | - |
8 | | -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] |
9 | | -enum ArgumentType { |
10 | | - Format(FormatTrait), |
11 | | - Usize, |
12 | | -} |
13 | | - |
14 | | -fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> { |
15 | | - // Generate: |
16 | | - // ::core::fmt::ArgumentV1::new_…(arg) |
17 | | - use ArgumentType::*; |
18 | | - use FormatTrait::*; |
19 | | - ecx.expr_call_global( |
20 | | - sp, |
21 | | - ecx.std_path(&[ |
22 | | - sym::fmt, |
23 | | - sym::ArgumentV1, |
24 | | - match ty { |
25 | | - Format(Display) => sym::new_display, |
26 | | - Format(Debug) => sym::new_debug, |
27 | | - Format(LowerExp) => sym::new_lower_exp, |
28 | | - Format(UpperExp) => sym::new_upper_exp, |
29 | | - Format(Octal) => sym::new_octal, |
30 | | - Format(Pointer) => sym::new_pointer, |
31 | | - Format(Binary) => sym::new_binary, |
32 | | - Format(LowerHex) => sym::new_lower_hex, |
33 | | - Format(UpperHex) => sym::new_upper_hex, |
34 | | - Usize => sym::from_usize, |
35 | | - }, |
36 | | - ]), |
37 | | - vec![arg], |
38 | | - ) |
39 | | -} |
40 | | - |
41 | | -fn make_count( |
42 | | - ecx: &ExtCtxt<'_>, |
43 | | - sp: Span, |
44 | | - count: &Option<FormatCount>, |
45 | | - argmap: &mut FxIndexSet<(usize, ArgumentType)>, |
46 | | -) -> P<ast::Expr> { |
47 | | - // Generate: |
48 | | - // ::core::fmt::rt::v1::Count::…(…) |
49 | | - match count { |
50 | | - Some(FormatCount::Literal(n)) => ecx.expr_call_global( |
51 | | - sp, |
52 | | - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]), |
53 | | - vec![ecx.expr_usize(sp, *n)], |
54 | | - ), |
55 | | - Some(FormatCount::Argument(arg)) => { |
56 | | - if let Ok(arg_index) = arg.index { |
57 | | - let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); |
58 | | - ecx.expr_call_global( |
59 | | - sp, |
60 | | - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]), |
61 | | - vec![ecx.expr_usize(sp, i)], |
62 | | - ) |
63 | | - } else { |
64 | | - DummyResult::raw_expr(sp, true) |
65 | | - } |
66 | | - } |
67 | | - None => ecx.expr_path(ecx.path_global( |
68 | | - sp, |
69 | | - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]), |
70 | | - )), |
71 | | - } |
72 | | -} |
73 | | - |
74 | | -fn make_format_spec( |
75 | | - ecx: &ExtCtxt<'_>, |
76 | | - sp: Span, |
77 | | - placeholder: &FormatPlaceholder, |
78 | | - argmap: &mut FxIndexSet<(usize, ArgumentType)>, |
79 | | -) -> P<ast::Expr> { |
80 | | - // Generate: |
81 | | - // ::core::fmt::rt::v1::Argument { |
82 | | - // position: 0usize, |
83 | | - // format: ::core::fmt::rt::v1::FormatSpec { |
84 | | - // fill: ' ', |
85 | | - // align: ::core::fmt::rt::v1::Alignment::Unknown, |
86 | | - // flags: 0u32, |
87 | | - // precision: ::core::fmt::rt::v1::Count::Implied, |
88 | | - // width: ::core::fmt::rt::v1::Count::Implied, |
89 | | - // }, |
90 | | - // } |
91 | | - let position = match placeholder.argument.index { |
92 | | - Ok(arg_index) => { |
93 | | - let (i, _) = |
94 | | - argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); |
95 | | - ecx.expr_usize(sp, i) |
96 | | - } |
97 | | - Err(_) => DummyResult::raw_expr(sp, true), |
98 | | - }; |
99 | | - let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' ')); |
100 | | - let align = ecx.expr_path(ecx.path_global( |
101 | | - sp, |
102 | | - ecx.std_path(&[ |
103 | | - sym::fmt, |
104 | | - sym::rt, |
105 | | - sym::v1, |
106 | | - sym::Alignment, |
107 | | - match placeholder.format_options.alignment { |
108 | | - Some(FormatAlignment::Left) => sym::Left, |
109 | | - Some(FormatAlignment::Right) => sym::Right, |
110 | | - Some(FormatAlignment::Center) => sym::Center, |
111 | | - None => sym::Unknown, |
112 | | - }, |
113 | | - ]), |
114 | | - )); |
115 | | - let flags = ecx.expr_u32(sp, placeholder.format_options.flags); |
116 | | - let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap); |
117 | | - let width = make_count(ecx, sp, &placeholder.format_options.width, argmap); |
118 | | - ecx.expr_struct( |
119 | | - sp, |
120 | | - ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])), |
121 | | - vec![ |
122 | | - ecx.field_imm(sp, Ident::new(sym::position, sp), position), |
123 | | - ecx.field_imm( |
124 | | - sp, |
125 | | - Ident::new(sym::format, sp), |
126 | | - ecx.expr_struct( |
127 | | - sp, |
128 | | - ecx.path_global( |
129 | | - sp, |
130 | | - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]), |
131 | | - ), |
132 | | - vec![ |
133 | | - ecx.field_imm(sp, Ident::new(sym::fill, sp), fill), |
134 | | - ecx.field_imm(sp, Ident::new(sym::align, sp), align), |
135 | | - ecx.field_imm(sp, Ident::new(sym::flags, sp), flags), |
136 | | - ecx.field_imm(sp, Ident::new(sym::precision, sp), prec), |
137 | | - ecx.field_imm(sp, Ident::new(sym::width, sp), width), |
138 | | - ], |
139 | | - ), |
140 | | - ), |
141 | | - ], |
142 | | - ) |
143 | | -} |
| 3 | +use rustc_span::sym; |
144 | 4 |
|
145 | 5 | pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> { |
146 | 6 | let macsp = ecx.with_def_site_ctxt(ecx.call_site()); |
147 | 7 |
|
148 | | - let lit_pieces = ecx.expr_array_ref( |
149 | | - fmt.span, |
150 | | - fmt.template |
151 | | - .iter() |
152 | | - .enumerate() |
153 | | - .filter_map(|(i, piece)| match piece { |
154 | | - &FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)), |
155 | | - &FormatArgsPiece::Placeholder(_) => { |
156 | | - // Inject empty string before placeholders when not already preceded by a literal piece. |
157 | | - if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { |
158 | | - Some(ecx.expr_str(fmt.span, kw::Empty)) |
159 | | - } else { |
160 | | - None |
161 | | - } |
162 | | - } |
163 | | - }) |
164 | | - .collect(), |
165 | | - ); |
166 | | - |
167 | | - // Whether we'll use the `Arguments::new_v1_formatted` form (true), |
168 | | - // or the `Arguments::new_v1` form (false). |
169 | | - let mut use_format_options = false; |
| 8 | + … // TODO |
170 | 9 |
|
171 | | - // Create a list of all _unique_ (argument, format trait) combinations. |
172 | | - // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] |
173 | | - let mut argmap = FxIndexSet::default(); |
174 | | - for piece in &fmt.template { |
175 | | - let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; |
176 | | - if placeholder.format_options != Default::default() { |
177 | | - // Can't use basic form if there's any formatting options. |
178 | | - use_format_options = true; |
179 | | - } |
180 | | - if let Ok(index) = placeholder.argument.index { |
181 | | - if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) { |
182 | | - // Duplicate (argument, format trait) combination, |
183 | | - // which we'll only put once in the args array. |
184 | | - use_format_options = true; |
185 | | - } |
186 | | - } |
187 | | - } |
188 | | - |
189 | | - let format_options = use_format_options.then(|| { |
190 | | - // Generate: |
191 | | - // &[format_spec_0, format_spec_1, format_spec_2] |
192 | | - ecx.expr_array_ref( |
193 | | - macsp, |
194 | | - fmt.template |
195 | | - .iter() |
196 | | - .filter_map(|piece| { |
197 | | - let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; |
198 | | - Some(make_format_spec(ecx, macsp, placeholder, &mut argmap)) |
199 | | - }) |
200 | | - .collect(), |
201 | | - ) |
202 | | - }); |
203 | | - |
204 | | - let arguments = fmt.arguments.into_vec(); |
205 | | - |
206 | | - // If the args array contains exactly all the original arguments once, |
207 | | - // in order, we can use a simple array instead of a `match` construction. |
208 | | - // However, if there's a yield point in any argument except the first one, |
209 | | - // we don't do this, because an ArgumentV1 cannot be kept across yield points. |
210 | | - let use_simple_array = argmap.len() == arguments.len() |
211 | | - && argmap.iter().enumerate().all(|(i, &(j, _))| i == j) |
212 | | - && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); |
213 | | - |
214 | | - let args = if use_simple_array { |
215 | | - // Generate: |
216 | | - // &[ |
217 | | - // ::core::fmt::ArgumentV1::new_display(&arg0), |
218 | | - // ::core::fmt::ArgumentV1::new_lower_hex(&arg1), |
219 | | - // ::core::fmt::ArgumentV1::new_debug(&arg2), |
220 | | - // ] |
221 | | - ecx.expr_array_ref( |
222 | | - macsp, |
223 | | - arguments |
224 | | - .into_iter() |
225 | | - .zip(argmap) |
226 | | - .map(|(arg, (_, ty))| { |
227 | | - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); |
228 | | - make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty) |
229 | | - }) |
230 | | - .collect(), |
231 | | - ) |
232 | | - } else { |
233 | | - // Generate: |
234 | | - // match (&arg0, &arg1, &arg2) { |
235 | | - // args => &[ |
236 | | - // ::core::fmt::ArgumentV1::new_display(args.0), |
237 | | - // ::core::fmt::ArgumentV1::new_lower_hex(args.1), |
238 | | - // ::core::fmt::ArgumentV1::new_debug(args.0), |
239 | | - // ] |
240 | | - // } |
241 | | - let args_ident = Ident::new(sym::args, macsp); |
242 | | - let args = argmap |
243 | | - .iter() |
244 | | - .map(|&(arg_index, ty)| { |
245 | | - if let Some(arg) = arguments.get(arg_index) { |
246 | | - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); |
247 | | - make_argument( |
248 | | - ecx, |
249 | | - sp, |
250 | | - ecx.expr_field( |
251 | | - sp, |
252 | | - ecx.expr_ident(macsp, args_ident), |
253 | | - Ident::new(sym::integer(arg_index), macsp), |
254 | | - ), |
255 | | - ty, |
256 | | - ) |
257 | | - } else { |
258 | | - DummyResult::raw_expr(macsp, true) |
259 | | - } |
260 | | - }) |
261 | | - .collect(); |
262 | | - ecx.expr_addr_of( |
263 | | - macsp, |
264 | | - ecx.expr_match( |
265 | | - macsp, |
266 | | - ecx.expr_tuple( |
267 | | - macsp, |
268 | | - arguments |
269 | | - .into_iter() |
270 | | - .map(|arg| { |
271 | | - ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr) |
272 | | - }) |
273 | | - .collect(), |
274 | | - ), |
275 | | - vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))], |
276 | | - ), |
277 | | - ) |
278 | | - }; |
279 | | - |
280 | | - if let Some(format_options) = format_options { |
281 | | - // Generate: |
282 | | - // ::core::fmt::Arguments::new_v1_formatted( |
283 | | - // lit_pieces, |
284 | | - // args, |
285 | | - // format_options, |
286 | | - // unsafe { ::core::fmt::UnsafeArg::new() } |
287 | | - // ) |
288 | | - ecx.expr_call_global( |
289 | | - macsp, |
290 | | - ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]), |
291 | | - vec![ |
292 | | - lit_pieces, |
293 | | - args, |
294 | | - format_options, |
295 | | - ecx.expr_block(P(ast::Block { |
296 | | - stmts: vec![ecx.stmt_expr(ecx.expr_call_global( |
297 | | - macsp, |
298 | | - ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]), |
299 | | - Vec::new(), |
300 | | - ))], |
301 | | - id: ast::DUMMY_NODE_ID, |
302 | | - rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), |
303 | | - span: macsp, |
304 | | - tokens: None, |
305 | | - could_be_bare_literal: false, |
306 | | - })), |
307 | | - ], |
308 | | - ) |
309 | | - } else { |
310 | | - // Generate: |
311 | | - // ::core::fmt::Arguments::new_v1( |
312 | | - // lit_pieces, |
313 | | - // args, |
314 | | - // ) |
315 | | - ecx.expr_call_global( |
316 | | - macsp, |
317 | | - ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]), |
318 | | - vec![lit_pieces, args], |
319 | | - ) |
320 | | - } |
321 | | -} |
322 | | - |
323 | | -fn may_contain_yield_point(e: &ast::Expr) -> bool { |
324 | | - struct MayContainYieldPoint(bool); |
325 | | - |
326 | | - impl Visitor<'_> for MayContainYieldPoint { |
327 | | - fn visit_expr(&mut self, e: &ast::Expr) { |
328 | | - if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { |
329 | | - self.0 = true; |
330 | | - } else { |
331 | | - visit::walk_expr(self, e); |
332 | | - } |
333 | | - } |
334 | | - |
335 | | - fn visit_mac_call(&mut self, _: &ast::MacCall) { |
336 | | - self.0 = true; |
337 | | - } |
338 | | - |
339 | | - fn visit_attribute(&mut self, _: &ast::Attribute) { |
340 | | - // Conservatively assume this may be a proc macro attribute in |
341 | | - // expression position. |
342 | | - self.0 = true; |
343 | | - } |
344 | | - |
345 | | - fn visit_item(&mut self, _: &ast::Item) { |
346 | | - // Do not recurse into nested items. |
347 | | - } |
348 | | - } |
349 | | - |
350 | | - let mut visitor = MayContainYieldPoint(false); |
351 | | - visitor.visit_expr(e); |
352 | | - visitor.0 |
| 10 | + // Generate: |
| 11 | + // ::core::fmt::Arguments::new( |
| 12 | + // … |
| 13 | + // ) |
| 14 | + ecx.expr_call_global( |
| 15 | + macsp, |
| 16 | + ecx.std_path(&[sym::fmt, sym::Arguments, sym::new]), |
| 17 | + vec![…], |
| 18 | + ) |
353 | 19 | } |
0 commit comments