Skip to content

Use pretty printing context when expanding records#4917

Open
crtschin wants to merge 5 commits intohaskell:masterfrom
crtschin:crtschin/record-qualified-expansion
Open

Use pretty printing context when expanding records#4917
crtschin wants to merge 5 commits intohaskell:masterfrom
crtschin:crtschin/record-qualified-expansion

Conversation

@crtschin
Copy link
Copy Markdown
Collaborator

Closes #4903.

There were some existing helpers for determining whether to print qualified/unqualified, use those when printing the expanded records.

An alternate approach would be to get the ranges from the expressions and use those to extract the expressions from the source files. That would have the benefit that record expansions with erroneous expressions would be nicely transplanted, but I think that would also require detaching CollectRecords from type checking, so I didn't pursue.

@crtschin crtschin marked this pull request as ready for review April 28, 2026 14:17
@crtschin crtschin requested review from ozkutuk and wz1000 as code owners April 28, 2026 14:17
Copy link
Copy Markdown
Collaborator

@ozkutuk ozkutuk left a comment

Choose a reason for hiding this comment

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

Thanks for taking care of this! I have a question and a few nitpicky remarks, but otherwise everything looks good.

Comment on lines +468 to +471
pretty (RecordInfoPat _ p) = pretty (printOutputable p)
pretty (RecordInfoCon _ e) = pretty (printOutputable e)
pretty (RecordInfoApp _ (RecordAppExpr _ _ fla))
= hsep (map (pretty . printOutputable) fla)
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.

Is there a fundamental reason to remove these, apart from the fact that printFieldName now requires a NamePprCtx? I used to find these helpful for debugging, so I think we can preserve them by inlining the old definition of printFieldName instead:

Suggested change
pretty (RecordInfoPat _ p) = pretty (printOutputable p)
pretty (RecordInfoCon _ e) = pretty (printOutputable e)
pretty (RecordInfoApp _ (RecordAppExpr _ _ fla))
= hsep (map (pretty . printOutputable) fla)
pretty (RecordInfoPat ss p) = pretty (stripOccNamePrefix (printOutputable ss)) <> ":" <+> pretty (printOutputable p)
pretty (RecordInfoCon ss e) = pretty (stripOccNamePrefix (printOutputable ss)) <> ":" <+> pretty (printOutputable e)
pretty (RecordInfoApp ss (RecordAppExpr _ _ fla))
= pretty (stripOccNamePrefix (printOutputable ss)) <> ":" <+> hsep (map (pretty . printOutputable) fla)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good one! No this was me being lazy.

nfp <- getNormalizedFilePathE uri
pragma <- getFirstPragma pId ideState nfp
CRR {crCodeActionResolve, nameMap, enabledExtensions} <- runActionE "ExplicitFields.CollectRecords" ideState $ useE CollectRecords nfp
(CRR {crCodeActionResolve, nameMap, enabledExtensions}, pprCtx) <- runActionE "ExplicitFields.CodeAction" ideState $ do
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.

I admit this is nitpicking at this point, but why are we renaming the debug name of just at this specific use site? (i.e. from "ExplicitFields.CollectRecords" to "ExplicitFields.CodeAction"). If the idea is to differentiate between different such calls, I can see the value in that, but in that case we should rename all of them to unique names IMO. Also, technically there are two code actions registered by this plugin, so renaming just one of them to "ExplicitFields.CodeAction" might cause some confusion down the line, I imagine.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'll give each one a unique name 👍🏽

Comment on lines +620 to +621
formatOutputable :: Outputable a => NamePprCtx -> a -> Text
formatOutputable pprCtx a = T.pack $ printSDocQualifiedUnsafe pprCtx (ppr a)
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.

The printOutputable function we used to use was doing some "unescaping" in the presence of printable escape sequences within double quotes. Is this not necessary anymore with formatOutputable?

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.

Perhaps helpful adding a regression test?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It appears this is only relevant for pretty printing type-level literals. So the current implementation didn't suffer from show-polluted strings as it's all value-level expressions.

To be sure, I've added a test-case with some unicode fields and expressions. I've also refactored it a bit and moved this formatOutputable next to the functions and changed it so it also did the unescaping, as it's probably more-wildly applicable.

@crtschin crtschin force-pushed the crtschin/record-qualified-expansion branch from 9967898 to f4df874 Compare April 30, 2026 23:17
@crtschin crtschin force-pushed the crtschin/record-qualified-expansion branch from f4df874 to e54e898 Compare May 1, 2026 08:27
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.

Record Inlay hint expansion removes qualified names

3 participants