Llogiq on stuff

An unmatched left parenthesis...

...creates an unresolved tension that will stay with you all day.

(relevant XKCD)

Consider the following example:

fn main() {
    let x = {
    //Oops, forgot the closing }
    let y = {
    }
}

Rust shows the end of file and asks

help: did you mean to close this delimiter?
 --> brackets.rs:1:11
  |
1 | fn main() {
  |           ^

No, I meant to close the delimiter on line 2! However, because Rust doesn’t take indentation into account, it cannot know that.

Let’s assume for the moment we had an indentation-aware Rust; it would simply keep track of the indentation level of the first non-whitespace character of a line for each delimiter on that line.

Now we could search each indentation level for delimiters. In our code above, there are the levels 0 with the bracket order {, } and 4 (spaces) with the bracket order {, {, }. Seeing that the latter has an unclosed bracket, we could correctly report the unclosed bracket on line 2.

The beauty of this is that we don’t care if the coder puts brackets on the beginning or end of the line, because we only care about the indentation on the first non-whitespace character.

There is a small wrinkle in that the current defaults of rustfmt may sometimes lead to some rightwards drift that would negate the benefits of this scheme. Consider the following snippet:

let x = frobnicate(Foo {
                        bar: vec![1, 2, 3],
                        baz: true,
                   });

In this case the indentation of the closing { delimiter would coincide with the horizontal position after the outer open ( delimiter. The idea is to extend our algorithm to have a set of possible horizontal positions for each closing delimiter:

  • if the closing delimiter is on the same line, ignore both
  • if there is only one opening delimiter on that line, the set only contains the horizontal position of the first non-whitespace character of that line
  • otherwise we need to match the position of the first non-whitespace character of the line the closing delimiter is in and match either the start of the line or the position at or directly after any of the opening delimiters

Perhaps by eliminating already matched delimiters, we can reduce the set of potential matches even more.

Yes, this gets pretty messy, and there are probably corner cases I haven’t thought about, but if it works, we’ll have much better reporting for that particular error.


Discuss on /r/rust or rust-users.