Skip to content

-bloogle-db: Bloogle suggestions in unbound-name errors and typed-hole warnings - #1111

Draft
matx-amy wants to merge 12 commits into
B-Lang-org:mainfrom
MatX-inc:amy/bloogle-db-flag
Draft

matx-amy wants to merge 12 commits into
B-Lang-org:mainfrom
MatX-inc:amy/bloogle-db-flag

Conversation

@matx-amy

@matx-amy matx-amy commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Stacked on #969 and #1110.

Adds a -bloogle-db <db> flag. When it's given, bsc runs bloogle search <db> ... (with bloogle from PATH) for some of its diagnostics and appends the results.

Every unbound-name error (variables, constructors, fields, type constructors, classes, packages) gets the exact-name matches, which mostly answers "which package do I import for this?":

package Q(mkQ) where

mkQ :: Module Empty
mkQ = module
    q <- mkFIFO
    rules
        when True ==> q.enq (0 :: Bit 8)
Error: "Q.bs", line 5, column 9: (T0004)
  Unbound variable `mkFIFO'
  bloogle found these exact name matches:
    FIFO mkFIFO :: (Bits a sa, IsModule m c) => (m (FIFO a))

and it works the same for e.g. an unbound type constructor:

Error: "T.bs", line 3, column 15: (T0007)
  Unbound type constructor `FIFO'
  bloogle found these exact name matches:
    module FIFO
    FIFO data FIFO a

Typed holes (#1110) get the approximate matches from a type search on the inferred type, so the foldr __ 0 v example from that PR becomes:

Warning: "Sum.bs", line 6, column 15: (T0159)
  Typed hole `__' has the inferred type:
    Prelude.Bit 8 -> Prelude.Bit 8 -> Prelude.Bit 8
  bloogle found these approximate matches:
    Prelude min :: (a -> a -> a)
    Prelude max :: (a -> a -> a)
    Prelude (&) :: (a -> a -> a)
    Prelude (^) :: (a -> a -> a)
    Prelude (~^) :: (a -> a -> a)

The database is the one you'd build for Bloogle itself, e.g. bloogle generate bluespec.hoo $BLUESPECDIR/bloogle from the .txt that #969 installs -- so it can include your own libraries too, not just the standard ones. Without the flag nothing changes at all; with it, a missing or failing bloogle just leaves the diagnostics undecorated.

Since the unbound-name errors are raised in several phases (MakeSymTab, kind inference, typecheck, GenSign), the lookup lives in the common reporting funnel, bsWarningsAndErrorsWithContext, rather than at each raise site: setErrorHandleFlags stashes the database path in the ErrorState, and a wrapper (EBloogleMatches) appends the matches to the wrapped message's text while keeping its tag. Unbound type variables, exports, and $tasks are deliberately not looked up, since a library search can't help with those. The tests use a stub bloogle script, so they don't depend on a real install.

Known gap: the type query is the hole's pretty-printed type, so for a BSV file it's in BSV syntax (UInt#(8)), which Bloogle doesn't parse, and those holes get unhelpful approximate matches. Classic holes and all the name lookups are unaffected.

matx-amy and others added 12 commits July 8, 2026 11:59
This adds a new utility, bo2bloogle. This utility reads .bo files and
dumps them in a format that Hoogle can read.

Symbols whose names are not valid Haskell (e.g. $display) currently get
dropped. Field accessors get emitted as e.g. foo instead of (.foo). I'll
be pushing a fork of Hoogle called Bloogle soon -- allowing both of
these in it is a worthwhile long-term goal, but isn't worth it in the
short term.
This is not immediately usable with Bloogle, but needs a

    bloogle generate db.hoo /path/to/inst/lib/bloogle

to produce the database Bloogle uses. Only shipping this avoids a
dependency on Bloogle, but also makes it easier to build a custom
database that includes both the standard library and third-party
libraries.
936's strict-ByteString readBinFile is upstream now; 969's tool still
unpacked to [Word8] (rc3 build-5's twin; outside both typechecked
closures, so only the full build caught it).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019cqQdWKp7jr73GHQYnvhiq
This lets e.g. B-Lang-org#970 use it as well instead of reimplementing it.
`__` is accepted wherever an expression dont-care is accepted (`_` in
Classic, alongside `?` in BSV) and behaves identically, except that the
typechecker emits a warning (T0159) reporting the type inferred for
that position.

The parsers mark the hole with a new UndefKind (UHole) on the CAny
node, and the existing tiExpr case carries it into the resulting CAnyT
unchanged.  After the final substitution has been applied to a
typechecked definition, reportTypedHoles walks the definition, warns
with the resolved type of each hole, and demotes the hole to UDontCare
so no later stage sees UHole.  A hole that escapes the typechecker
anyway (e.g. in a typeclass default clause, whose typechecked form is
currently discarded) is treated as an ordinary dont-care downstream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZAJ5Pt7KQgVWdCJqzJFXX
Classic and BSV holes reporting their inferred types: in a plain
definition, a submodule argument, and a rule body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZAJ5Pt7KQgVWdCJqzJFXX
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ReSvFGvaEoj8mrS76aGaYp
When a bloogle database is named with -bloogle-db, the typechecker's
diagnostics are decorated with results from "bloogle search <db>
<query>" (bloogle is assumed to be on PATH):

  * a typed-hole warning gains the approximate matches from a type
    search on the hole's inferred type;

  * an unbound-variable error gains the results of a name search,
    filtered down to identifiers exactly matching the unbound name.

The searches run in tiDefns, where the accumulated warnings and errors
pass through IO on their way to being reported; a missing or failing
bloogle executable just leaves the diagnostics without suggestions.
With the flag unset, behavior is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZAJ5Pt7KQgVWdCJqzJFXX
The -bloogle-db decorations for a typed hole (approximate matches) and
an unbound variable (exact name matches only), using a stub bloogle
script that the .exp file puts on PATH.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZAJ5Pt7KQgVWdCJqzJFXX
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ReSvFGvaEoj8mrS76aGaYp
Route every unbound-name diagnostic through the bloogle exact-name
lookup, not just EUnboundVar: unbound constructors, fields, type
constructors, classes, and packages.  Since those errors are raised in
several phases (MakeSymTab, kind inference, typecheck, GenSign), the
annotation moves from tiDefns into the common reporting funnel,
bsWarningsAndErrorsWithContext: setErrorHandleFlags stashes the
-bloogle-db path in the ErrorState, and every reported message is
decorated there, which also covers the typed-hole warnings that were
previously annotated in tiDefns.

Rather than adding a matches field to each constructor, a wrapper
(EBloogleMatches) appends the suggestions to the wrapped message's
text while keeping its tag, so raise sites are untouched;
EUnboundVar keeps the matches field it already has.  Bloogle.hs is
reduced to the query primitives, with no Error or Flags imports, so
Error.hs can call it without an import cycle.

Unbound type variables, exports, and system tasks are deliberately
not looked up: a library search cannot supply a locally bound type
variable, a definition missing from the current package, or a $task.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZAJ5Pt7KQgVWdCJqzJFXX
An unbound type constructor (raised during symbol-table construction)
and an unbound data constructor (raised during typecheck) each get
exact name matches from the stub bloogle, exercising the reporting
funnel from two different phases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZAJ5Pt7KQgVWdCJqzJFXX
@matx-amy
matx-amy marked this pull request as draft September 5, 2026 02:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants