Skip to content

Reintroduce hls-retrie-plugin - #5147

Open
simonhorlick wants to merge 93 commits into
haskell:masterfrom
simonhorlick:hls-retrie3
Open

simonhorlick wants to merge 93 commits into
haskell:masterfrom
simonhorlick:hls-retrie3

Conversation

@simonhorlick

@simonhorlick simonhorlick commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

This PR resurrects the hls-retrie-plugin.

The previous retrie plugin had a few issues that I wanted to ensure were solved by the new plugin:

  • imports were often missing or incorrect
  • grafting often introduced syntax errors
  • precedence was not handled correctly
  • test coverage was quite sparse
  • several correctness issues have also been fixed upstream

This is the result of many attempts and failures, each leading to a hopefully better implementation. I have tried to document below the known shortcomings, many of these I intend to address with follow up PRs.

AI disclaimer: Some of the test cases were suggested by Claude. The plugin code itself is almost completely hand written.

What's supported

  • Inlining of top-level definitions, infix operators and sections
  • Inlining of let and where bindings
  • Patterns in the definitions arguments
  • Bindings in the expression are renamed to avoid capture
  • Where bindings in the definition are rewritten as let bindings in the rewrite
  • Use sites that are not fully applied get lambdas inserted
  • Cross-module support (including adding of imports)

What's missing?

  • Definitions with several clauses, guards or a record wildcard construction. Previously these were handled incorrectly, now they are refused
  • We do not emit changes for non-active CPP branches
  • Visible type application
  • Recursive functions
  • Functions that reference a type variable in the expression
  • Cross-module inlining where the target module is missing a language pragma
  • Type constraints solved by the expressions signature are not propagated to the inlining site
  • Duplication of arguments (inlining could cause an argument to be evaluated multiple times)
  • Capture avoidance outside of the substitution (if a binder somewhere on the path to the splice point captures a free variable in the template)
  • Rewrites into CPP modules have incorrect indentation (see Layout issues when using Replacements xich/retrie#24)
  • Capture avoidence from binders introduced by RecordWildCards dots
  • Removal of the definition after inlining

Testing

This PR has undergone the following tests:

  • As many distinct golden tests as I could think of. Including previous inlining tests from the hls-retrie-plugin.
  • Running the inline action at a load of locations in the haskell-language-server repo

Fixes #279
Fixes #307
Fixes #1758
Partially fixes #4374 (by rejecting defs with guards, for now)
Fixes #4408 (except for the ghc10 support as noted in the comments)


example.gif


Replace the two plugin commands with a resolve provider registered via
mkCodeActionWithResolveAndCommand. This allows for better integration with
editors.
* appends an import
* append import at layout column
* import unqualified to match template
* import qualified
* reject if required import isn't exported
Import handling was mostly broken for inlining. The new implementation looks up
how the defining module imports a name and attempts to add that import to the
target module. If the name cannot be imported (it uses PatternSynonyms, or the
name is just not exported) then alert the user and skip the rewrite.
Since the addition of the resolve flow, this is better handled inside the
client. For example, in VSCode using ctrl+enter on a code action allows
users to select which rewrites to apply.
stylish-haskell blanks the #if lines and parses the whole module, with the body
in the previous position that caused a parse error from stylish haskell. This
seems like the simplest fix.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant