09704869

Give every rule a directory, and every fact its own module

Two commits. The first gives every fact its own module; the second gives every
rule a directory, which is what the module layout was actually missing.

## A rule is a directory

`Rule.hs` is the check, and beside it goes whatever only that rule needs:
`Fact.hs` for a fact nothing else reads, `Extract.hs` for the reading of the
parse tree that produces it.

```
Hopinion/Check/Hs/NoSemigroupOnText/
    Fact.hs      ConcatChain, ConcatOperand          44 lines
    Extract.hs   concatChainsOf, runs, operands     104 lines
    Rule.hs      the check                           30 lines
Hopinion/Check/Comment/BareTodo/Rule.hs
Hopinion/Check/Hs/NoCustomShowRead/Rule.hs
Hopinion/Check/Hs/NoFilePath/Rule.hs
Hopinion/Check/Package/GenValidInGenPackage/Rule.hs
Hopinion/Check/Project/GenValidSpecPerGenValid/Rule.hs
```

Five of the six rules need neither a fact nor an extraction and are the one
module, in a directory of their own so the shape is the same for all of them.

A rule's cost is now readable off the rule. `HsNoSemigroupOnText` is 178 lines,
and the 104 of parse-tree reading was invisible while it sat in
`Hopinion.Extract`. That number is what M5 has to stop a later expression rule
from paying again.

## What no rule owns

`Hopinion.Extract.Ghc`: a GHC span as a fact's span, the declaration a span
falls inside, and taking an expression apart far enough to see what it is
(`peelExpr`, `infixOperands`, `spineOf`). A rule's own extraction asks that for
the parts it shares, rather than importing `Hopinion.Extract`, which would have
made the two import each other. It is also where the walking M5 plans to
centralise belongs.

## Facts, one per module, no re-exports

`Hopinion.Facts` was one module holding fourteen types and re-exporting four
more, so nothing said which of them it needed. Each type now lives in the module
that gives it meaning, and no module re-exports another. This costs import
lines rather than saving them, and that is the trade: what each line says is now
true.

Three dependencies nobody could see, all now said outright:

- **`Hopinion.Compiled`** uses `CompiledModule` and `DeclaredInstance`, which
  reached it through `Facts` re-exporting `Hopinion.Hie`. It imports `Hie`
  directly now.
- **`GenValidSpecPerGenValid`** uses `declaredInstanceType` and
  `declaredInstanceClass`, field accessors it only ever saw through two layers
  of re-export. Same fix.
- **`validity-aeson`** was a dependency of the library only because `Facts`
  imported `Data.Validity.Aeson ()` for orphan instances no `Validity` instance
  here needs. The import alone satisfied `-Wunused-packages`; removing it took
  the dependency with it.

`NameFact` is in `Facts.Occurrence`, not `Facts.Name` where a name-shaped thing
would seem to belong: it carries a `Span` and a `ScopeKey`, and `Facts.Place`
already imports `Facts.Name`, so that would have closed a cycle.

## The one edge left

`ModuleContext` still carries a field per module-level fact, so it imports the
fact of any rule that brings one. That is the only edge pointing from the middle
of the tool at a rule, and it is why the rule directory holds the fact rather
than the fact holding the rule.

No behaviour change: no type, field, constructor or function was renamed, added
or removed. `nix flake check` passes.

Total

1h23m37s

Created Started Finished

Time to Start Worker time Duration Time to finish Idle
Config 7m29s 0s 0s 7m30s 7m29s
Eval 9m18s 17s 17s 9m36s 1m48s
Build 9m31s 11s 1h21m36s 1h31m07s 1h21m18s
Suite 7m29s 30s 1h23m37s 1h31m07s 1h30m36s

Timeline

Config Eval Build Compressed gap
0s7m30s9m20s9m30s1h31m