summaryrefslogtreecommitdiffstats
path: root/src/doc/style-guide/src/expressions.md
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/doc/style-guide/src/expressions.md850
1 files changed, 850 insertions, 0 deletions
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
new file mode 100644
index 000000000..c7d0446dd
--- /dev/null
+++ b/src/doc/style-guide/src/expressions.md
@@ -0,0 +1,850 @@
+## Expressions
+
+### Blocks
+
+A block expression should have a newline after the initial `{` and before the
+terminal `}`. Any qualifier before the block (e.g., `unsafe`) should always be
+on the same line as the opening brace, and separated with a single space. The
+contents of the block should be block indented:
+
+```rust
+fn block_as_stmt() {
+ a_call();
+
+ {
+ a_call_inside_a_block();
+
+ // a comment in a block
+ the_value
+ }
+}
+
+fn block_as_expr() {
+ let foo = {
+ a_call_inside_a_block();
+
+ // a comment in a block
+ the_value
+ };
+}
+
+fn unsafe_block_as_stmt() {
+ a_call();
+
+ unsafe {
+ a_call_inside_a_block();
+
+ // a comment in a block
+ the_value
+ }
+}
+```
+
+If a block has an attribute, it should be on its own line:
+
+```rust
+fn block_as_stmt() {
+ #[an_attribute]
+ {
+ #![an_inner_attribute]
+
+ // a comment in a block
+ the_value
+ }
+}
+```
+
+Avoid writing comments on the same line as the braces.
+
+An empty block should be written as `{}`.
+
+A block may be written on a single line if:
+
+* it is either used in expression position (not statement position) or is an
+ unsafe block in statement position
+* contains a single-line expression and no statements
+* contains no comments
+
+A single line block should have spaces after the opening brace and before the
+closing brace.
+
+Examples:
+
+```rust
+fn main() {
+ // Single line
+ let _ = { a_call() };
+ let _ = unsafe { a_call() };
+
+ // Not allowed on one line
+ // Statement position.
+ {
+ a_call()
+ }
+
+ // Contains a statement
+ let _ = {
+ a_call();
+ };
+ unsafe {
+ a_call();
+ }
+
+ // Contains a comment
+ let _ = {
+ // A comment
+ };
+ let _ = {
+ // A comment
+ a_call()
+ };
+
+ // Multiple lines
+ let _ = {
+ a_call();
+ another_call()
+ };
+ let _ = {
+ a_call(
+ an_argument,
+ another_arg,
+ )
+ };
+}
+```
+
+
+### Closures
+
+Don't put any extra spaces before the first `|` (unless the closure is prefixed
+by `move`); put a space between the second `|` and the expression of the
+closure. Between the `|`s, you should use function definition syntax, however,
+elide types where possible.
+
+Use closures without the enclosing `{}`, if possible. Add the `{}` when you have
+a return type, when there are statements, there are comments in the body, or the
+body expression spans multiple lines and is a control-flow expression. If using
+braces, follow the rules above for blocks. Examples:
+
+```rust
+|arg1, arg2| expr
+
+move |arg1: i32, arg2: i32| -> i32 {
+ expr1;
+ expr2
+}
+
+|| Foo {
+ field1,
+ field2: 0,
+}
+
+|| {
+ if true {
+ blah
+ } else {
+ boo
+ }
+}
+
+|x| unsafe {
+ expr
+}
+```
+
+
+### Struct literals
+
+If a struct literal is *small* it may be formatted on a single line. If not,
+each field should be on it's own, block-indented line. There should be a
+trailing comma in the multi-line form only. There should be a space after the
+colon only.
+
+There should be a space before the opening brace. In the single-line form there
+should be spaces after the opening brace and before the closing brace.
+
+```rust
+Foo { field1, field2: 0 }
+let f = Foo {
+ field1,
+ field2: an_expr,
+};
+```
+
+Functional record update syntax is treated like a field, but it must never have
+a trailing comma. There should be no space after `..`.
+
+let f = Foo {
+ field1,
+ ..an_expr
+};
+
+
+### Tuple literals
+
+Use a single-line form where possible. There should not be spaces around the
+parentheses. Where a single-line form is not possible, each element of the tuple
+should be on its own block-indented line and there should be a trailing comma.
+
+```rust
+(a, b, c)
+
+let x = (
+ a_long_expr,
+ another_very_long_expr,
+);
+```
+
+
+### Tuple struct literals
+
+There should be no space between the identifier and the opening parenthesis.
+Otherwise, follow the rules for tuple literals, e.g., `Foo(a, b)`.
+
+
+### Enum literals
+
+Follow the formatting rules for the various struct literals. Prefer using the
+name of the enum as a qualifying name, unless the enum is in the prelude. E.g.,
+
+```rust
+Foo::Bar(a, b)
+Foo::Baz {
+ field1,
+ field2: 1001,
+}
+Ok(an_expr)
+```
+
+
+### Array literals
+
+For simple array literals, avoid line breaking, no spaces around square
+brackets, contents of the array should be separated by commas and spaces. If
+using the repeating initialiser, there should be a space after the semicolon
+only. Apply the same rules if using the `vec!` or similar macros (always use
+square brackets here). Examples:
+
+```rust
+fn main() {
+ [1, 2, 3];
+ vec![a, b, c, d];
+ let a = [42; 10];
+}
+```
+
+If a line must be broken, prefer breaking only after the `;`, if possible.
+Otherwise, follow the rules below for function calls. In any case, the contents
+of the initialiser should be block indented and there should be line breaks
+after the opening bracket and before the closing bracket:
+
+```rust
+fn main() {
+ [
+ a_long_expression();
+ 1234567890
+ ]
+ let x = [
+ an_expression,
+ another_expression,
+ a_third_expression,
+ ];
+}
+```
+
+
+### Array accesses, indexing, and slicing.
+
+No spaces around the square brackets, avoid breaking lines if possible, never
+break a line between the target expression and the opening bracket. If the
+indexing expression covers multiple lines, then it should be block indented and
+there should be newlines after the opening brackets and before the closing
+bracket. However, this should be avoided where possible.
+
+Examples:
+
+```rust
+fn main() {
+ foo[42];
+ &foo[..10];
+ bar[0..100];
+ foo[4 + 5 / bar];
+ a_long_target[
+ a_long_indexing_expression
+ ];
+}
+```
+
+### Unary operations
+
+Do not include a space between a unary op and its operand (i.e., `!x`, not
+`! x`). However, there must be a space after `&mut`. Avoid line-breaking
+between a unary operator and its operand.
+
+### Binary operations
+
+Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=`
+and other assignment operators such as `+=` or `*=`).
+
+For comparison operators, because for `T op U`, `&T op &U` is also implemented:
+if you have `t: &T`, and `u: U`, prefer `*t op u` to `t op &u`. In general,
+within expressions, prefer dereferencing to taking references.
+
+Use parentheses liberally, do not necessarily elide them due to precedence.
+Tools should not automatically insert or remove parentheses. Do not use spaces
+to indicate precedence.
+
+If line-breaking, put the operator on a new line and block indent. Put each
+sub-expression on its own line. E.g.,
+
+```rust
+foo_bar
+ + bar
+ + baz
+ + qux
+ + whatever
+```
+
+Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
+than at other binary operators.
+
+### Control flow
+
+Do not include extraneous parentheses for `if` and `while` expressions.
+
+```rust
+if true {
+}
+```
+
+is better than
+
+```rust
+if (true) {
+}
+```
+
+Do include extraneous parentheses if it makes an arithmetic or logic expression
+easier to understand (`(x * 15) + (y * 20)` is fine)
+
+### Function calls
+
+Do not put a space between the function name, and the opening parenthesis.
+
+Do not put a space between an argument, and the comma which follows.
+
+Do put a space between an argument, and the comma which precedes it.
+
+Prefer not to break a line in the callee expression.
+
+#### Single-line calls
+
+Do not put a space between the function name and open paren, between the open
+paren and the first argument, or between the last argument and the close paren.
+
+Do not put a comma after the last argument.
+
+```rust
+foo(x, y, z)
+```
+
+#### Multi-line calls
+
+If the function call is not *small*, it would otherwise over-run the max width,
+or any argument or the callee is multi-line, then the call should be formatted
+across multiple lines. In this case, each argument should be on it's own block-
+indented line, there should be a newline after the opening parenthesis and
+before the closing parenthesis, and there should be a trailing comma. E.g.,
+
+```rust
+a_function_call(
+ arg1,
+ a_nested_call(a, b),
+)
+```
+
+
+### Method calls
+
+Follow the function rules for calling.
+
+Do not put any spaces around the `.`.
+
+```rust
+x.foo().bar().baz(x, y, z);
+```
+
+
+### Macro uses
+
+Macros which can be parsed like other constructs should be formatted like those
+constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a
+function call (ignoring the `!`), therefore it should be formatted following the
+rules for function calls.
+
+#### Special case macros
+
+Macros which take a format string and where all other arguments are *small* may
+be formatted with arguments before and after the format string on a single line
+and the format string on its own line, rather than putting each argument on its
+own line. For example,
+
+```rust
+println!(
+ "Hello {} and {}",
+ name1, name2,
+);
+
+assert_eq!(
+ x, y,
+ "x and y were not equal, see {}",
+ reason,
+);
+```
+
+
+### Casts (`as`)
+
+Put spaces before and after `as`:
+
+```rust
+let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char;
+```
+
+
+### Chains of fields and method calls
+
+A chain is a sequence of field accesses and/or method calls. A chain may also
+include the try operator ('?'). E.g., `a.b.c().d` or `foo?.bar().baz?`.
+
+Prefer formatting on one line if possible, and the chain is *small*. If
+formatting on multiple lines, each field access or method call in the chain
+should be on its own line with the line-break before the `.` and after any `?`.
+Each line should be block-indented. E.g.,
+
+```rust
+let foo = bar
+ .baz?
+ .qux();
+```
+
+If the length of the last line of the first element plus its indentation is
+less than or equal to the indentation of the second line (and there is space),
+then combine the first and second lines, e.g.,
+
+```rust
+x.baz?
+ .qux()
+
+let foo = x
+ .baz?
+ .qux();
+
+foo(
+ expr1,
+ expr2,
+).baz?
+ .qux();
+```
+
+#### Multi-line elements
+
+If any element in a chain is formatted across multiple lines, then that element
+and any later elements must be on their own line. Earlier elements may be kept
+on a single line. E.g.,
+
+```rust
+a.b.c()?.d
+ .foo(
+ an_expr,
+ another_expr,
+ )
+ .bar
+ .baz
+```
+
+Note there is block indent due to the chain and the function call in the above
+example.
+
+Prefer formatting the whole chain in multi-line style and each element on one
+line, rather than putting some elements on multiple lines and some on a single
+line, e.g.,
+
+```rust
+// Better
+self.pre_comment
+ .as_ref()
+ .map_or(false, |comment| comment.starts_with("//"))
+
+// Worse
+self.pre_comment.as_ref().map_or(
+ false,
+ |comment| comment.starts_with("//"),
+)
+```
+
+### Control flow expressions
+
+This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for`
+expressions.
+
+The keyword, any initial clauses, and the opening brace of the block should be
+on a single line. The usual rules for [block formatting](#blocks) should be
+applied to the block.
+
+If there is an `else` component, then the closing brace, `else`, any following
+clause, and the opening brace should all be on the same line. There should be a
+single space before and after the `else` keyword. For example:
+
+```rust
+if ... {
+ ...
+} else {
+ ...
+}
+
+if let ... {
+ ...
+} else if ... {
+ ...
+} else {
+ ...
+}
+```
+
+If the control line needs to be broken, then prefer to break before the `=` in
+`* let` expressions and before `in` in a `for` expression; the following line
+should be block indented. If the control line is broken for any reason, then the
+opening brace should be on its own line and not indented. Examples:
+
+```rust
+while let Some(foo)
+ = a_long_expression
+{
+ ...
+}
+
+for foo
+ in a_long_expression
+{
+ ...
+}
+
+if a_long_expression
+ && another_long_expression
+ || a_third_long_expression
+{
+ ...
+}
+```
+
+Where the initial clause is multi-lined and ends with one or more closing
+parentheses, square brackets, or braces, and there is nothing else on that line,
+and that line is not indented beyond the indent on the first line of the control
+flow expression, then the opening brace of the block should be put on the same
+line with a preceding space. For example:
+
+```rust
+if !self.config.file_lines().intersects(
+ &self.codemap.lookup_line_range(
+ stmt.span,
+ ),
+) { // Opening brace on same line as initial clause.
+ ...
+}
+```
+
+
+#### Single line `if else`
+
+Formatters may place an `if else` or `if let else` on a single line if it occurs
+in expression context (i.e., is not a standalone statement), it contains a
+single `else` clause, and is *small*. For example:
+
+```rust
+let y = if x { 0 } else { 1 };
+
+// Examples that must be multi-line.
+let y = if something_very_long {
+ not_small
+} else {
+ also_not_small
+};
+
+if x {
+ 0
+} else {
+ 1
+}
+```
+
+
+### Match
+
+Prefer not to line-break inside the discriminant expression. There must always
+be a line break after the opening brace and before the closing brace. The match
+arms must be block indented once:
+
+```rust
+match foo {
+ // arms
+}
+
+let x = match foo.bar.baz() {
+ // arms
+};
+```
+
+Use a trailing comma for a match arm if and only if not using a block.
+
+Never start a match arm pattern with `|`, e.g.,
+
+```rust
+match foo {
+ // Don't do this.
+ | foo => bar,
+ // Or this.
+ | a_very_long_pattern
+ | another_pattern
+ | yet_another_pattern
+ | a_forth_pattern => {
+ ...
+ }
+}
+```
+
+Prefer
+
+
+```rust
+match foo {
+ foo => bar,
+ a_very_long_pattern
+ | another_pattern
+ | yet_another_pattern
+ | a_forth_pattern => {
+ ...
+ }
+}
+```
+
+Avoid splitting the left-hand side (before the `=>`) of a match arm where
+possible. If the right-hand side of the match arm is kept on the same line,
+never use a block (unless the block is empty).
+
+If the right-hand side consists of multiple statements or has line comments or
+the start of the line cannot be fit on the same line as the left-hand side, use
+a block.
+
+The body of a block arm should be block indented once.
+
+Examples:
+
+```rust
+match foo {
+ foo => bar,
+ a_very_long_patten | another_pattern if an_expression() => {
+ no_room_for_this_expression()
+ }
+ foo => {
+ // A comment.
+ an_expression()
+ }
+ foo => {
+ let a = statement();
+ an_expression()
+ }
+ bar => {}
+ // Trailing comma on last item.
+ foo => bar,
+}
+```
+
+If the body is a single expression with no line comments and not a control flow
+expression, then it may be started on the same line as the right-hand side. If
+not, then it must be in a block. Example,
+
+```rust
+match foo {
+ // A combinable expression.
+ foo => a_function_call(another_call(
+ argument1,
+ argument2,
+ )),
+ // A non-combinable expression
+ bar => {
+ a_function_call(
+ another_call(
+ argument1,
+ argument2,
+ ),
+ another_argument,
+ )
+ }
+}
+```
+
+#### Line-breaking
+
+Where it is possible to use a block form on the right-hand side and avoid
+breaking the left-hand side, do that. E.g.
+
+```rust
+ // Assuming the following line does done fit in the max width
+ a_very_long_pattern | another_pattern => ALongStructName {
+ ...
+ },
+ // Prefer this
+ a_very_long_pattern | another_pattern => {
+ ALongStructName {
+ ...
+ }
+ }
+ // To splitting the pattern.
+```
+
+Never break after `=>` without using the block form of the body.
+
+If the left-hand side must be split and there is an `if` clause, break before
+the `if` and block indent. In this case, always use a block body and start the
+body on a new line:
+
+```rust
+ a_very_long_pattern | another_pattern
+ if expr =>
+ {
+ ...
+ }
+```
+
+If required to break the pattern, put each clause of the pattern on its own
+line with no additional indent, breaking before the `|`. If there is an `if`
+clause, then you must use the above form:
+
+```rust
+ a_very_long_pattern
+ | another_pattern
+ | yet_another_pattern
+ | a_forth_pattern => {
+ ...
+ }
+ a_very_long_pattern
+ | another_pattern
+ | yet_another_pattern
+ | a_forth_pattern
+ if expr =>
+ {
+ ...
+ }
+```
+
+If the pattern is multi-line, and the last line is less wide than the indent, do
+not put the `if` clause on a newline. E.g.,
+
+```rust
+ Token::Dimension {
+ value,
+ ref unit,
+ ..
+ } if num_context.is_ok(context.parsing_mode, value) => {
+ ...
+ }
+```
+
+If every clause in a pattern is *small*, but does not fit on one line, then the
+pattern may be formatted across multiple lines with as many clauses per line as
+possible. Again break before a `|`:
+
+```rust
+ foo | bar | baz
+ | qux => {
+ ...
+ }
+```
+
+We define a pattern clause to be *small* if it matches the following grammar:
+
+```
+[small, ntp]:
+ - single token
+ - `&[single-line, ntp]`
+
+[small]:
+ - `[small, ntp]`
+ - unary tuple constructor `([small, ntp])`
+ - `&[small]`
+```
+
+E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
+
+
+### Combinable expressions
+
+Where a function call has a single argument, and that argument is formatted
+across multiple-lines, the outer call may be formatted as if it were a single-
+line call. The same combining behaviour may be applied to any similar
+expressions which have multi-line, block-indented lists of sub-expressions
+delimited by parentheses (e.g., macros or tuple struct literals). E.g.,
+
+```rust
+foo(bar(
+ an_expr,
+ another_expr,
+))
+
+let x = foo(Bar {
+ field: whatever,
+});
+
+foo(|param| {
+ action();
+ foo(param)
+})
+```
+
+Such behaviour should extend recursively, however, tools may choose to limit the
+depth of nesting.
+
+Only where the multi-line sub-expression is a closure with an explicit block,
+this combining behaviour may be used where there are other arguments, as long as
+all the arguments and the first line of the closure fit on the first line, the
+closure is the last argument, and there is only one closure argument:
+
+```rust
+foo(first_arg, x, |param| {
+ action();
+ foo(param)
+})
+```
+
+
+### Ranges
+
+Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`.
+
+When writing a range with both upper and lower bounds, if the line must be
+broken, break before the range operator and block indent the second line:
+
+```rust
+a_long_expression
+ ..another_long_expression
+```
+
+For the sake of indicating precedence, we recommend that if either bound is a
+compound expression, then use parentheses around it, e.g., `..(x + 1)`,
+`(x.f)..(x.f.len())`, or `0..(x - 10)`.
+
+
+### Hexadecimal literals
+
+Hexadecimal literals may use upper- or lower-case letters, but they must not be
+mixed within the same literal. Projects should use the same case for all
+literals, but we do not make a recommendation for either lower- or upper-case.
+Tools should have an option to convert mixed case literals to upper-case, and
+may have an option to convert all literals to either lower- or upper-case.
+
+
+## Patterns
+
+Patterns should be formatted like their corresponding expressions. See the
+section on `match` for additional formatting for patterns in match arms.