Skip to content

Plinth: improve error reporting for unsupported Haskell features#7659

Open
zliu41 wants to merge 5 commits intomasterfrom
zliu41/unsupported
Open

Plinth: improve error reporting for unsupported Haskell features#7659
zliu41 wants to merge 5 commits intomasterfrom
zliu41/unsupported

Conversation

@zliu41
Copy link
Member

@zliu41 zliu41 commented Mar 11, 2026

Added a typeCheckResultAction that detects unsupported Haskell features, and wraps offending exprs with a specific marker function. It currently detects base's Eq/Ord, and IO actions.

This requires compiling Plinth using plinthc or plc instead of compile, since compile uses TH, and TH cannot install frontend plugins.

Old error (it's much longer than this, and only a portion is shown):

old

New error:

new

@zliu41 zliu41 requested review from a team and SeungheonOh March 11, 2026 02:43
@zliu41 zliu41 force-pushed the zliu41/unsupported branch from eff28eb to 12c380c Compare March 11, 2026 03:11
Copy link
Contributor

@Unisay Unisay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, I am happy that we're able to do this now.

I'd be even more happy to see some unit tests to prove this functionality works as intended and demonstrate how the error message looks like.

Copy link
Contributor

@Unisay Unisay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions — mostly style nits plus removing the unnecessary MonadIO additions (confirmed cabal build all passes without them).

plugin =
GHC.defaultPlugin
{ GHC.typeCheckResultAction = injectAnchors
{ GHC.typeCheckResultAction = const . const $ injectAnchors >=> injectUnsupportedMarkers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: named ignored arguments are more self-documenting than point-free const . const:

Suggested change
{ GHC.typeCheckResultAction = const . const $ injectAnchors >=> injectUnsupportedMarkers
{ GHC.typeCheckResultAction = \_cliArgs _modSummary -> injectAnchors >=> injectUnsupportedMarkers

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a matter of style preference - const feels cleaner to me, at least in this particular instance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, this is indeed a style / taste matter, my preference is driven by the desire to name explicitly the thing that is being discarded or ignored, as in:
"The CLI Args and Mod Summary are available in the context but are unused"
vs.
"There are two arguments that are unused"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, updated per your suggestion.

plugin =
GHC.defaultPlugin
{ GHC.pluginRecompile = GHC.flagRecompile
{ GHC.typeCheckResultAction = const . const $ injectUnsupportedMarkers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same nit here:

Suggested change
{ GHC.typeCheckResultAction = const . const $ injectUnsupportedMarkers
{ GHC.typeCheckResultAction = \_cliArgs _modSummary -> injectUnsupportedMarkers

, MonadReader r
, MonadQuote
, MonadWriter w
, MonadIO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MonadIO isn't needed here — cabal build all passes without it. The IO usage is in injectUnsupportedMarkers which runs in TcM, not in the compilation monad.

Suggested change
, MonadIO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I initially added some IO actions in compileExpr, but later removed them.

, MonadState CompileState m
, MonadDefs LexName uni fun Ann m
, MonadWriter CoverageIndex m
, MonadIO m
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above — MonadIO isn't needed in the Compiling constraint. The marker extraction in Expr.hs is pure pattern matching.

Suggested change
, MonadIO m

Copy link
Member Author

@zliu41 zliu41 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I need to add some tests.

, MonadReader r
, MonadQuote
, MonadWriter w
, MonadIO
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I initially added some IO actions in compileExpr, but later removed them.

Copy link
Member Author

@zliu41 zliu41 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few tests.

plugin =
GHC.defaultPlugin
{ GHC.typeCheckResultAction = injectAnchors
{ GHC.typeCheckResultAction = const . const $ injectAnchors >=> injectUnsupportedMarkers
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a matter of style preference - const feels cleaner to me, at least in this particular instance.

@zliu41 zliu41 force-pushed the zliu41/unsupported branch from e2147fd to 6c8f70c Compare March 11, 2026 22:36
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