Skip to content

Typed rules - #5025

Open
vidit-od wants to merge 1 commit into
haskell:masterfrom
vidit-od:Typed-Rules
Open

Typed rules#5025
vidit-od wants to merge 1 commit into
haskell:masterfrom
vidit-od:Typed-Rules

Conversation

@vidit-od

@vidit-od vidit-od commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

This PR introduces typed inputs for HLS/ghcide rules.

HLS already associates every rule key with its result through RuleResult, but all rules previously accepted the same input type: NormalizedFilePath. Theis PR adds an open type family that associates each rule with the kind of input it supports:

type family RuleInput k

type instance RuleInput TypeCheck = ProjectHaskellInput
type instance RuleResult TypeCheck = TcModuleResult

Rule inputs are now part of the rule's contract, just like rule results.

Why this is needed

A raw NormalizedFilePath does not tell us what a path actually represent. These distinctions matter. For example, TypeCheck and GhcSession require a project component and session, while file-content rules can work on many file
types. Typed inputs make these assumptions explicit, reject incorrect rule/input pairings earlier, and provide the foundation needed to support dependency sources without treating them as project modules.

How it works

The new Development.IDE.Core.RuleInput module defines this input hierarchy:

SomeInput
|-- NoInput
`-- SomeFileInput
    |-- SomeHaskellInput
    |   |-- ProjectHaskellInput
    |   `-- NonProjectHaskellInput
    |-- CabalInput
    `-- arbitrary NormalizedFilePath

Internally, Shake still needs one heterogeneous key representation. SomeInput
therefore existentially stores typed inputs inside Q, while InputFingerprint
provides consistent equality and hashing.

Comment thread ghcide/src/Development/IDE/Core/Actions.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Rules.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Rules.hs Outdated

@wz1000 wz1000 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Broadly looks good, some inputs need to be tightened up

Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Actions.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Actions.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Rules.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleTypes.hs Outdated

@fendor fendor left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, this looks very nice! This is a nitpick review, so it is the intention to be done after the review is addressed. I have reviewed the ghcide changes, will review plugins soon.

Further, we agreed the following documentation is still missing and will be added:

    * What are the existing rules?
    * What is RuleInput?
    * Why do we have RuleInput
    * What is the design of RuleInput
        Note [Hierarchical Inputs]
        Note [RuleInput]
        
        Reference these notes from various type classes and RuleInput type
    * Helper functions need documentation

Comment thread ghcide/session-loader/Development/IDE/Session/Diagnostics.hs Outdated
Comment thread ghcide/session-loader/Development/IDE/Session/Ghc.hs Outdated
Comment thread ghcide/session-loader/Development/IDE/Session/Ghc.hs Outdated
Comment thread ghcide/src/Development/IDE/Import/DependencyInformation.hs Outdated
Comment thread ghcide/src/Development/IDE/Import/FindImports.hs Outdated
Comment thread ghcide/src/Development/IDE/Spans/Pragmas.hs Outdated
Comment thread hls-plugin-api/src/Ide/Plugin/Error.hs Outdated
Comment thread hls-plugin-api/src/Ide/Plugin/Error.hs
Comment thread hls-plugin-api/src/Ide/Plugin/Error.hs
toPriority :: PluginError -> Priority
toPriority (PluginInternalError _) = Error
toPriority (PluginInvalidParams _) = Warning
toPriority (PluginUnsupportedUriType _) = Warning

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We might want to demote this to Debug. IIRC, a warning is displayed in the editor, but these errors will be perfectly sensible in the future, right?

@wz1000 opinions?

@vidit-od
vidit-od force-pushed the Typed-Rules branch 7 times, most recently from 144b524 to ec6e677 Compare August 4, 2026 20:50
@vidit-od
vidit-od force-pushed the Typed-Rules branch 3 times, most recently from bc09427 to 0afd603 Compare August 8, 2026 13:06

@fendor fendor left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Some more comments :)

Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs
case file of
SomeProjectHaskellInput projectFile ->
setFileModified (cmapWithPrio LogFileStore recorder) (VFSModified vfs) ide False projectFile action
_ -> setSomethingModified (VFSModified vfs) ide (fromNormalizedFilePath (inputFilePath file) ++ " (modified)") action

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We shouldn't do anything here, rather log this case.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@wz1000 What should we do in this case? Call setSomethingModified for completeness? We need to add it to the set of files of interest, but it might not need to record that it isn't the first time this non project haskell file was opened, right? 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

setSomethingModified is not correct here, that will trash the entire session. I think setFileModified should accept SomeHaskellInput instead of ProjectHaskellInput

It should always restart with the new VFS and dirty the file’s GetModificationTime, then run typecheckParents only in the SomeProjectHaskellInput branch

Comment thread ghcide/src/Development/IDE/LSP/Notifications.hs Outdated
case file of
SomeProjectHaskellInput projectFile ->
setFileModified (cmapWithPrio LogFileStore recorder) (VFSModified vfs) ide True projectFile action
_ -> setSomethingModified (VFSModified vfs) ide (fromNormalizedFilePath (inputFilePath file) ++ " (modified)") action

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same here

Comment thread ghcide/src/Development/IDE/Core/Rules.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Shake.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Shake.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Shake.hs Outdated
Comment thread ghcide/src/Development/IDE/Core/Shake.hs Outdated
Comment thread ghcide/src/Development/IDE/Import/FindImports.hs Outdated
Comment thread ghcide/src/Development/IDE/Plugin/Completions.hs Outdated
Comment thread ghcide/src/Development/IDE/Plugin/Test.hs Outdated

@wz1000 wz1000 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

plugins and input types broadly look correct. I need to do another more careful pass though.

Comment thread ghcide/src/Development/IDE/Core/RuleInput.hs Outdated
case file of
SomeProjectHaskellInput projectFile ->
setFileModified (cmapWithPrio LogFileStore recorder) (VFSModified vfs) ide False projectFile action
_ -> setSomethingModified (VFSModified vfs) ide (fromNormalizedFilePath (inputFilePath file) ++ " (modified)") action

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

setSomethingModified is not correct here, that will trash the entire session. I think setFileModified should accept SomeHaskellInput instead of ProjectHaskellInput

It should always restart with the new VFS and dirty the file’s GetModificationTime, then run typecheckParents only in the SomeProjectHaskellInput branch

Comment thread plugins/hls-notes-plugin/src/Ide/Plugin/Notes.hs Outdated
Comment thread plugins/hls-notes-plugin/src/Ide/Plugin/Notes.hs Outdated
@vidit-od vidit-od mentioned this pull request Aug 23, 2026
@vidit-od
vidit-od force-pushed the Typed-Rules branch 2 times, most recently from ab25f1d to 243e8a9 Compare August 30, 2026 19:41
Introduces typed rule inputs so each HLS rule explicitly declares the kinds of input it can consume. This replaces the previous NormalizedFilePath (NFP)-based convention with a typed model in which inputs are classified before a rule is invoked. The hierarchy captures relationships between global, file-based, Haskell, Cabal, project, and dependency inputs. Broader rule-input types do not automatically subsume more specific inputs, so callers must explicitly pattern match to narrow a general input or wrap a specific input to widen it to the exact type expected by a rule. This allows the compiler to reject invalid rule invocations and makes rule scope, dependencies, caching, and invalidation behavior clearer.
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.

3 participants