Opened 2 years ago

Closed 20 months ago

#7783 closed bug (fixed)

MultiWayIf should start a new layout

Reported by: exbb2 Owned by:
Priority: normal Milestone: 7.8.1
Component: Compiler (Parser) Version: 7.6.2
Keywords: Cc: simonmar
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: #4359 Differential Revisions:

Description (last modified by simonpj)

Currently, MultiWayIf doesn't fully replace old case () of _ form. This outputs 3:

{-# LANGUAGE MultiWayIf #-}
x = case () of
    _ | False -> case () of
                _ | False -> 1
                  | False -> 2
      | True -> 3

main = print (x :: Int)

but this errors out:

{-# LANGUAGE MultiWayIf #-}
x = if | False -> if | False -> 1
                     | False -> 2
       | True -> 3

main = print (x :: Int)

because it parses like this:

x = if | False -> if | False -> 1
                     | False -> 2
                     | True -> 3

Every other syntax introducing guards starts a layout; MultiWayIf's current behavior leads to subtle logic bugs for those unaware that MultiWayIf is special.

Change History (10)

comment:1 Changed 2 years ago by simonpj

  • Description modified (diff)
  • difficulty set to Unknown

comment:2 Changed 2 years ago by simonpj

  • Description modified (diff)

comment:3 Changed 2 years ago by simonpj

Good point. I think you expectation is that, with layout braces inserted, it'd look like this:

x = if { | False -> if { | False -> 1
                         | False -> 2
                       }
         | True -> 3
       }

No semicolons (there are no semicolons between the guards of a multi-way case. Now it is quite unambiguous, even if it was written all on one line.

This looks reasonable to me, if someone would like to try it.

Simon

comment:4 Changed 2 years ago by igloo

See also the last few comments of #4359

comment:5 Changed 2 years ago by igloo

  • Component changed from Compiler to Compiler (Parser)
  • Milestone set to 7.8.1

comment:6 Changed 20 months ago by Simon Marlow <marlowsd@…>

In aab65608f9a26990b2c5083e4b65b9d1f6c9b48a/ghc:

Add layout to MultiWayIf (#7783)

This makes it possible to write

x = if | False -> if | False -> 1
                     | False -> 2
       | True -> 3

Layout normally inserts semicolons between declarations at the same
indentation level, so I added optional semicolons to the syntax for
guards in MultiWayIf syntax.  This is a bit of a hack, but the
alternative (a special kind of layout that doesn't insert semicolons)
seemed worse, or at least equally bad.

comment:7 Changed 20 months ago by simonmar

  • Resolution set to fixed
  • Status changed from new to closed

comment:8 Changed 20 months ago by simonpj

  • Cc simonmar added
  • Resolution fixed deleted
  • Status changed from closed to new

Simon, would it be possible to document the design in the user manual? For example, is it now possible to explain it by saying that a multi-way 'if' is a layout herald, so that your example behaves thus?

 x = if { | False -> if { | False -> 1  
                        ; | False -> 2 }

        ; | True -> 3 }

Am I allowed to put the braces and semicolons in myself? Does the close brace get put in just before the first token to the left of the initial "|"?

Thanks

Simon

comment:9 Changed 20 months ago by Simon Marlow <marlowsd@…>

In d2013e85976cccde6c915211f8bcc26f2dc93e33/ghc:

docs for new layout behaviour with MultiWayIf (#7783)

comment:10 Changed 20 months ago by simonmar

  • Resolution set to fixed
  • Status changed from new to closed
Note: See TracTickets for help on using tickets.