Opened 4 years ago

Closed 4 years 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 Rev(s):
Wiki Page:

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 4 years ago by simonpj

Description: modified (diff)
difficulty: Unknown

comment:2 Changed 4 years ago by simonpj

Description: modified (diff)

comment:3 Changed 4 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 4 years ago by igloo

See also the last few comments of #4359

comment:5 Changed 4 years ago by igloo

Component: CompilerCompiler (Parser)
Milestone: 7.8.1

comment:6 Changed 4 years 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 4 years ago by simonmar

Resolution: fixed
Status: newclosed

comment:8 Changed 4 years ago by simonpj

Cc: simonmar added
Resolution: fixed
Status: closednew

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 4 years ago by Simon Marlow <marlowsd@…>

In d2013e85976cccde6c915211f8bcc26f2dc93e33/ghc:

docs for new layout behaviour with MultiWayIf (#7783)

comment:10 Changed 4 years ago by simonmar

Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.