Skip to content

Better handling of leading infix operators in indented code #11959

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

Merged
merged 1 commit into from
Apr 2, 2021

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Mar 31, 2021

@main def Test =
  val x = false
  val y = 1
  val result =
    x
    || y.match
        case 1 => false
        case 3 => false
        case _ => true
    || !x
  assert(result)

In this code, the last || !x was seen as a part of the previous case, so the code was parsed as

@main def Test =
  val x = false
  val y = 1
  val result =
    x
    || y.match
        case 1 => false
        case 3 => false
        case _ => true || !x
  assert(result)

This is highly surprising and unintuitive. The fix will insert an <outdent> token instead
if the leading infix operator is too far to the left. Too far means: (1) left of the current indentation
region, (2) and not to the right of any outer indentation widths.

(2) allows to still parse code like this

if xyz then
    one
  + two
  + three

Here, the width of the indentation region after then is 4, but the + operator is to the right
of the outer indentation width of 0., so the indentation region is not closed. In other words,
we do not close an indentation region if the result would not be legal, since it matches none of
the previous indentation widths.

```code
@main def Test =
  val x = false
  val y = 1
  val result =
    x
    || y.match
        case 1 => false
        case 3 => false
        case _ => true
    || !x
  assert(result)
```
In this code, the last `|| !x` was seen as a part of the previous case, so the code was parsed as
```scala
@main def Test =
  val x = false
  val y = 1
  val result =
    x
    || y.match
        case 1 => false
        case 3 => false
        case _ => true || !x
  assert(result)
```
This is highly surprising and unintuitive. The fix will insert an <outdent> token instead
if the leading infix operator is too far to the left. Too far means: (1) left of the current indentation
region, (2) and not to the right of any outer indentation widths.

(2) allows to still parse code like this
```scala
if xyz then
    one
  + two
  + three
```
Here, the width of the indentation region after `then` is 4, but the `+` operator is to the right
of the outer indentation width of 0., so the indentation region is not closed. In other words,
we do not close an indentation region if the result would not be legal, since it matches none of
the previous indentation widths.
Copy link
Contributor

@liufengyun liufengyun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

+ c
else d
```
is parsed as `if x then a + b + c else d`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following code compiles previously:

class Test:
   if
     5 < 6
   + 3
   then
    println("hello")

But I guess it's fine to reject it after the change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK, in particular since there is no legacy code, since leading infix operators are a Scala 3 thing.

@odersky odersky merged commit 775d881 into scala:master Apr 2, 2021
@odersky odersky deleted the add-indent-after-operator branch April 2, 2021 19:12
@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants