[GHC] #15272: Handle implied flags more intuitively

GHC ghc-devs at haskell.org
Thu Jun 14 14:31:09 UTC 2018


#15272: Handle implied flags more intuitively
-------------------------------------+-------------------------------------
           Reporter:  tdammers       |             Owner:  (none)
               Type:  feature        |            Status:  new
  request                            |
           Priority:  normal         |         Milestone:  8.6.1
          Component:  Compiler       |           Version:  8.4.3
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  Other
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:  #14963
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 Many flags in GHC imply other flags. For example, enabling `-fdefer-type-
 errors` also enables `-fdefer-type-holes` and `-fdefer-out-of-scope-
 variables`:

 {{{
 GHCi, version 8.4.2: http://www.haskell.org/ghc/  :? for help
 Prelude> :set
 options currently set: none.
 base language is: Haskell2010
 with the following modifiers:
   -XNoDatatypeContexts
   -XNondecreasingIndentation
 GHCi-specific dynamic flag settings:
 other dynamic, non-language, flag settings:
   -fignore-optim-changes
   -fignore-hpc-changes
   -fimplicit-import-qualified
 warning settings:
 Prelude> :set -fdefer-type
 -fdefer-type-errors  -fdefer-typed-holes
 Prelude> :set -fdefer-type-errors
 Prelude> :set
 options currently set: none.
 base language is: Haskell2010
 with the following modifiers:
   -XNoDatatypeContexts
   -XNondecreasingIndentation
 GHCi-specific dynamic flag settings:
 other dynamic, non-language, flag settings:
   -fdefer-type-errors
   -fdefer-typed-holes
   -fdefer-out-of-scope-variables
   -fignore-optim-changes
   -fignore-hpc-changes
   -fimplicit-import-qualified
 warning settings:
 }}}

 This is fine.

 Disabling previously enabled flags does not disable the implied flags:
 `-fno-defer-type-errors` does not also set `-fno-defer-type-holes` and
 `-fno-defer-out-of-scope-variables`. This is also fine in principle;
 otherwise, setting `-fdefer-type-holes -fno-defer-type-errors` would do
 the unintuitive thing of setting neither flag.

 But it does lead to unintuitive behavior when the implied flags have never
 been touched explicitly: setting `-fdefer-type-errors`, and then later
 `-fno-defer-type-errors`, leaves `-fdefer-type-holes` and `-fdefer-out-of-
 scope-variables` set, even though the user never asked for them:

 {{{
 Prelude> :set -fdefer-type-errors
 Prelude> :set
 options currently set: none.
 base language is: Haskell2010
 with the following modifiers:
   -XNoDatatypeContexts
   -XNondecreasingIndentation
 GHCi-specific dynamic flag settings:
 other dynamic, non-language, flag settings:
   -fdefer-type-errors
   -fdefer-typed-holes
   -fdefer-out-of-scope-variables
   -fignore-optim-changes
   -fignore-hpc-changes
   -fimplicit-import-qualified
 warning settings:
 Prelude> :set -fno-defer-type-errors
 Prelude> :set
 options currently set: none.
 base language is: Haskell2010
 with the following modifiers:
   -XNoDatatypeContexts
   -XNondecreasingIndentation
 GHCi-specific dynamic flag settings:
 other dynamic, non-language, flag settings:
   -fdefer-typed-holes                <- These two are
   -fdefer-out-of-scope-variables     <- unexpected!
   -fignore-optim-changes
   -fignore-hpc-changes
   -fimplicit-import-qualified
 warning settings:
 }}}

 So we have a conundrum: when unsetting a flag, we may or may not need to
 unset the options it implies - neither is always correct, so in order to
 figure out what to do, we need to know *why* the flag was set. But it's
 even worse: if we have a flag X, and two other flags A and B, both of
 which imply X, and we first set A and B, and then unset B, we would have
 to keep X set, because otherwise we would break A. But if we then also
 unset A, we would have to also unset X. Tracking which option implicitly
 enabled which other option, and correctly resolving that, seems like
 terribly messy business. So I propose a different solution:

 1. Maintain one set of `DynFlags` that holds only those flags that were
 requested explicitly. Setting `-fdefer-type-errors` would only set
 `Opt_DeferTypeErrors` in this set, but none of the implied flags; and
 `-fno-defer-type-errors` would simply unset `Opt_DeferTypeErrors`.
 2. Maintain another set of `DynFlags` that holds the effective flags: we
 can always calculate these based on the explicit flags. We could either do
 this on the fly, just before running the actual compilation / evaluation,
 or we could keep the data structure around and only update it when the
 explicit flags have changed.

 This way, setting and unsetting flags will always do the right thing, and
 we don't throw away the information about which flags were set explicitly.


 This is probably more relevant in GHCi, because in plain GHC, one would
 typically just set all the needed flags at once and then never change them
 again until the next run; but in GHCi, modifying compiler flags between
 evaluations is a common thing to do.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15272>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list