ruff/crates
Charlie Marsh 68f605e80a
Fix `WithItem` ranges for parenthesized, non-`as` items (#6782)
## Summary

This PR attempts to address a problem in the parser related to the
range's of `WithItem` nodes in certain contexts -- specifically,
`WithItem` nodes in parentheses that do not have an `as` token after
them.

For example,
[here](https://play.ruff.rs/71be2d0b-2a04-4c7e-9082-e72bff152679):

```python
with (a, b):
    pass
```

The range of the `WithItem` `a` is set to the range of `(a, b)`, as is
the range of the `WithItem` `b`. In other words, when we have this kind
of sequence, we use the range of the entire parenthesized context,
rather than the ranges of the items themselves.

Note that this also applies to cases
[like](https://play.ruff.rs/c551e8e9-c3db-4b74-8cc6-7c4e3bf3713a):

```python
with (a, b, c as d):
    pass
```

You can see the issue in the parser here:

```rust
#[inline]
WithItemsNoAs: Vec<ast::WithItem> = {
    <location:@L> <all:OneOrMore<Test<"all">>> <end_location:@R> => {
        all.into_iter().map(|context_expr| ast::WithItem { context_expr, optional_vars: None, range: (location..end_location).into() }).collect()
    },
}
```

Fixing this issue is... very tricky. The naive approach is to use the
range of the `context_expr` as the range for the `WithItem`, but that
range will be incorrect when the `context_expr` is itself parenthesized.
For example, _that_ solution would fail here, since the range of the
first `WithItem` would be that of `a`, rather than `(a)`:

```python
with ((a), b):
    pass
```

The `with` parsing in general is highly precarious due to ambiguities in
the grammar. Changing it in _any_ way seems to lead to an ambiguous
grammar that LALRPOP fails to translate. Consensus seems to be that we
don't really understand _why_ the current grammar works (i.e., _how_ it
avoids these ambiguities as-is).

The solution implemented here is to avoid changing the grammar itself,
and instead change the shape of the nodes returned by various rules in
the grammar. Specifically, everywhere that we return `Expr`, we instead
return `ParenthesizedExpr`, which includes a parenthesized range and the
underlying `Expr` itself. (If an `Expr` isn't parenthesized, the ranges
will be equivalent.) In `WithItemsNoAs`, we can then use the
parenthesized range as the range for the `WithItem`.
2023-08-31 16:21:29 +01:00
..
flake8_to_ruff Unify line size settings between ruff and the formatter (#6873) 2023-08-28 06:44:56 +00:00
ruff Add hidden `--preview` / `--no-preview` options to `ruff check` (#7009) 2023-08-31 09:51:59 -05:00
ruff_benchmark Add unicode benchmark (#7002) 2023-08-30 09:57:57 +02:00
ruff_cache Error on zero tab width (#6429) 2023-08-08 16:51:37 -04:00
ruff_cli Add hidden `--preview` / `--no-preview` options to `ruff check` (#7009) 2023-08-31 09:51:59 -05:00
ruff_dev Show changed files (#7003) 2023-08-30 06:47:45 +00:00
ruff_diagnostics Implement `Ranged` on more structs (#6921) 2023-08-27 19:03:08 +00:00
ruff_formatter Update `dynamic_text` builder doc comment (#6978) 2023-08-29 16:29:11 +02:00
ruff_index Add unreachable code rule (#5384) 2023-07-04 14:27:23 +00:00
ruff_macros Move `Configuration` to `ruff_workspace` crate (#6920) 2023-08-28 06:21:35 +00:00
ruff_python_ast Fix `WithItem` ranges for parenthesized, non-`as` items (#6782) 2023-08-31 16:21:29 +01:00
ruff_python_codegen Make `Parameters` an optional field on `ExprLambda` (#6669) 2023-08-18 15:34:54 +00:00
ruff_python_formatter Allow `tab_width` to be configable (#7016) 2023-08-31 07:40:03 +00:00
ruff_python_index Move `Ranged` into `ruff_text_size` (#6919) 2023-08-27 14:12:51 -04:00
ruff_python_literal Avoid parsing other parts of a format specification if replacements are present (#6858) 2023-08-25 17:42:57 +00:00
ruff_python_parser Fix `WithItem` ranges for parenthesized, non-`as` items (#6782) 2023-08-31 16:21:29 +01:00
ruff_python_resolver Replace `.map_or(false, $closure)` with `.is_some_and(closure)` (#6244) 2023-08-01 19:29:42 +02:00
ruff_python_semantic Move `refurb/helpers` utils to `ruff_python_semantic` for broader use (#6990) 2023-08-29 14:45:09 -04:00
ruff_python_stdlib Add TOML files to `SourceType` (#6929) 2023-08-28 15:01:48 +00:00
ruff_python_trivia Implement `Ranged` on more structs (#6921) 2023-08-27 19:03:08 +00:00
ruff_shrinking Move `Ranged` into `ruff_text_size` (#6919) 2023-08-27 14:12:51 -04:00
ruff_source_file Allow `Locator#slice` to take `Ranged` (#6922) 2023-08-28 11:08:39 -04:00
ruff_text_size Unify line size settings between ruff and the formatter (#6873) 2023-08-28 06:44:56 +00:00
ruff_wasm Add hidden `--preview` / `--no-preview` options to `ruff check` (#7009) 2023-08-31 09:51:59 -05:00
ruff_workspace Add hidden `--preview` / `--no-preview` options to `ruff check` (#7009) 2023-08-31 09:51:59 -05:00