303db594

By: Tom Sydney Kerckhove <syd@cs-syd.eu>

A rule that sees a whole package

Stacked on the suppression PR. Adds HsGenValidInGenPackage from
haskell-style.md, which is the first rule that cannot answer from one module,
and with it the fact store that lets a rule see further.

A database rather than a file of records, because what a rule above the module
level does with facts is join them. One table per fact, owned by the rule that
writes it, so a rule brings its own schema the way it brings its own check. The
envelope never learns what is in that table, which is why adding a rule adds no
case to it: a package rule is a migration, what it writes out of one module,
and the query it answers with.

A fact is a row rather than a keyed entry. Two instances in one module are two
facts, and there is nothing to key them on that is not invented.

The rule's constructor is also its level, so nothing can disagree with it, and
each level judges exactly the suppressions naming its own rules. That is what
keeps unused-suppression detection sound without a global pass over the
repository.

Still one process, so the store has nowhere to go and nothing crosses a process
boundary yet. Nothing reads what the compiler wrote down. weeder removed seven
store queries on the way in that only a project rule would want, and the
package check's signature does not take the compiler's answers because this
rule has no use for them.

Where a store lives is a type rather than a path, because SQLite's word for
having no file at all is a file name that is not one, and a magic string is a
state a type can rule out. ChoicesFileError carries the file beside what is
wrong with it, so the error stays typed until the boundary that turns it into
something a report holds.

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 10m40s 1s 1s 10m41s 10m40s
Eval 13m55s 11s 11s 14m06s 3m13s
Build 14m06s 6s 22m46s 36m52s 22m39s
Suite 10m40s 18s 26m11s 36m52s 36m33s

Timeline

0s14m36m50s