Optimize `'format_str' % (args,)` into f-string bytecode. Returns true if optimization was applied, false to fall back to normal BINARY_OP %. Matches CPython's codegen.c `compiler_formatted_value` optimization.
(
&mut self,
format_str: &str,
args: &[ast::Expr],
range: ruff_text_size::TextRange,
)
| 10053 | /// Returns true if optimization was applied, false to fall back to normal BINARY_OP %. |
| 10054 | /// Matches CPython's codegen.c `compiler_formatted_value` optimization. |
| 10055 | fn try_optimize_format_str( |
| 10056 | &mut self, |
| 10057 | format_str: &str, |
| 10058 | args: &[ast::Expr], |
| 10059 | range: ruff_text_size::TextRange, |
| 10060 | ) -> CompileResult<bool> { |
| 10061 | // Parse format string into segments |
| 10062 | let Some(segments) = Self::parse_percent_format(format_str) else { |
| 10063 | return Ok(false); |
| 10064 | }; |
| 10065 | |
| 10066 | // Verify arg count matches specifier count |
| 10067 | let spec_count = segments.iter().filter(|s| s.conversion.is_some()).count(); |
| 10068 | if spec_count != args.len() { |
| 10069 | return Ok(false); |
| 10070 | } |
| 10071 | |
| 10072 | self.set_source_range(range); |
| 10073 | |
| 10074 | // Special case: no specifiers, just %% escaping → constant fold |
| 10075 | if spec_count == 0 { |
| 10076 | let folded: String = segments.iter().map(|s| s.literal.as_str()).collect(); |
| 10077 | self.emit_load_const(ConstantData::Str { |
| 10078 | value: folded.into(), |
| 10079 | }); |
| 10080 | return Ok(true); |
| 10081 | } |
| 10082 | |
| 10083 | // Emit f-string style bytecode |
| 10084 | let mut part_count: u32 = 0; |
| 10085 | let mut arg_idx = 0; |
| 10086 | |
| 10087 | for seg in &segments { |
| 10088 | if !seg.literal.is_empty() { |
| 10089 | self.emit_load_const(ConstantData::Str { |
| 10090 | value: seg.literal.clone().into(), |
| 10091 | }); |
| 10092 | part_count += 1; |
| 10093 | } |
| 10094 | if let Some(conv) = seg.conversion { |
| 10095 | self.compile_expression(&args[arg_idx])?; |
| 10096 | self.set_source_range(range); |
| 10097 | emit!(self, Instruction::ConvertValue { oparg: conv }); |
| 10098 | emit!(self, Instruction::FormatSimple); |
| 10099 | part_count += 1; |
| 10100 | arg_idx += 1; |
| 10101 | } |
| 10102 | } |
| 10103 | |
| 10104 | if part_count == 0 { |
| 10105 | self.emit_load_const(ConstantData::Str { |
| 10106 | value: String::new().into(), |
| 10107 | }); |
| 10108 | } else if part_count > 1 { |
| 10109 | emit!(self, Instruction::BuildString { count: part_count }); |
| 10110 | } |
| 10111 | |
| 10112 | Ok(true) |
no test coverage detected