-
Notifications
You must be signed in to change notification settings - Fork 898
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add option to control trailing zero in floating-point literals #5834
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,6 +2,8 @@ use std::borrow::Cow; | |||||||||||||||||
use std::cmp::min; | ||||||||||||||||||
|
||||||||||||||||||
use itertools::Itertools; | ||||||||||||||||||
use lazy_static::lazy_static; | ||||||||||||||||||
use regex::Regex; | ||||||||||||||||||
use rustc_ast::token::{Delimiter, Lit, LitKind}; | ||||||||||||||||||
use rustc_ast::{ast, ptr, token, ForLoopKind}; | ||||||||||||||||||
use rustc_span::{BytePos, Span}; | ||||||||||||||||||
|
@@ -13,7 +15,9 @@ use crate::comment::{ | |||||||||||||||||
rewrite_missing_comment, CharClasses, FindUncommented, | ||||||||||||||||||
}; | ||||||||||||||||||
use crate::config::lists::*; | ||||||||||||||||||
use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, Version}; | ||||||||||||||||||
use crate::config::{ | ||||||||||||||||||
Config, ControlBraceStyle, FloatLiteralTrailingZero, HexLiteralCase, IndentStyle, Version, | ||||||||||||||||||
}; | ||||||||||||||||||
use crate::lists::{ | ||||||||||||||||||
definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape, | ||||||||||||||||||
struct_lit_tactic, write_list, ListFormatting, Separator, | ||||||||||||||||||
|
@@ -1242,6 +1246,7 @@ pub(crate) fn rewrite_literal( | |||||||||||||||||
match token_lit.kind { | ||||||||||||||||||
token::LitKind::Str => rewrite_string_lit(context, span, shape), | ||||||||||||||||||
token::LitKind::Integer => rewrite_int_lit(context, token_lit, span, shape), | ||||||||||||||||||
token::LitKind::Float => rewrite_float_lit(context, token_lit, span, shape), | ||||||||||||||||||
_ => wrap_str( | ||||||||||||||||||
context.snippet(span).to_owned(), | ||||||||||||||||||
context.config.max_width(), | ||||||||||||||||||
|
@@ -1282,7 +1287,12 @@ fn rewrite_int_lit( | |||||||||||||||||
span: Span, | ||||||||||||||||||
shape: Shape, | ||||||||||||||||||
) -> Option<String> { | ||||||||||||||||||
if token_lit.is_semantic_float() { | ||||||||||||||||||
return rewrite_float_lit(context, token_lit, span, shape); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
let symbol = token_lit.symbol.as_str(); | ||||||||||||||||||
let suffix = token_lit.suffix.as_ref().map(|s| s.as_str()); | ||||||||||||||||||
|
||||||||||||||||||
if let Some(symbol_stripped) = symbol.strip_prefix("0x") { | ||||||||||||||||||
let hex_lit = match context.config.hex_literal_case() { | ||||||||||||||||||
|
@@ -1292,11 +1302,7 @@ fn rewrite_int_lit( | |||||||||||||||||
}; | ||||||||||||||||||
if let Some(hex_lit) = hex_lit { | ||||||||||||||||||
return wrap_str( | ||||||||||||||||||
format!( | ||||||||||||||||||
"0x{}{}", | ||||||||||||||||||
hex_lit, | ||||||||||||||||||
token_lit.suffix.map_or(String::new(), |s| s.to_string()) | ||||||||||||||||||
), | ||||||||||||||||||
format!("0x{}{}", hex_lit, suffix.unwrap_or("")), | ||||||||||||||||||
context.config.max_width(), | ||||||||||||||||||
shape, | ||||||||||||||||||
); | ||||||||||||||||||
|
@@ -1310,6 +1316,69 @@ fn rewrite_int_lit( | |||||||||||||||||
) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
fn rewrite_float_lit( | ||||||||||||||||||
context: &RewriteContext<'_>, | ||||||||||||||||||
token_lit: token::Lit, | ||||||||||||||||||
span: Span, | ||||||||||||||||||
shape: Shape, | ||||||||||||||||||
) -> Option<String> { | ||||||||||||||||||
if matches!( | ||||||||||||||||||
context.config.float_literal_trailing_zero(), | ||||||||||||||||||
FloatLiteralTrailingZero::Preserve | ||||||||||||||||||
) { | ||||||||||||||||||
return wrap_str( | ||||||||||||||||||
context.snippet(span).to_owned(), | ||||||||||||||||||
context.config.max_width(), | ||||||||||||||||||
shape, | ||||||||||||||||||
); | ||||||||||||||||||
Comment on lines
+1329
to
+1333
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For For reference, here's the code in Lines 1261 to 1263 in cedb7b5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please elaborate? I guess the statement “there is no meaningful way to break a float literal over multiple lines” is always true, so why would this depend on config version? BTW, would you say that Lines 1306 to 1310 in cedb7b5
|
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
let symbol = token_lit.symbol.as_str(); | ||||||||||||||||||
let suffix = token_lit.suffix.as_ref().map(|s| s.as_str()); | ||||||||||||||||||
|
||||||||||||||||||
let FloatSymbolParts { | ||||||||||||||||||
integer_part, | ||||||||||||||||||
fractional_part, | ||||||||||||||||||
exponent, | ||||||||||||||||||
} = parse_float_symbol(symbol); | ||||||||||||||||||
|
||||||||||||||||||
let has_postfix = exponent.is_some() || suffix.is_some(); | ||||||||||||||||||
let fractional_part_nonzero = fractional_part.map_or(false, |s| !is_zero_integer_literal(s)); | ||||||||||||||||||
|
||||||||||||||||||
let (include_period, include_fractional_part) = | ||||||||||||||||||
match context.config.float_literal_trailing_zero() { | ||||||||||||||||||
FloatLiteralTrailingZero::Preserve => unreachable!("handled above"), | ||||||||||||||||||
FloatLiteralTrailingZero::Always => (true, true), | ||||||||||||||||||
FloatLiteralTrailingZero::IfNoPostfix => ( | ||||||||||||||||||
fractional_part_nonzero || !has_postfix, | ||||||||||||||||||
fractional_part_nonzero || !has_postfix, | ||||||||||||||||||
), | ||||||||||||||||||
FloatLiteralTrailingZero::Never => ( | ||||||||||||||||||
fractional_part_nonzero || !has_postfix, | ||||||||||||||||||
fractional_part_nonzero, | ||||||||||||||||||
), | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
let period = if include_period { "." } else { "" }; | ||||||||||||||||||
let fractional_part = if include_fractional_part { | ||||||||||||||||||
fractional_part.unwrap_or("0") | ||||||||||||||||||
} else { | ||||||||||||||||||
"" | ||||||||||||||||||
}; | ||||||||||||||||||
wrap_str( | ||||||||||||||||||
format!( | ||||||||||||||||||
"{}{}{}{}{}", | ||||||||||||||||||
integer_part, | ||||||||||||||||||
period, | ||||||||||||||||||
fractional_part, | ||||||||||||||||||
exponent.unwrap_or(""), | ||||||||||||||||||
suffix.unwrap_or(""), | ||||||||||||||||||
), | ||||||||||||||||||
context.config.max_width(), | ||||||||||||||||||
shape, | ||||||||||||||||||
) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option<SeparatorTactic> { | ||||||||||||||||||
if context.inside_macro() { | ||||||||||||||||||
if span_ends_with_comma(context, span) { | ||||||||||||||||||
|
@@ -2215,9 +2284,39 @@ pub(crate) fn is_method_call(expr: &ast::Expr) -> bool { | |||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
struct FloatSymbolParts<'a> { | ||||||||||||||||||
integer_part: &'a str, | ||||||||||||||||||
fractional_part: Option<&'a str>, | ||||||||||||||||||
exponent: Option<&'a str>, | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
// Parses a float literal. The `symbol` must be a valid floating point literal without a type | ||||||||||||||||||
// suffix. Otherwise the function may panic or return wrong result. | ||||||||||||||||||
fn parse_float_symbol(symbol: &str) -> FloatSymbolParts<'_> { | ||||||||||||||||||
lazy_static! { | ||||||||||||||||||
// This regex may accept invalid float literals (such as `1`, `_` or `2.e3`). That's ok. | ||||||||||||||||||
// We only use it to parse literals whose validity has already been established. | ||||||||||||||||||
static ref FLOAT_LITERAL: Regex = | ||||||||||||||||||
Regex::new(r"^([0-9_]+)(?:\.([0-9_]+)?)?([eE][+-]?[0-9_]+)?$").unwrap(); | ||||||||||||||||||
} | ||||||||||||||||||
let caps = FLOAT_LITERAL.captures(symbol).unwrap(); | ||||||||||||||||||
FloatSymbolParts { | ||||||||||||||||||
integer_part: caps.get(1).unwrap().as_str(), | ||||||||||||||||||
fractional_part: caps.get(2).map(|m| m.as_str()), | ||||||||||||||||||
exponent: caps.get(3).map(|m| m.as_str()), | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
fn is_zero_integer_literal(symbol: &str) -> bool { | ||||||||||||||||||
lazy_static! { | ||||||||||||||||||
static ref ZERO_LITERAL: Regex = Regex::new(r"^[0_]+$").unwrap(); | ||||||||||||||||||
} | ||||||||||||||||||
ZERO_LITERAL.is_match(symbol) | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[cfg(test)] | ||||||||||||||||||
mod test { | ||||||||||||||||||
use super::last_line_offsetted; | ||||||||||||||||||
use super::*; | ||||||||||||||||||
|
||||||||||||||||||
#[test] | ||||||||||||||||||
fn test_last_line_offsetted() { | ||||||||||||||||||
|
@@ -2239,4 +2338,60 @@ mod test { | |||||||||||||||||
let lines = "one\n two three"; | ||||||||||||||||||
assert_eq!(last_line_offsetted(2, lines), false); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[test] | ||||||||||||||||||
fn test_parse_float_symbol() { | ||||||||||||||||||
let parts = parse_float_symbol("123.456e789"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "123"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, Some("456")); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e789")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("123.456e+789"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "123"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, Some("456")); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e+789")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("123.456e-789"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "123"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, Some("456")); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e-789")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("123e789"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "123"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, None); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e789")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("123E789"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "123"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, None); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("E789")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("123."); | ||||||||||||||||||
assert_eq!(parts.integer_part, "123"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, None); | ||||||||||||||||||
assert_eq!(parts.exponent, None); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[test] | ||||||||||||||||||
fn test_parse_float_symbol_with_underscores() { | ||||||||||||||||||
let parts = parse_float_symbol("_123._456e_789"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "_123"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, Some("_456")); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e_789")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("123_.456_e789_"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "123_"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, Some("456_")); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e789_")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("1_23.4_56e7_89"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "1_23"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, Some("4_56")); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e7_89")); | ||||||||||||||||||
|
||||||||||||||||||
let parts = parse_float_symbol("_1_23_._4_56_e_7_89_"); | ||||||||||||||||||
assert_eq!(parts.integer_part, "_1_23_"); | ||||||||||||||||||
assert_eq!(parts.fractional_part, Some("_4_56_")); | ||||||||||||||||||
assert_eq!(parts.exponent, Some("e_7_89_")); | ||||||||||||||||||
} | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// rustfmt-float_literal_trailing_zero: Always | ||
|
||
fn float_literals() { | ||
let a = 0.; | ||
let b = 0.0; | ||
let c = 100.; | ||
let d = 100.0; | ||
let e = 5e3; | ||
let f = 5.0e3; | ||
let g = 5e+3; | ||
let h = 5.0e+3; | ||
let i = 5e-3; | ||
let j = 5.0e-3; | ||
let k = 5E3; | ||
let l = 5.0E3; | ||
let m = 7f32; | ||
let n = 7.0f32; | ||
let o = 9e3f32; | ||
let p = 9.0e3f32; | ||
let q = 1000.00; | ||
let r = 1_000_.; | ||
let s = 1_000_.000_000; | ||
} | ||
|
||
fn line_wrapping() { | ||
let array = [ | ||
1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., | ||
]; | ||
println!("This is floaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaat {}", 10e3); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// rustfmt-float_literal_trailing_zero: IfNoPostfix | ||
|
||
fn float_literals() { | ||
let a = 0.; | ||
let b = 0.0; | ||
let c = 100.; | ||
let d = 100.0; | ||
let e = 5e3; | ||
let f = 5.0e3; | ||
let g = 5e+3; | ||
let h = 5.0e+3; | ||
let i = 5e-3; | ||
let j = 5.0e-3; | ||
let k = 5E3; | ||
let l = 5.0E3; | ||
let m = 7f32; | ||
let n = 7.0f32; | ||
let o = 9e3f32; | ||
let p = 9.0e3f32; | ||
let q = 1000.00; | ||
let r = 1_000_.; | ||
let s = 1_000_.000_000; | ||
} | ||
|
||
fn line_wrapping() { | ||
let array = [ | ||
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11., 12., 13., 14., 15., 16., 17., 18., | ||
]; | ||
println!( | ||
"This is floaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaat {}", | ||
10.0e3 | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we'll need to add a new tracking issue for this one. #3187 isn't a tracking issue. We can certainly add the tracking issue after this PR is merged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we create an issue now, so that we don't have to go back and modify the link later?
Is there a document that describes how a tracking issue should look like?