Handle implied flags more intuitively
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:
- Maintain one set of
DynFlags
that holds only those flags that were requested explicitly. Setting-fdefer-type-errors
would only setOpt_DeferTypeErrors
in this set, but none of the implied flags; and-fno-defer-type-errors
would simply unsetOpt_DeferTypeErrors
. - 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.
Trac metadata
Trac field | Value |
---|---|
Version | 8.4.3 |
Type | FeatureRequest |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |