[Git][ghc/ghc][wip/T27724] 14 commits: rts: handle large CONSTR closures in compacting GC
by Simon Peyton Jones (@simonpj) 16 Sep '26
by Simon Peyton Jones (@simonpj) 16 Sep '26
16 Sep '26
Simon Peyton Jones pushed to branch wip/T27724 at Glasgow Haskell Compiler / GHC
Commits:
749d2448 by Luite Stegeman at 2026-09-15T14:07:01-04:00
rts: handle large CONSTR closures in compacting GC
The function update_fwd_large in the compacting GC could run into
an unexpected object with the following error:
internal error: update_fwd_large: unknown/strange object 1
Closure type 1 is CONSTR. This patch adds cases for CONSTR and
CONSTR_NOCAF.
This is the same problem as #27434 (large AP closures, fixed by
cca0d58963), which missed this case.
Fixes #27649
- - - - -
177d6155 by Luite Stegeman at 2026-09-15T14:07:02-04:00
testsuite: fix T27434 test with compacting GC
Ensure that the interpreter is actually run with the compacting GC
- - - - -
5796aa63 by Luite Stegeman at 2026-09-15T14:07:49-04:00
rts: initialise the stack frame header for mask_frame and apply_mask_frame
We must leave the stack in consistent state before jumping to
mask_frame or apply_mask_frame because they may result. Failing
to do so could lead to a crash if there were waiting exceptions.
Fixes #27651
- - - - -
2486cc92 by Simon Peyton Jones at 2026-09-15T14:08:36-04:00
Re-introduce the "weird SpecDict" case
In this commit
commit f80375dd4945350a1d784e436975b48b9c736eaf
Author: Simon Peyton Jones <simon.peytonjones(a)gmail.com>
Date: Sun Jun 29 15:26:58 2025 +0100
Refactor of Specialise.hs
I removed a test for a dictionary with unbound type variables. This
turned out to be wrong; see #27629.
So this MR re-introduces it.
- - - - -
8e09a46f by Duncan Coutts at 2026-09-15T20:11:35-04:00
Refactor (and rename) removeFromQueues, to simplify I/O managers
Rename it to unblockAndAppendToRunQueue which better reflects what it is
intended to do.
The post-condition for unblockAndAppendToRunQueue is that the TSO is on
the run queue or it is in the process of migrating to another cap.
Previously it achieved that by always directly adding the TSO to the run
queue itself.
But this actually made things more complicated for the I/O managers,
because it meant they needed a separate code path for notifying for
cancellation compared to notifying for completion. The general
notification code would always add the TSO to the run queue itself.
So the improvement is to allow different cases in
unblockAndAppendToRunQueue to achieve the same outcome in different
ways: either directly adding to the run queue or calling helper
functions that do so themselves.
This then allows the new I/O managers to share code between the sync and
async cancellation, and to reuse their notifyIOCompletion helpers for
cancellation. This avoids a source of bugs where the completion path may
be updated but the cancellation path may be forgotten, or similarly in
future for sync/async operations.
Update all the existing in-RTS I/O managers, and the posix timeout code.
- - - - -
d668782c by Duncan Coutts at 2026-09-15T20:11:35-04:00
Document that awaitCompletedTimeoutsOrIO expects an empty run queue
This was true before but implicit and not relied on much. It's better to
be explicit, and allow things to depend on it.
- - - - -
11d938bb by Duncan Coutts at 2026-09-15T20:11:35-04:00
Store the I/O opcode and fd in the StgAsyncIOOp
This will be useful in several I/O managers and it is handy for logging
and debugging.
It also doesn't increase the size of the StgAsyncIOOp structure. There
was enough spare padding space already.
Update the poll I/O manager to set the new fields.
Add a helper function to convert the enum IOReadOrWrite into the enum
IOOpCode. Also change IOReadOrWrite to be an enum without a typedef, for
consistency with other enumerations in IOManager.h
- - - - -
bfa87882 by Duncan Coutts at 2026-09-15T20:11:36-04:00
Add a new I/O manager based on select()
Yes, this is the second such I/O manager, but it is a modern
re-implementation based on the new in-RTS I/O manager infrastructure. So
it is cleaner and faster than the old select I/O manager.
Why do we need another I/O manager based on select? Why isn't the poll()
one good enough as a baseline portable unix I/O manager? Because macOS.
Apple Inc. is why we cannot have nice things.
The man page for poll on macOS documents the fact that it does not work.
At least, it does not work for all files. Specifically, it does not work
for device files. Whereas macOS select() does work for device files.
Aaaaarg!
We _do_ want to deprecate and remove the old select I/O manager, but due to
macOS we cannot do that until we have a replacement. This is that
replacement. Until of course a nice new k-queue I/O manager arrives,
which could become the new default for macOS and FreeBSD.
Interestingly, this select I/O manager is actually faster than the poll
one, on Linix, in some circumstances: specifically when many Haskell
threads are waiting on the same fd. The poll I/O manager does O(n) work
for n threads waiting on I/O, whereas the select one does O(fds) work
for the number of fds that threads are waiting on. Usually this is 1:1,
so it's not noticable, but one can concoct extreme benchmarks to show
the difference.
- - - - -
8e9de15a by Duncan Coutts at 2026-09-15T20:11:36-04:00
Minor updates in the poll I/O manager to keep in sync with select
This keeps it in sync with select one. The changes are based on code review
while implementing the new select I/O manager. The two I/O managers are so
similar in structure that it makes sense to try to minimise the diff between
them. This should aid understanding, and fixes to both in future.
- - - - -
222668bb by Duncan Coutts at 2026-09-15T20:11:36-04:00
Document the new select I/O manager in the user guide
in the RTS section about I/O managers.
And add a changelog entry.
- - - - -
0f48735b by Cheng Shao at 2026-09-15T20:12:23-04:00
Revert "wasm: workaround WebKit bug in dyld"
This reverts commit c9b8465c2c338176fcab9d197e9d31f4aee11f68. The
underlying webkit bug has been fixed in
https://commits.webkit.org/314219@main. Closes #27564.
- - - - -
809294f1 by Luite Stegeman at 2026-09-15T20:13:08-04:00
rts: make stg_threadLabelzh return a valid pointer for unlabeled threads.
This fixes a segfault in the GC caused by stg_threadLabelzh returning
a 0 pointer in a GC pointer field.
stg_threadLabelzh returns a tuple of type (# Int#, ByteArray# #). If a
thread has no label, the second field is unused. We must still return
a valid heap object pointer.
Instead of returning 0, we now return stg_DEAD_SLOT_closure.
fixes #27618
- - - - -
e2d57026 by Luite Stegeman at 2026-09-15T20:13:54-04:00
JS: fix selector thunk handling
fix a bug where entering a selector thunk could lead to a crash
if the selected field was still a thunk.
fixes #27788
- - - - -
c561949f by Simon Peyton Jones at 2026-09-16T13:25:34+01:00
Redesign the noinline magic
Main idea:
* When simplifying `noinline (f e1 e2)`, switch off inlining when simplifying `f`
* Mechanism: see `simplOutId`, the `noinlineIdKey` case
* If we see `noinline (f e1) e2`, the simplifier moves the `e2` inside; see the `splitContArgs` call.
This is important so you can write `noinliine f e1 e2` and have it mean the same as `noinline (f e1 e2)`.
* Now `f` sees all its arguments, henc:
* Fixes #27724
* Fixes #23911
* Also fixes #27803 where we were not respecting `noinline` if the RHS
was trivial
See Note [noinlineId magic] for lots of specifics. It's surprisingly tricky!
For some reason a couple of perf tests allocate 1.2% less at compile time,n
namely T29872 and T8095. Geom mean decease of 0.1%
Metric Decrease:
T9872d
- - - - -
82 changed files:
- + changelog.d/T27629
- + changelog.d/T27724
- + changelog.d/T27788-js-selector
- + changelog.d/fix-compacting-gc-constr-27649
- + changelog.d/fix-control0-mask-trampoline
- + changelog.d/fix-threadlabel-segfault-27618
- + changelog.d/select-io-manager
- compiler/GHC/Builtin/WiredIn/Ids.hs
- compiler/GHC/Builtin/WiredIn/Prim.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Driver/Config/Core/Opt/Simplify.hs
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/Symbols.hs
- compiler/GHC/Tc/Instance/Class.hs
- compiler/GHC/Tc/Types/Origin.hs
- docs/users_guide/runtime_control.rst
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/ghc-internal/src/GHC/Internal/Magic.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- rts/ContinuationOps.cmm
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/StgMiscClosures.cmm
- rts/configure.ac
- rts/include/rts/Flags.h
- rts/include/rts/storage/Closures.h
- rts/include/stg/MiscClosures.h
- rts/posix/Poll.c
- rts/posix/Poll.h
- + rts/posix/SelectBis.c
- + rts/posix/SelectBis.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
- rts/rts.cabal
- rts/sm/Compact.c
- testsuite/tests/corelint/LintEtaExpand.hs
- + testsuite/tests/dmdanal/should_compile/T23911.hs
- + testsuite/tests/dmdanal/should_compile/T23911.stderr
- testsuite/tests/dmdanal/should_compile/all.T
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- + testsuite/tests/javascript/T27788.hs
- + testsuite/tests/javascript/T27788.stdout
- testsuite/tests/javascript/all.T
- + testsuite/tests/rts/T27618.hs
- + testsuite/tests/rts/T27618.stdout
- + testsuite/tests/rts/T27649.hs
- + testsuite/tests/rts/T27649.stdout
- testsuite/tests/rts/all.T
- + testsuite/tests/rts/continuations/T27651.hs
- + testsuite/tests/rts/continuations/T27651.stdout
- testsuite/tests/rts/continuations/all.T
- testsuite/tests/simplCore/should_compile/Makefile
- testsuite/tests/simplCore/should_compile/T18995.stderr
- + testsuite/tests/simplCore/should_compile/T27629.hs
- + testsuite/tests/simplCore/should_compile/T27629.stderr
- + testsuite/tests/simplCore/should_compile/T27629Plugin.hs
- + testsuite/tests/simplCore/should_compile/T27724a.hs
- + testsuite/tests/simplCore/should_compile/T27724a.stderr
- + testsuite/tests/simplCore/should_compile/T27803.hs
- + testsuite/tests/simplCore/should_compile/T27803.stderr
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/typecheck/should_fail/T17940.stderr
- utils/genprimopcode/Main.hs
- utils/jsffi/dyld.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/dc55d4ce900445241c228693fe3bc1…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/dc55d4ce900445241c228693fe3bc1…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/T26543b] 43 commits: X86 NCG: use btr/bts/btc for single-bit operations
by Simon Peyton Jones (@simonpj) 16 Sep '26
by Simon Peyton Jones (@simonpj) 16 Sep '26
16 Sep '26
Simon Peyton Jones pushed to branch wip/T26543b at Glasgow Haskell Compiler / GHC
Commits:
2908ab36 by Simon Jakobi at 2026-09-05T07:22:17-04:00
X86 NCG: use btr/bts/btc for single-bit operations
Previously the Cmm patterns
x & ~(1 << i)
x | (1 << i)
x ^ (1 << i)
compiled to mov/shl/not/and-style sequences of 3-4 instructions. Now
they compile to a single btr, bts or btc, matching what C compilers
produce.
When the bit index is a literal, constant folding has already collapsed
these patterns into ones with a literal mask, such as
x & 0xfffffeffffffffff for x & ~(1 << 40). Such masks are now also
compiled to a bit-test instruction when they don't fit in an imm32 and
would otherwise have to be loaded into a register first.
For a variable bit index, this applies only when the shift is unchecked
(uncheckedShiftL#, Data.Bits.unsafeShiftL): the bounds-checked shiftL
used by e.g. the default clearBit/setBit/complementBit implementations
wraps the shift in a bounds mask that this optimisation does not see
through. With a literal index, the bounds mask is constant-folded away,
so the checked operations benefit too.
See Note [Bit-test instructions] in GHC.CmmToAsm.X86.CodeGen.
Fixes #25233.
Assisted-by: Claude Fable 5
- - - - -
c673ecf0 by Simon Peyton Jones at 2026-09-05T07:22:59-04:00
Move HsStatic free-var test to typechecker
A `static` form should have no free *term* variables, but it
can have free *type* variables. Alas, the renamer does not really know what
is a term variable and what is a type variable, because of required type
arguments. This patch moves the test to the typechecker, which does know.
Addresses #27664
- - - - -
5939ceaf by sheaf at 2026-09-05T22:06:18-04:00
Windows: enforce path convention in ./configure
As detailed in Note [MSYS paths] in Hadrian.Utilities, the standing
convention (using Windows-style paths with forward slashes) is now
enforced in ./configure instead of within Hadrian, removing the need for
'cygpath' calls within Hadrian.
Fixes #26683
- - - - -
a6061455 by sheaf at 2026-09-05T22:06:18-04:00
Hadrian: introduce ExeSpawnPath
Specific details about the filepath used to specify the executable to
spawn with CreateProcess matters on Windows: whether we use forward or
backward slashes, a leading ./, or an absolute path changes how the
executable is found.
This commit introduces 'ExeSpawnPath' which is a path that is guaranteed
to be found when spawning a process. All command invocations now go
through this type to ensure the path has been properly sanitised.
See Note [NeedCurrentDirectoryForExePath] in Hadrian.Utilities.
The same treatment is applied to hsc2hs. Updates hsc2hs submodule.
- - - - -
e28313e3 by sheaf at 2026-09-05T22:07:06-04:00
Preserve tick ordering in 'tickTickedExpr'
'GHC.Core.Utils.tickTickedExpr' tries to combine a tick 't1' into an
existing stack of ticks 't2s'. There are two situations:
1. 't1' is subsumed by a tick in 't2s': drop it.
2. A tick in 't2s' is subsumed by 't1', say 't2'.
This commit ensures that in case (2) we keep 't1' on the outside instead
of replacing 't2' at its position in the stack. This avoids re-ordering
source notes (which was the cause of #27749).
This fixes a regression introduced in 2dadf3b0d05.
Fixes #27749
- - - - -
3172f557 by sheaf at 2026-09-05T22:07:06-04:00
Consistently prefer local source note ticks
GHC.Cmm.DebugBlock.cmmDebugGen (DWARF annotations) and
GHC.Stg.Debug.quickSourcePos (-finfo-table-map) both contained logic to
prioritise source note ticks from the current module.
This commit commons up this logic and propagates it to a third consumer:
IPE stack frames, in GHC.Driver.GenerateCgIPEStub.
See the new function GHC.Types.Tickish.bestSourceNote.
- - - - -
192be0b6 by Luite Stegeman at 2026-09-07T19:43:36-04:00
rts: fix ctoi_tuple_spill_words getting out of sync
Fix a few places that were not updating ctoi_tuple_spill_words
correctly, leading to corruption/crashes when dealing with large
unboxed tuples in bytecode:
- captureContinuationAndAbort
- findRetryFrameHelper/findAtomicallyFrameHelper
- interpretBCO bci_BRK_FUN
fixes #27633
- - - - -
604eb43c by Simon Jakobi at 2026-09-07T19:44:15-04:00
Hadrian: don't capture the testsuite driver's output (#27780)
a6061455d54 switched the Testsuite RunTest case from Shake's cmd to the
cmd' wrapper. cmd' always captures stdout and stderr, and since the
caller asks for Exit, it returns without dumping what it captured. As a
result the testsuite output no longer appears in CI job logs: failures,
performance metrics and the summary were lost with the job.
Use cmdExe, the uncaptured cmd, as the other plain-cmd sites in that
commit do.
Fixes #27780.
Assisted-by: Claude Fable 5.1
- - - - -
06eee015 by Luite Stegeman at 2026-09-08T06:03:06+02:00
rts: Fix missing memory barrier in eval_thunk_selector (#27477)
unchain_thunk_selectors() was missing an ACQUIRE_LOAD for the
indirectee, leading to segfaults and corruption during GC on
weakly-ordered architectures.
Fixes #27477
- - - - -
f8b2bd8f by Alan Zimmerman at 2026-09-08T09:39:12-04:00
EPA Fix HsCmdDo exact print with comments
Exact printing of HsCmdDo was ignoring the location for the do
statements, and this is an annotation that can have comments in it.
Update it so we print the statements as a unit, including any
comments.
Also add the result of auditing that we capture comments in all needed
places, noting that the remaining Anno SrcSpan instances are benign.
- - - - -
430967ab by Duncan Coutts at 2026-09-09T11:07:01+01:00
Reorder cmm decls in HeapStackCheck for a better logical grouping
And put more section headers in to deliniate the groups.
We're about to add more here, so better to organise it first.
- - - - -
344080fd by Duncan Coutts at 2026-09-09T11:07:01+01:00
Add raisePrimIOException and add it to RTS<->ghc-internal API
The raisePrimIOException is a new helper function that I/O primops will
use to help them report I/O errors. This is implemented in Haskell
(since that's a lot easier), but has a calling convention that is
easy(ish) to use from Cmm in the I/O primops.
So we add it to the RTS API struct, and since we'll use it from Cmm we
also need a field accessor macro for cmm (in deriveConstants).
See the Note about how we cannot have nice things due to async
exceptions and thunks preventing us from using catch.
- - - - -
cfdb3399 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Add new blocking functions for I/O primops
See the Note [Thread blocking for new I/O primops],
and the Note [Calling convention for raisePrimIOException].
The point is, it will allow us to report synchronous exceptions from I/O
primops, and do so much more flexibly.
Previously the I/O managers could only report async exceptions and only
nullary exceptions. This was OK historically, but no good as we add
more I/O managers and expand the range of I/O operations we support.
- - - - -
f09c09d8 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Change the encoding of results from the I/O manager to I/O primops
Previously we just had async continue or heap overflow.
We now extend what we can report with synchronous success, and
synchronous failure with an errno.
See Note [Encoding of result of I/O manager operations]
We don't use these two new cases yet, but we will. In particular an
epoll I/O manager needs to be able to report synchronous success or
failure for waitRead#/waitWrite#.
- - - - -
30f074d9 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Switch waitRead/Write# to use new blocking return frames
and update the I/O managers to set the result before resuming the
blocked threads.
This makes it possible for I/O managers to report synchronous exceptions
from the I/O primops, but that will be done in a subsequent commit.
- - - - -
a8786ced by Duncan Coutts at 2026-09-09T11:07:01+01:00
Switch Poll and Select I/O managers to report sync exceptions
rather than using raiseAsync with blockedOnBadFD_closure.
This uses the new mechanism in the blocking frame return code to report
synchronous exceptions.
- - - - -
7a9df79a by Duncan Coutts at 2026-09-09T11:07:01+01:00
Remove now-unused blockedOnBadFD
It was previously thrown by the select and poll I/O managers, but now
they use raisePrimIOException (with an EBADF errno).
- - - - -
6b0424e3 by Duncan Coutts at 2026-09-09T11:07:01+01:00
Improve the docs for delay# waitRead# and waitWrite#
Document that the waitRead/Write# can throw exceptions (this was true
before too), and that all of them are async exception cancellation
points.
- - - - -
afeb2c30 by Duncan Coutts at 2026-09-09T20:08:58-04:00
Enable printf warnings for trace functions and fix resulting warnings
Most of the existing printf-style functions are annotated with
attributes to enable gcc/clang warnings for the printf format string,
but several trace functions in Trace.h were missing this annotation.
Enable them, and fix the resulting warnings.
- - - - -
9a442c93 by Alan Zimmerman at 2026-09-09T20:09:36-04:00
EPA: Exact print ConDeclGADT without custom enterAnn
!16321 brought in explicit capture of parens in a ConDeclGADT.
The ExactPrint update introduced a modification of the fundamental
function in exact printing, `enterAnn`, by splitting it into a version
allowing injection of functionality normally handled by the
ExactPrint class methods.
This commit refactors that code, to restore the prior `enterAnn`
version, by following the convention in ExactPrint of introducing a
helper data structure with its own `ExactPrint` instance to achieve
the same effect.
- - - - -
4e9297ea by Simon Jakobi at 2026-09-11T08:32:45-04:00
ci: Actually pass --ignore-perf-failures to the testsuite driver
684c0018d9 changed the IGNORE_PERF_FAILURES handling to append to
RUNTEST_ARGS with bash array syntax, but the three use sites still
expand RUNTEST_ARGS as a scalar, which yields only the first array
element. The appended flag was therefore dropped in every job, so
perf improvements kept failing Marge Bot batches and master pipelines,
contrary to #19562.
Append as a string instead, matching the existing --force-colors
append in test_hadrian.
Fixes #27563.
Assisted-by: Claude Fable 5.1
- - - - -
4f78dfdf by Simon Jakobi at 2026-09-11T08:33:24-04:00
testsuite: Give T26537 a 1.5x compile timeout
Its -fregs-graph compile step tends to time out in unoptimized builds
(#27188, #27776).
Assisted-by: Claude Fable 5.1
- - - - -
130286e3 by Alan Zimmerman at 2026-09-11T08:34:08-04:00
EPA: Remove ListBanana / ListParens from AnnListBrackets
This is a step towards making AnnList only represent
lists of items which can have either braces or layout.
- - - - -
a9827d13 by Simon Jakobi at 2026-09-11T18:53:32-04:00
Reject ~, UNPACK and multiplicity annotations on type data fields
Only `!` was rejected so far. `~`, UNPACK and multiplicity annotations
were silently accepted. None of them make sense at the type level, so
restriction (R3) of Note [Type data declarations] now covers all of
them.
Fixes #27732.
Assisted-by: Claude Fable 5.1
- - - - -
c71d5e23 by Alan Zimmerman at 2026-09-11T18:54:11-04:00
EPA: Add a Note for the exact print main loop
- - - - -
7a108e43 by Simon Jakobi at 2026-09-12T18:35:59-04:00
FastString: Drop mkFastStringWith's constructor callback
All three callers passed the same callback, a partial application of
mkNewFastStringShortByteString to the string being interned. That
partial application is allocated as a closure before the table lookup,
on the common hit path too, although the callback is needed only after
a miss.
Drop the parameter and call mkNewFastStringShortByteString directly
after a miss. Since nothing is passed "with" anymore, rename the
function to internSB.
Suggested by Simon PJ in #27528:
https://gitlab.haskell.org/ghc/ghc/-/work_items/27528#note_687031
Assisted-by: Claude Fable 5
- - - - -
82c73b22 by Alan Zimmerman at 2026-09-12T18:36:38-04:00
EPA: More targeted HsDo exact print annotation
HsDo is multi-purpose, as encoded in its HsDoFlavour field. Some of
these are in a layout context (DoExpr, MDoExpr), others are not
(ListComp, MonadComp).
We are moving towards using AnnList only in layout contexts, so we
switch the HsDo TTG annotation from holding an AnnList for this, to
holding
Either (EpToken "[", EpToken "]") AnnList
This also allows us to trim down AnnListBrackets to only have braces
or None, thereby opening the door for unification with the existing
layout context data type EpLayout.
- - - - -
749d2448 by Luite Stegeman at 2026-09-15T14:07:01-04:00
rts: handle large CONSTR closures in compacting GC
The function update_fwd_large in the compacting GC could run into
an unexpected object with the following error:
internal error: update_fwd_large: unknown/strange object 1
Closure type 1 is CONSTR. This patch adds cases for CONSTR and
CONSTR_NOCAF.
This is the same problem as #27434 (large AP closures, fixed by
cca0d58963), which missed this case.
Fixes #27649
- - - - -
177d6155 by Luite Stegeman at 2026-09-15T14:07:02-04:00
testsuite: fix T27434 test with compacting GC
Ensure that the interpreter is actually run with the compacting GC
- - - - -
5796aa63 by Luite Stegeman at 2026-09-15T14:07:49-04:00
rts: initialise the stack frame header for mask_frame and apply_mask_frame
We must leave the stack in consistent state before jumping to
mask_frame or apply_mask_frame because they may result. Failing
to do so could lead to a crash if there were waiting exceptions.
Fixes #27651
- - - - -
2486cc92 by Simon Peyton Jones at 2026-09-15T14:08:36-04:00
Re-introduce the "weird SpecDict" case
In this commit
commit f80375dd4945350a1d784e436975b48b9c736eaf
Author: Simon Peyton Jones <simon.peytonjones(a)gmail.com>
Date: Sun Jun 29 15:26:58 2025 +0100
Refactor of Specialise.hs
I removed a test for a dictionary with unbound type variables. This
turned out to be wrong; see #27629.
So this MR re-introduces it.
- - - - -
8e09a46f by Duncan Coutts at 2026-09-15T20:11:35-04:00
Refactor (and rename) removeFromQueues, to simplify I/O managers
Rename it to unblockAndAppendToRunQueue which better reflects what it is
intended to do.
The post-condition for unblockAndAppendToRunQueue is that the TSO is on
the run queue or it is in the process of migrating to another cap.
Previously it achieved that by always directly adding the TSO to the run
queue itself.
But this actually made things more complicated for the I/O managers,
because it meant they needed a separate code path for notifying for
cancellation compared to notifying for completion. The general
notification code would always add the TSO to the run queue itself.
So the improvement is to allow different cases in
unblockAndAppendToRunQueue to achieve the same outcome in different
ways: either directly adding to the run queue or calling helper
functions that do so themselves.
This then allows the new I/O managers to share code between the sync and
async cancellation, and to reuse their notifyIOCompletion helpers for
cancellation. This avoids a source of bugs where the completion path may
be updated but the cancellation path may be forgotten, or similarly in
future for sync/async operations.
Update all the existing in-RTS I/O managers, and the posix timeout code.
- - - - -
d668782c by Duncan Coutts at 2026-09-15T20:11:35-04:00
Document that awaitCompletedTimeoutsOrIO expects an empty run queue
This was true before but implicit and not relied on much. It's better to
be explicit, and allow things to depend on it.
- - - - -
11d938bb by Duncan Coutts at 2026-09-15T20:11:35-04:00
Store the I/O opcode and fd in the StgAsyncIOOp
This will be useful in several I/O managers and it is handy for logging
and debugging.
It also doesn't increase the size of the StgAsyncIOOp structure. There
was enough spare padding space already.
Update the poll I/O manager to set the new fields.
Add a helper function to convert the enum IOReadOrWrite into the enum
IOOpCode. Also change IOReadOrWrite to be an enum without a typedef, for
consistency with other enumerations in IOManager.h
- - - - -
bfa87882 by Duncan Coutts at 2026-09-15T20:11:36-04:00
Add a new I/O manager based on select()
Yes, this is the second such I/O manager, but it is a modern
re-implementation based on the new in-RTS I/O manager infrastructure. So
it is cleaner and faster than the old select I/O manager.
Why do we need another I/O manager based on select? Why isn't the poll()
one good enough as a baseline portable unix I/O manager? Because macOS.
Apple Inc. is why we cannot have nice things.
The man page for poll on macOS documents the fact that it does not work.
At least, it does not work for all files. Specifically, it does not work
for device files. Whereas macOS select() does work for device files.
Aaaaarg!
We _do_ want to deprecate and remove the old select I/O manager, but due to
macOS we cannot do that until we have a replacement. This is that
replacement. Until of course a nice new k-queue I/O manager arrives,
which could become the new default for macOS and FreeBSD.
Interestingly, this select I/O manager is actually faster than the poll
one, on Linix, in some circumstances: specifically when many Haskell
threads are waiting on the same fd. The poll I/O manager does O(n) work
for n threads waiting on I/O, whereas the select one does O(fds) work
for the number of fds that threads are waiting on. Usually this is 1:1,
so it's not noticable, but one can concoct extreme benchmarks to show
the difference.
- - - - -
8e9de15a by Duncan Coutts at 2026-09-15T20:11:36-04:00
Minor updates in the poll I/O manager to keep in sync with select
This keeps it in sync with select one. The changes are based on code review
while implementing the new select I/O manager. The two I/O managers are so
similar in structure that it makes sense to try to minimise the diff between
them. This should aid understanding, and fixes to both in future.
- - - - -
222668bb by Duncan Coutts at 2026-09-15T20:11:36-04:00
Document the new select I/O manager in the user guide
in the RTS section about I/O managers.
And add a changelog entry.
- - - - -
0f48735b by Cheng Shao at 2026-09-15T20:12:23-04:00
Revert "wasm: workaround WebKit bug in dyld"
This reverts commit c9b8465c2c338176fcab9d197e9d31f4aee11f68. The
underlying webkit bug has been fixed in
https://commits.webkit.org/314219@main. Closes #27564.
- - - - -
809294f1 by Luite Stegeman at 2026-09-15T20:13:08-04:00
rts: make stg_threadLabelzh return a valid pointer for unlabeled threads.
This fixes a segfault in the GC caused by stg_threadLabelzh returning
a 0 pointer in a GC pointer field.
stg_threadLabelzh returns a tuple of type (# Int#, ByteArray# #). If a
thread has no label, the second field is unused. We must still return
a valid heap object pointer.
Instead of returning 0, we now return stg_DEAD_SLOT_closure.
fixes #27618
- - - - -
e2d57026 by Luite Stegeman at 2026-09-15T20:13:54-04:00
JS: fix selector thunk handling
fix a bug where entering a selector thunk could lead to a crash
if the selected field was still a thunk.
fixes #27788
- - - - -
6e5db94d by Simon Peyton Jones at 2026-09-16T13:18:59+01:00
Line up simpleUnifyCheck and check_ty_eq_rhs
Even after #26543 was allegedly fixed, the original repo case in the
Description continued to fail. The reason was that the QuickLook
unifier, `qlUnify`, used `simpleUnifyCheck` for checking unification
invariants; and `simpleUnifyCheck` conservatively rejected any RHS
with a coercion hole in it. The upshot was that QuickLook was not
as clever as it should be, wrongly failing to do an impredicative
instantiation.
Interestingly `check_ty_eq_rhs`, which does the same job, only during
constraint solving, was more liberal: it just looked at the free
vars of the coercion, and allowed coercion holes.
This MR lines them up, adding some careful notes. See
Note [simpleUnifyCheck] esp (SUC1)
Note [Unification preconditions] esp (COERCIONS)
Things are better than before, but I am still uncomfortable about the
possibilty that a hole might be filled with a coercion that mentions
the LHS type variable; for now I have left this discomfort documented
in (SUC1).
- - - - -
b4305dae by Simon Peyton Jones at 2026-09-16T13:19:02+01:00
Improve the atvFolder stuff
...to use the same idiom that we already use in exprFreeVars.
- - - - -
fc7e1ef7 by Simon Peyton Jones at 2026-09-16T13:19:02+01:00
More free-var improvements
- - - - -
187 changed files:
- .gitlab/ci.sh
- + changelog.d/27732
- + changelog.d/T26543
- + changelog.d/T27629
- + changelog.d/T27749
- + changelog.d/T27764
- + changelog.d/T27788-js-selector
- + changelog.d/fix-compacting-gc-constr-27649
- + changelog.d/fix-control0-mask-trampoline
- + changelog.d/fix-parallel-gc-selector-race-27477
- + changelog.d/fix-threadlabel-segfault-27618
- + changelog.d/ncg-x86-bit-test-instructions
- + changelog.d/select-io-manager
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/Cmm/DebugBlock.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/Core/FVs.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/TyCo/FVs.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/Data/FastString.hs
- compiler/GHC/Driver/GenerateCgIPEStub.hs
- compiler/GHC/Driver/Main/Compile.hs
- compiler/GHC/Hs/Doc.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Extension/Pass.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Stg/Debug.hs
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/Symbols.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Utils/Unify.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Types/Var/FV.hs
- configure.ac
- docs/users_guide/exts/type_data.rst
- docs/users_guide/runtime_control.rst
- hadrian/src/Base.hs
- hadrian/src/Builder.hs
- hadrian/src/Hadrian/Builder.hs
- hadrian/src/Hadrian/Builder/Ar.hs
- hadrian/src/Hadrian/Oracles/Path.hs
- hadrian/src/Hadrian/Utilities.hs
- hadrian/src/Oracles/Setting.hs
- hadrian/src/Oracles/TestSettings.hs
- hadrian/src/Rules/BinaryDist.hs
- hadrian/src/Rules/Changelog.hs
- hadrian/src/Rules/Codes.hs
- hadrian/src/Rules/Lint.hs
- hadrian/src/Rules/Nofib.hs
- hadrian/src/Rules/Test.hs
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/ghc-internal/include/RtsIfaceSymbols.h
- libraries/ghc-internal/src/GHC/Internal/Conc/IO.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Thread.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- m4/find_python.m4
- + m4/fp_canonicalise_win_path.m4
- m4/fp_find_nm.m4
- m4/fp_find_root.m4
- m4/fp_prog_ar.m4
- m4/fp_prog_ar_args.m4
- m4/fp_prog_sh.m4
- m4/fptools_alex.m4
- m4/fptools_happy.m4
- rts/Capability.c
- rts/Continuation.c
- rts/ContinuationOps.cmm
- rts/HeapStackCheck.cmm
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/Interpreter.c
- rts/Messages.c
- rts/Prelude.h
- rts/PrimOps.cmm
- rts/Printer.c
- rts/RaiseAsync.c
- rts/STM.c
- rts/Schedule.c
- rts/Sparks.c
- rts/StableName.c
- rts/StgMiscClosures.cmm
- rts/ThreadPaused.c
- rts/Threads.c
- rts/Trace.h
- rts/configure.ac
- rts/include/rts/Flags.h
- rts/include/rts/RtsToHsIface.h
- rts/include/rts/storage/Closures.h
- rts/include/stg/MiscClosures.h
- rts/posix/Poll.c
- rts/posix/Poll.h
- rts/posix/Select.c
- + rts/posix/SelectBis.c
- + rts/posix/SelectBis.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
- rts/rts.cabal
- rts/sm/Compact.c
- rts/sm/Evac.c
- rts/sm/GC.c
- rts/sm/GCUtils.c
- rts/sm/MBlock.c
- rts/sm/NonMoving.c
- rts/sm/NonMovingMark.c
- rts/sm/Storage.c
- rts/sm/Sweep.c
- + testsuite/tests/bytecode/T27633/Obj.hs
- + testsuite/tests/bytecode/T27633/T27633a.hs
- + testsuite/tests/bytecode/T27633/T27633a.stdout
- + testsuite/tests/bytecode/T27633/T27633b.hs
- + testsuite/tests/bytecode/T27633/T27633b.stdout
- + testsuite/tests/bytecode/T27633/all.T
- + testsuite/tests/codeGen/should_gen_asm/T25233.asm
- + testsuite/tests/codeGen/should_gen_asm/T25233.hs
- + testsuite/tests/codeGen/should_gen_asm/T25233b.asm
- + testsuite/tests/codeGen/should_gen_asm/T25233b.cmm
- testsuite/tests/codeGen/should_gen_asm/all.T
- testsuite/tests/codeGen/should_run/all.T
- testsuite/tests/ghc-api/T25121_status.stdout
- + testsuite/tests/ghci.debugger/scripts/T27633c.hs
- + testsuite/tests/ghci.debugger/scripts/T27633c.script
- + testsuite/tests/ghci.debugger/scripts/T27633c.stdout
- + testsuite/tests/ghci.debugger/scripts/T27633c_obj.hs
- testsuite/tests/ghci.debugger/scripts/all.T
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- + testsuite/tests/javascript/T27788.hs
- + testsuite/tests/javascript/T27788.stdout
- testsuite/tests/javascript/all.T
- testsuite/tests/parser/should_compile/DumpParsedAstComments.stderr
- testsuite/tests/parser/should_compile/DumpSemis.stderr
- testsuite/tests/printer/Test20297.stdout
- testsuite/tests/rename/should_fail/RnStaticPointersFail01.stderr
- testsuite/tests/rename/should_fail/RnStaticPointersFail03.stderr
- testsuite/tests/rename/should_fail/T26545.stderr
- + testsuite/tests/rts/T27477.hs
- + testsuite/tests/rts/T27477.stdout
- + testsuite/tests/rts/T27618.hs
- + testsuite/tests/rts/T27618.stdout
- + testsuite/tests/rts/T27649.hs
- + testsuite/tests/rts/T27649.stdout
- testsuite/tests/rts/all.T
- + testsuite/tests/rts/continuations/T27651.hs
- + testsuite/tests/rts/continuations/T27651.stdout
- testsuite/tests/rts/continuations/all.T
- testsuite/tests/simplCore/should_compile/Makefile
- + testsuite/tests/simplCore/should_compile/T27629.hs
- + testsuite/tests/simplCore/should_compile/T27629.stderr
- + testsuite/tests/simplCore/should_compile/T27629Plugin.hs
- + testsuite/tests/simplCore/should_compile/T27749.hs
- + testsuite/tests/simplCore/should_compile/T27749.stderr
- testsuite/tests/simplCore/should_compile/all.T
- + testsuite/tests/type-data/should_fail/T27732a.hs
- + testsuite/tests/type-data/should_fail/T27732a.stderr
- + testsuite/tests/type-data/should_fail/T27732b.hs
- + testsuite/tests/type-data/should_fail/T27732b.stderr
- + testsuite/tests/type-data/should_fail/T27732c.hs
- + testsuite/tests/type-data/should_fail/T27732c.stderr
- + testsuite/tests/type-data/should_fail/T27732d.hs
- + testsuite/tests/type-data/should_fail/T27732d.stderr
- + testsuite/tests/type-data/should_fail/T27732e.hs
- + testsuite/tests/type-data/should_fail/T27732e.stderr
- + testsuite/tests/type-data/should_fail/T27732f.hs
- + testsuite/tests/type-data/should_fail/T27732f.stderr
- testsuite/tests/type-data/should_fail/TDStrictnessGADT.stderr
- testsuite/tests/type-data/should_fail/TDStrictnessH98.stderr
- testsuite/tests/type-data/should_fail/all.T
- + testsuite/tests/typecheck/should_compile/T26543_orig.hs
- + testsuite/tests/typecheck/should_compile/T27664.hs
- testsuite/tests/typecheck/should_compile/all.T
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Utils.hs
- utils/deriveConstants/Main.hs
- utils/hsc2hs
- utils/jsffi/dyld.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e2f4f707b4ea34b99a04a761161856…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e2f4f707b4ea34b99a04a761161856…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/fendor/has-field-hie] 3 commits: Record `FieldLabel` source span in AST node
by Hannes Siebenhandl (@fendor) 16 Sep '26
by Hannes Siebenhandl (@fendor) 16 Sep '26
16 Sep '26
Hannes Siebenhandl pushed to branch wip/fendor/has-field-hie at Glasgow Haskell Compiler / GHC
Commits:
caf1171c by fendor at 2026-09-16T13:16:10+02:00
Record `FieldLabel` source span in AST node
We attach evidence variables based on the source span of the concrete
AST node in the HIE file.
The evidence for the `HasField` constraint has the source span of the
field selector, e.g. the AST node that gave rise to the `HasField`
constraint.
Since the AST node doesn't show up in the HIE file, the evidence for
`HasField` was also not recorded for the span. Thus, `getEvidenceTree`
wouldn't even list `HasField` as evidence, even in the perfectly normal
case of:
baz :: HasField "foo" f Int => f -> Int
baz f = f.foo
Requesting the evidence tree for `.foo` should point to the definition
of `baz`, but since we omitted the source span for the field selector `.foo`
from the AST node, the HIE file doesn't list it as evidence.
By using the source spans of the individual field selectors, there are two consequences:
* We can see the `HasField` evidence for record dot syntax at the field
selector span
* The reported type of `.foo` is `Foo -> Int` instead of just `Int`
The latter is a change of behaviour that is unfortunate but the right
behaviour, since there is now a source span for the whole expression
`x.foo`, one for `x` and one for the selector `.foo`.
If you query for the type at span `x.foo`, then the correct type `Int`
is shown, but in downstream tooling (such as HLS), such requests are not
possible in LSP. Thus, the behaviour changes.
- - - - -
cb9e4d0f by fendor at 2026-09-16T13:30:01+02:00
Allow any `Id` to be used for HIE evidence
HIE evidence is used to show how a constraint has been solved and allows
users to go directly to the definition or introduction of a particular
evidence variable.
So far, we only looked at evidence introduced by type class variables,
but some evidence terms refer to other variables as well, such as record selectors.
Such evidence terms add additional details and source locations.
For generated evidence, such as `HasField` evidence to support
`-XRecordDotSyntax`, the type class evidence is lacking and doesn't
give us any usable source span pointing to the actual record selector.
See this example evidence:
$dHasField_aLw
= GHC.Internal.Records.C:HasField
@GHC.Internal.Types.Symbol
@GHC.Internal.Types.LiftedRep
@GHC.Internal.Types.LiftedRep
@"foo"
@Foo
@Int
(foo `cast` (<Foo -> Int>_R :: (Foo -> Int) ~R# (Foo -> Int)))
The free variables of this term are `{C:HasField, foo}`.
`foo` is the record selector from the type `Foo` and is crucial to guide
users how this evidence is constructed, as the evidence `HasField` is
not helpful.
During HIE generation, we now take any `Id` into account to provide
additional source spans to point to user to the definition site of the
record selector.
As a direct consequence, this allows HLS to implement a limited form of
`Goto Definition` for expressions of the form `x.foo`, where `x :: Foo`.
Capturing more `Id`s for evidence may have some side effects that are
somewhat tricky to predict, since the tests are quite lacking.
- - - - -
1793ebd8 by fendor at 2026-09-16T13:30:01+02:00
Add additional details to evidence bindings
Evidence bindings can be all sorts of things, such as type class
evidence, a record selector or other builtin constructs such as
`Typeable`.
- - - - -
12 changed files:
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Iface/Ext/Types.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Rename/Expr.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
- + testsuite/tests/hiefile/should_run/HieTypeable.hs
- + testsuite/tests/hiefile/should_run/HieTypeable.stdout
- testsuite/tests/hiefile/should_run/RecordDotTypes.hs
- testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
- testsuite/tests/hiefile/should_run/T23492.stdout
- testsuite/tests/hiefile/should_run/all.T
Changes:
=====================================
compiler/GHC/Iface/Ext/Ast.hs
=====================================
@@ -23,7 +23,6 @@ import GHC.Core.DataCon ( dataConWrapperType )
import GHC.Core.Type ( Type, ForAllTyFlag(..) )
import GHC.Core.TyCon ( TyCon, tyConClass_maybe )
import GHC.Core.InstEnv
-import GHC.Core.Predicate ( isEvId )
import GHC.Hs
import GHC.Hs.Syn.Type
@@ -33,7 +32,7 @@ import GHC.Types.Basic
import GHC.Types.UnresolvedImport ( isGeneratedImport )
import GHC.Types.FieldLabel
import GHC.Types.Avail ( Avails )
-import GHC.Types.Id ( isDataConId_maybe )
+import GHC.Types.Id ( isDataConId_maybe, isId, idDetails )
import GHC.Types.Name ( Name, nameSrcSpan, nameUnique, wiredInNameTyThing_maybe, getName )
import GHC.Types.Name.Env ( NameEnv, emptyNameEnv, extendNameEnv, lookupNameEnv )
import GHC.Types.Name.Reader ( RecFieldInfo(..), WithUserRdr(..) )
@@ -81,6 +80,7 @@ import Control.Applicative ( (<|>) )
import GHC.Types.TypeEnv ( TypeEnv )
import Control.Arrow ( second )
import Data.Traversable ( mapAccumR )
+import GHC.Types.Id.Info (IdDetails(..), recSelParentName)
{- Note [Updating HieAst for changes in the GHC AST]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -682,7 +682,7 @@ instance ToHie (Context (Located (WithUserRdr Name))) where
hieEvIdsOfTerm :: EvTerm -> [EvId]
-- Returns only EvIds satisfying relevantEvId
-hieEvIdsOfTerm = runFVSelectiveList isEvId . evTermFVs
+hieEvIdsOfTerm = runFVSelectiveList isId . evTermFVs
instance ToHie (EvBindContext (LocatedA TcEvBinds)) where
toHie (EvBindContext sc sp (L span (EvBinds bs)))
@@ -690,7 +690,7 @@ instance ToHie (EvBindContext (LocatedA TcEvBinds)) where
where
go evbind = do
let evDeps = hieEvIdsOfTerm $ eb_rhs evbind
- depNames = EvBindDeps $ map varName evDeps
+ depNames = EvBindDeps $ map classifyEvDeps evDeps
concatM $
[ toHie (C (EvidenceVarBind (EvLetBind depNames) (combineScopes sc (mkScope span)) sp)
(L span $ eb_lhs evbind))
@@ -698,6 +698,12 @@ instance ToHie (EvBindContext (LocatedA TcEvBinds)) where
]
toHie _ = pure []
+classifyEvDeps :: EvId -> EvBindDep
+classifyEvDeps evId =
+ case idDetails evId of
+ RecSelId{sel_tycon} -> RecordField (varName evId) (recSelParentName sel_tycon)
+ _ -> EvidenceVar (varName evId)
+
instance ToHie (LocatedA HsWrapper) where
toHie (L osp wrap)
= case wrap of
=====================================
compiler/GHC/Iface/Ext/Types.hs
=====================================
@@ -598,17 +598,61 @@ instance Outputable EvVarSource where
ppr (EvInstBind True cls) = text "bound due to a superclass of " <+> ppr cls
ppr (EvLetBind deps) = text "bound by a let, depending on:" <+> ppr deps
+data EvBindDep
+ = EvidenceVar Name
+ | RecordField Name Name
+ | TypeableEvidence Name
+ deriving (Eq, Ord)
+
+instance Outputable EvBindDep where
+ ppr = \ case
+ EvidenceVar n -> ppr n
+ RecordField sel parent -> ppr sel <+> text "of Record" <+> ppr parent
+ TypeableEvidence n -> ppr n <+> text "bound by Typeable"
+
+evBindDepName :: EvBindDep -> Name
+evBindDepName = \ case
+ EvidenceVar n -> n
+ RecordField selector _record -> selector
+ TypeableEvidence n -> n
+
+evBindDepHieName :: EvBindDep -> HieName
+evBindDepHieName = toHieName . evBindDepName
+
+instance Binary EvBindDep where
+ put_ bh = \ case
+ EvidenceVar n -> do
+ putByte bh 0
+ put_ bh n
+ RecordField n sel -> do
+ putByte bh 1
+ put_ bh n
+ put_ bh sel
+ TypeableEvidence n -> do
+ putByte bh 2
+ put_ bh n
+
+ get bh =
+ getByte bh >>= \ case
+ 0 -> EvidenceVar <$> get bh
+ 1 -> RecordField <$> get bh <*> get bh
+ 2 -> TypeableEvidence <$> get bh
+ t -> fail $ "EvBindDep: Unknown tag: " ++ show t
+
-- | Eq/Ord instances compare on the converted HieName,
-- as non-exported names may have different uniques after
-- a roundtrip
-newtype EvBindDeps = EvBindDeps { getEvBindDeps :: [Name] }
+newtype EvBindDeps = EvBindDeps { getEvBindDeps :: [EvBindDep] }
deriving Outputable
+evBindDepsNames :: EvBindDeps -> [Name]
+evBindDepsNames = map evBindDepName . getEvBindDeps
+
instance Eq EvBindDeps where
- (==) = coerce ((==) `on` map toHieName)
+ (==) = coerce ((==) `on` map evBindDepHieName)
instance Ord EvBindDeps where
- compare = coerce (compare `on` map toHieName)
+ compare = coerce (compare `on` map evBindDepHieName)
instance Binary EvBindDeps where
put_ bh (EvBindDeps xs) = put_ bh xs
=====================================
compiler/GHC/Iface/Ext/Utils.hs
=====================================
@@ -82,15 +82,19 @@ resolveVisibility kind ty_args
foldType :: (HieType a -> a) -> HieTypeFix -> a
foldType f (Roll t) = f $ fmap (foldType f) t
-selectPoint :: HieFile -> (Int,Int) -> Maybe (HieAST Int)
-selectPoint hf (sl,sc) = getFirst $
+selectPoint :: HieFile -> (Int,Int) -> Maybe (HieAST TypeIndex)
+selectPoint hf p = selectRange hf p p
+
+selectRange :: HieFile -> (Int,Int) -> (Int,Int) -> Maybe (HieAST TypeIndex)
+selectRange hf (sl,sc) (el, ec) = getFirst $
flip foldMap (M.toList (getAsts $ hie_asts hf)) $ \(HiePath fs,ast) -> First $
case selectSmallestContaining (sp fs) ast of
Nothing -> Nothing
Just ast' -> Just ast'
where
sloc fs = mkRealSrcLoc fs sl sc
- sp fs = mkRealSrcSpan (sloc fs) (sloc fs)
+ eloc fs = mkRealSrcLoc fs el ec
+ sp fs = mkRealSrcSpan (sloc fs) (eloc fs)
findEvidenceUse :: NodeIdentifiers a -> [Name]
findEvidenceUse ni = [n | (Right n, dets) <- xs, any isEvidenceUse (identInfo dets)]
@@ -141,7 +145,7 @@ getEvidenceTree refmap var = go emptyNameSet var
det <- S.toList $ identInfo dets
case det of
EvidenceVarBind src@(EvLetBind (getEvBindDeps -> xs)) scp spn ->
- pure $ Just ((src,scp,spn),mapMaybe (go $ extendNameSet seen var) xs)
+ pure $ Just ((src,scp,spn),mapMaybe (go (extendNameSet seen var) . evBindDepName) xs)
EvidenceVarBind src scp spn -> pure $ Just ((src,scp,spn),[])
_ -> pure Nothing
pure $ Tree.Node (EvidenceInfo var sp typ (Just evdet)) children
@@ -386,7 +390,7 @@ definedInAsts asts n = case nameSrcSpan n of
getEvidenceBindDeps :: ContextInfo -> [Name]
getEvidenceBindDeps (EvidenceVarBind (EvLetBind xs) _ _) =
- getEvBindDeps xs
+ evBindDepsNames xs
getEvidenceBindDeps _ = []
isEvidenceBind :: ContextInfo -> Bool
=====================================
compiler/GHC/Rename/Expr.hs
=====================================
@@ -422,7 +422,7 @@ rnExpr (HsGetField _ e f)
; let f' = rnDotFieldOcc <$> f
; return ( mkExpandedExpr
(HsGetField noExtField e f')
- (mkGetField getField e (fmap (unLoc . dfoLabel) f'))
+ (mkGetField getField e (dfoLabel $ unLoc f'))
, fv_e `plusFN` fv_getField ) }
rnExpr (HsProjection _ fs)
@@ -431,7 +431,7 @@ rnExpr (HsProjection _ fs)
; let fs' = NE.map rnDotFieldOcc fs
; return ( mkExpandedExpr
(HsProjection noExtField fs')
- (mkProjection getField circ $ NE.map (unLoc . dfoLabel) fs')
+ (mkProjection getField circ $ NE.map dfoLabel fs')
, unitFN circ `plusFN` fv_getField) }
------------------------------------------
@@ -2882,8 +2882,9 @@ rnHsIf p b1 b2
-- mkGetField arg field calculates a get_field @field arg expression.
-- e.g. z.x = mkGetField z x = get_field @x z
-mkGetField :: Name -> LHsExpr GhcRn -> LocatedAn NoEpAnns FieldLabelString -> HsExpr GhcRn
-mkGetField get_field arg field = unLoc (head $ mkGet get_field (arg :| []) field)
+mkGetField :: Name -> LHsExpr GhcRn -> XRec GhcRn FieldLabelString -> HsExpr GhcRn
+mkGetField get_field arg field =
+ HsApp noExtField (mkGetField' get_field field) arg
-- mkSetField a field b calculates a set_field @field expression.
-- e.g mkSetSetField a field b = set_field @"field" a b (read as "set field 'field' to a on b").
@@ -2902,14 +2903,16 @@ mkSet set_field acc (field, g) = wrapGenSpan (mkSetField set_field g field acc)
-- mkProjection fields calculates a projection.
-- e.g. .x = mkProjection [x] = getField @"x"
-- .x.y = mkProjection [.x, .y] = (.y) . (.x) = getField @"y" . getField @"x"
-mkProjection :: Name -> Name -> NonEmpty FieldLabelString -> HsExpr GhcRn
-mkProjection getFieldName circName (field :| fields) = foldl' f (proj field) fields
+mkProjection :: Name -> Name -> NonEmpty (XRec GhcRn FieldLabelString) -> HsExpr GhcRn
+mkProjection getFieldName circName (field :| fields) =
+ unLoc $ foldl' f (mkGetField' getFieldName field) fields
where
- f :: HsExpr GhcRn -> FieldLabelString -> HsExpr GhcRn
- f acc field = genHsApps circName $ map wrapGenSpan [proj field, acc]
+ f :: LHsExpr GhcRn -> XRec GhcRn FieldLabelString -> LHsExpr GhcRn
+ f acc field = wrapGenSpan $ genHsApps circName [mkGetField' getFieldName field, acc]
- proj :: FieldLabelString -> HsExpr GhcRn
- proj (FieldLabelString f) = genHsVar getFieldName `genAppType` genHsTyLit f
+mkGetField' :: Name -> XRec GhcRn FieldLabelString -> LHsExpr GhcRn
+mkGetField' getFieldName (L ann (FieldLabelString f)) =
+ wrapGenSpan' (getHasLoc ann) (genHsVar getFieldName `genAppType` genHsTyLit f)
-- mkProjUpdateSetField calculates functions representing dot notation record updates.
-- e.g. Suppose an update like foo.bar = 1.
=====================================
testsuite/tests/hiefile/should_run/HasFieldQueries.hs
=====================================
@@ -0,0 +1,52 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+module Main where
+
+import TestUtils
+import GHC.Records
+import GHC.TypeLits
+import Data.Tree
+
+data Thing = Thing {field1 :: Char, field2 :: Bool}
+ deriving (Show, Eq)
+
+foo :: Thing -> String
+foo t = show t.field1
+-- ^ this is the point
+
+testing2 (x :: Thing) = x.field1
+-- ^ this is the point
+-- ^ this is the point
+
+data NestedThing = NestedThing { nested1 :: Thing }
+
+nestedSig :: NestedThing -> Char
+nestedSig n = n.nested1.field1
+-- ^ this is the point
+-- ^ this is the point
+
+nestedNoSig n = n.nested1.field2 :: Bool
+-- ^ this is the point
+-- ^ this is the point
+
+
+withConstraint :: HasField "field1" x Char => x -> Char
+withConstraint x = x.field1
+-- ^ this is the point
+
+points =
+ [ (13,17)
+ , (16,25)
+ , (16,27)
+ , (23,17)
+ , (23,25)
+ , (27,20)
+ , (27,28)
+ , (33,22)
+ ]
+
+main = do
+ (df, hf) <- readTestHie "HasFieldQueries.hie"
+ let refmap = generateReferencesMap $ getAsts $ hie_asts hf
+
+ traverse (explainEv df hf refmap) points
+ return ()
=====================================
testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
=====================================
@@ -0,0 +1,156 @@
+==========================
+At point (13,17), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1 of Record Thing]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (16,25), we found:
+==========================
+==========================
+At point (16,27), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:16:1-32, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1 of Record Thing]
+│ with scope: LocalScope HasFieldQueries.hs:16:1-32
+│ bound at: HasFieldQueries.hs:16:1-32
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (23,17), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "nested1" NestedThing Thing
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ nested1 of Record NestedThing]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ nested1 at HasFieldQueries.hs:1:1, of type: NestedThing -> Thing
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:20:34
+ └
+
+==========================
+At point (23,25), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1 of Record Thing]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (27,20), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:27:1-40
+│ bound at: HasFieldQueries.hs:27:1-40
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
+ │ is an evidence variable bound by a type signature
+ │ with scope: LocalScope HasFieldQueries.hs:27:1-40
+ │ bound at: HasFieldQueries.hs:27:1-40
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (27,28), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:27:1-40
+│ bound at: HasFieldQueries.hs:27:1-40
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
+ │ is an evidence variable bound by a type signature
+ │ with scope: LocalScope HasFieldQueries.hs:27:1-40
+ │ bound at: HasFieldQueries.hs:27:1-40
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (33,22), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:33:1-27
+│ bound at: HasFieldQueries.hs:33:1-27
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
+ │ is an evidence variable bound by a HsWrapper
+ │ with scope: LocalScope HasFieldQueries.hs:33:1-27
+ │ bound at: HasFieldQueries.hs:33:1-27
+ │ Defined at <no location info>
+ └
+
=====================================
testsuite/tests/hiefile/should_run/HieTypeable.hs
=====================================
@@ -0,0 +1,28 @@
+module Main where
+
+import Data.Dynamic
+import Data.Typeable
+import TestUtils
+
+data Thing = Thing {field1 :: Char, field2 :: Bool}
+ deriving (Show, Eq)
+
+castFromDynamic :: Dynamic -> Maybe Thing
+castFromDynamic d = fromDynamic d
+ -- ^ this is the point
+
+rep :: Thing -> TypeRep
+rep d = typeOf d
+ -- ^ this is the point
+
+points =
+ [ (11,21)
+ , (15,10)
+ ]
+
+main = do
+ (df, hf) <- readTestHie "HieTypeable.hie"
+ let refmap = generateReferencesMap $ getAsts $ hie_asts hf
+
+ traverse (explainEv df hf refmap) points
+ return ()
=====================================
testsuite/tests/hiefile/should_run/HieTypeable.stdout
=====================================
@@ -0,0 +1,30 @@
+==========================
+At point (11,21), we found:
+==========================
+┌
+│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+│ is an evidence variable bound by a let, depending on: [$dTypeable]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+ │ is an evidence variable bound by a let, depending on: []
+ │ with scope: ModuleScope
+ │
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (15,10), we found:
+==========================
+┌
+│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+│ is an evidence variable bound by a let, depending on: []
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+
=====================================
testsuite/tests/hiefile/should_run/RecordDotTypes.hs
=====================================
@@ -22,6 +22,11 @@ x = MyRecord { a = "Hello", b = 12, c = MyChild { z = "there" } }
y = x.a ++ show x.b ++ x.c.z
-- ^ ^ ^ ^^
-- 1 2 3 45
+-- ^-^ ^-^ ^-^
+-- 6 7 8
+-- ^---^
+-- 9
+
p1,p2,p3,p4 :: (Int,Int)
p1 = (22,6)
@@ -30,10 +35,19 @@ p3 = (22,25)
p4 = (22,28)
p5 = (22,29)
+r6 = (p1, (22, 8))
+r7 = ((22,17), p2)
+r8 = (p3, (22, 27))
+r9 = (p3, p5)
+
selectPoint' :: HieFile -> (Int,Int) -> HieAST Int
selectPoint' hf loc =
maybe (error "point not found") id $ selectPoint hf loc
+selectRange' :: HieFile -> ((Int,Int), (Int, Int)) -> HieAST Int
+selectRange' hf (s, e) =
+ maybe (error "range not found") id $ selectRange hf s e
+
main = do
(df, hf) <- readTestHie "RecordDotTypes.hie"
forM_ [p1,p2,p3,p4,p5] $ \point -> do
@@ -41,3 +55,11 @@ main = do
let types = concatMap nodeType $ getSourcedNodeInfo $ sourcedNodeInfo $ selectPoint' hf point
forM_ types $ \typ -> do
putStrLn (renderHieType df $ recoverFullType typ (hie_types hf))
+
+ forM_ [r6, r7, r8, r9] $ \range -> do
+ putStr $ "At " ++ showRange range ++ ", got type: "
+ let types = concatMap nodeType $ getSourcedNodeInfo $ sourcedNodeInfo $ selectRange' hf range
+ forM_ types $ \typ -> do
+ putStrLn (renderHieType df $ recoverFullType typ (hie_types hf))
+ where
+ showRange (p1, p2) = show p1 ++ " - " ++ show p2
=====================================
testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
=====================================
@@ -1,5 +1,9 @@
At (22,6), got type: MyRecord
-At (22,20), got type: Integer
+At (22,20), got type: MyRecord -> Integer
At (22,25), got type: MyRecord
-At (22,28), got type: String
-At (22,29), got type: String
\ No newline at end of file
+At (22,28), got type: MyChild -> [Char]
+At (22,29), got type: MyChild -> [Char]
+At (22,6) - (22,8), got type: [Char]
+At (22,17) - (22,20), got type: Integer
+At (22,25) - (22,27), got type: MyChild
+At (22,25) - (22,29), got type: [Char]
=====================================
testsuite/tests/hiefile/should_run/T23492.stdout
=====================================
@@ -4,4 +4,4 @@ PartialFieldSelector
At (18,7), got type: PartialFieldSelector -> Bool
At (23,7), got type: PartialFieldSelector
At (23,8), got type: PartialFieldSelector
-At (23,9), got type: Bool
+At (23,9), got type: PartialFieldSelector -> Bool
=====================================
testsuite/tests/hiefile/should_run/all.T
=====================================
@@ -10,3 +10,4 @@ test('T23120', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUti
test('T24544', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
test('HieGadtConSigs', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
test('T25709', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
+test('HasFieldQueries', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8926227e75bdaeaf3f2a649f2d1edf…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/8926227e75bdaeaf3f2a649f2d1edf…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/jeltsch/improve-closure-property-check] Replace `ShortText` by `UnitAbiHash`
by Wolfgang Jeltsch (@jeltsch) 16 Sep '26
by Wolfgang Jeltsch (@jeltsch) 16 Sep '26
16 Sep '26
Wolfgang Jeltsch pushed to branch wip/jeltsch/improve-closure-property-check at Glasgow Haskell Compiler / GHC
Commits:
32c0a8d0 by Wolfgang Jeltsch at 2026-09-16T14:22:40+03:00
Replace `ShortText` by `UnitAbiHash`
- - - - -
1 changed file:
- compiler/GHC/Driver/Downsweep.hs
Changes:
=====================================
compiler/GHC/Driver/Downsweep.hs
=====================================
@@ -57,7 +57,6 @@ import Language.Haskell.Syntax.ImpExp
import GHC.Types.UnresolvedImport
import GHC.Data.FastString
-import GHC.Data.ShortText ( ShortText )
import GHC.Data.Maybe ( expectJust )
import qualified GHC.Data.Maybe as M
import GHC.Data.OsPath ( OsPath, unsafeEncodeUtf )
@@ -96,6 +95,7 @@ import GHC.Unit.Module.Graph
import GHC.Unit.Module.Deps
import qualified GHC.Unit.Home.Graph as HUG
import GHC.Unit.Module.Stage
+import GHC.Unit.External.Index (UnitAbiHash)
import Data.Either ( partitionEithers, lefts )
import Data.Map (Map)
@@ -979,7 +979,7 @@ checkHomeUnitsClosed unit_env
collect :: [UnitState]
-- ^ The 'UnitState's of the home units from which to traverse
-- the dependency graph.
- -> State (UniqMap UnitId (Set ShortText)) [(UnitId, UnitId)]
+ -> State (UniqMap UnitId (Set UnitAbiHash)) [(UnitId, UnitId)]
-- ^ A stateful computation that collects offending dependencies
-- that have not yet been found. It uses its state, which is an
-- efficent representation of a set of 'GlobalUnitKey's, to
@@ -999,7 +999,7 @@ checkHomeUnitsClosed unit_env
-> [UnitId]
-- ^ The 'UnitId's of the units from which to traverse the dependency
-- graph.
- -> State (UniqMap UnitId (Set ShortText)) [(UnitId, UnitId)]
+ -> State (UniqMap UnitId (Set UnitAbiHash)) [(UnitId, UnitId)]
-- ^ A stateful computation that collects offending dependencies that
-- have not yet been found. It uses its state, which is an efficent
-- representation of a set of 'GlobalUnitKey's, to keep track of
@@ -1022,7 +1022,7 @@ checkHomeUnitsClosed unit_env
unit_not_found_msg = "Unit not found during closure property check"
-- | The ABI hash of the current unit.
- unit_abi_hash :: ShortText
+ unit_abi_hash :: UnitAbiHash
unit_abi_hash = unitAbiHash unit_info
has_been_processed <- gets $ maybe False (Set.member unit_abi_hash) .
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/32c0a8d0c1a4d90e6c1444c6d31d10f…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/32c0a8d0c1a4d90e6c1444c6d31d10f…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 13 commits: Refactor (and rename) removeFromQueues, to simplify I/O managers
by Marge Bot (@marge-bot) 16 Sep '26
by Marge Bot (@marge-bot) 16 Sep '26
16 Sep '26
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
8e09a46f by Duncan Coutts at 2026-09-15T20:11:35-04:00
Refactor (and rename) removeFromQueues, to simplify I/O managers
Rename it to unblockAndAppendToRunQueue which better reflects what it is
intended to do.
The post-condition for unblockAndAppendToRunQueue is that the TSO is on
the run queue or it is in the process of migrating to another cap.
Previously it achieved that by always directly adding the TSO to the run
queue itself.
But this actually made things more complicated for the I/O managers,
because it meant they needed a separate code path for notifying for
cancellation compared to notifying for completion. The general
notification code would always add the TSO to the run queue itself.
So the improvement is to allow different cases in
unblockAndAppendToRunQueue to achieve the same outcome in different
ways: either directly adding to the run queue or calling helper
functions that do so themselves.
This then allows the new I/O managers to share code between the sync and
async cancellation, and to reuse their notifyIOCompletion helpers for
cancellation. This avoids a source of bugs where the completion path may
be updated but the cancellation path may be forgotten, or similarly in
future for sync/async operations.
Update all the existing in-RTS I/O managers, and the posix timeout code.
- - - - -
d668782c by Duncan Coutts at 2026-09-15T20:11:35-04:00
Document that awaitCompletedTimeoutsOrIO expects an empty run queue
This was true before but implicit and not relied on much. It's better to
be explicit, and allow things to depend on it.
- - - - -
11d938bb by Duncan Coutts at 2026-09-15T20:11:35-04:00
Store the I/O opcode and fd in the StgAsyncIOOp
This will be useful in several I/O managers and it is handy for logging
and debugging.
It also doesn't increase the size of the StgAsyncIOOp structure. There
was enough spare padding space already.
Update the poll I/O manager to set the new fields.
Add a helper function to convert the enum IOReadOrWrite into the enum
IOOpCode. Also change IOReadOrWrite to be an enum without a typedef, for
consistency with other enumerations in IOManager.h
- - - - -
bfa87882 by Duncan Coutts at 2026-09-15T20:11:36-04:00
Add a new I/O manager based on select()
Yes, this is the second such I/O manager, but it is a modern
re-implementation based on the new in-RTS I/O manager infrastructure. So
it is cleaner and faster than the old select I/O manager.
Why do we need another I/O manager based on select? Why isn't the poll()
one good enough as a baseline portable unix I/O manager? Because macOS.
Apple Inc. is why we cannot have nice things.
The man page for poll on macOS documents the fact that it does not work.
At least, it does not work for all files. Specifically, it does not work
for device files. Whereas macOS select() does work for device files.
Aaaaarg!
We _do_ want to deprecate and remove the old select I/O manager, but due to
macOS we cannot do that until we have a replacement. This is that
replacement. Until of course a nice new k-queue I/O manager arrives,
which could become the new default for macOS and FreeBSD.
Interestingly, this select I/O manager is actually faster than the poll
one, on Linix, in some circumstances: specifically when many Haskell
threads are waiting on the same fd. The poll I/O manager does O(n) work
for n threads waiting on I/O, whereas the select one does O(fds) work
for the number of fds that threads are waiting on. Usually this is 1:1,
so it's not noticable, but one can concoct extreme benchmarks to show
the difference.
- - - - -
8e9de15a by Duncan Coutts at 2026-09-15T20:11:36-04:00
Minor updates in the poll I/O manager to keep in sync with select
This keeps it in sync with select one. The changes are based on code review
while implementing the new select I/O manager. The two I/O managers are so
similar in structure that it makes sense to try to minimise the diff between
them. This should aid understanding, and fixes to both in future.
- - - - -
222668bb by Duncan Coutts at 2026-09-15T20:11:36-04:00
Document the new select I/O manager in the user guide
in the RTS section about I/O managers.
And add a changelog entry.
- - - - -
0f48735b by Cheng Shao at 2026-09-15T20:12:23-04:00
Revert "wasm: workaround WebKit bug in dyld"
This reverts commit c9b8465c2c338176fcab9d197e9d31f4aee11f68. The
underlying webkit bug has been fixed in
https://commits.webkit.org/314219@main. Closes #27564.
- - - - -
809294f1 by Luite Stegeman at 2026-09-15T20:13:08-04:00
rts: make stg_threadLabelzh return a valid pointer for unlabeled threads.
This fixes a segfault in the GC caused by stg_threadLabelzh returning
a 0 pointer in a GC pointer field.
stg_threadLabelzh returns a tuple of type (# Int#, ByteArray# #). If a
thread has no label, the second field is unused. We must still return
a valid heap object pointer.
Instead of returning 0, we now return stg_DEAD_SLOT_closure.
fixes #27618
- - - - -
e2d57026 by Luite Stegeman at 2026-09-15T20:13:54-04:00
JS: fix selector thunk handling
fix a bug where entering a selector thunk could lead to a crash
if the selected field was still a thunk.
fixes #27788
- - - - -
30a1cdae by sheaf at 2026-09-16T06:58:21-04:00
Improvements to type/data family handling
This commit makes several improvements to the treatment of type and data
families in GHC:
- We consistently use "type family" instead of "type synonym family"
to avoid a confusion with type synonyms. For example:
- OpenSynFamilyTyCon ==> OpenTypeFamilyTyCon
- ClosedSynFamilyTyCon => ClosedTypeFamilyTyCon
- Various functions that were specific to data families have been
renamed to make this clear. For example:
- tyConFamInst_maybe ==> tyConDataFamInst_maybe
- isFamInstTyCon ==> isDataFamInstTyCon
- 'FamTyConFlav' has been refactored so that all closed type families
share a single 'ClosedTypeFamilyTyCon' constructor.
The corresponding 'IfaceFamTyConFlav' type was updated similarly.
This is then used to tidy up the implementation of
GHC.Core.FamInstEnv.reduceTyFamApp_maybe.
- - - - -
a2f60b4b by sheaf at 2026-09-16T06:58:21-04:00
Small refactor of lookupFamInstEnv
This commit reworks the code for looking up family instances in
GHC.Core.FamInstEnv, reducing duplication a little bit.
No change in behaviour.
- - - - -
18fc4c62 by sheaf at 2026-09-16T06:58:22-04:00
Use a type family for boxing unboxed types
This commit overhauls the way in which unboxed types are boxed, as per
the updated Note [Boxing constructors] in GHC.Builtin.WiredIn.Types.Box.
The main change is to allow boxing to be parametrised by representation,
e.g. making 'Box ty' a valid type. We achieve this by implementing 'Box'
using a closed type family:
newtype Box (a :: TYPE r) = Box (BoxTF r)
type BoxTF :: RuntimeRep -> Type
type family BoxTF r where
BoxTF IntRep = BoxInt
BoxTF Int8Rep = BoxInt8
BoxTF WordRep = BoxWord
BoxTF LiftedRep = Any @Type
BoxTF (TupleRep [r1, r2]) = (BoxTF r1, BoxTF r2)
...
BoxTF (SumRep rs) = BoxSum rs
This new design solves the following problems:
- It allows boxing a type whose 'RuntimeRep' has not yet been
determined (e.g. because we only learn the 'RuntimeRep' after
constraint solving). That is, 'Box @r a' is a perfectly valid type
even if 'r' is an unfilled metavariable. This is a requirement
to fix #25065 (in which we need to box a type whose 'RuntimeRep'
is only filled in during constraint solving).
- It handles boxing of unboxed tuples and unboxed sums, via recursive
boxing. See Note [Boxing TupleRep and SumRep] in
GHC.Builtin.WiredIn.Types.Box.
'Box', 'BoxTF' and all of the boxing data constructors are defined in
a new 'ghc-internal' module, 'GHC.Internal.Box'. This module contains
nothing but wired-in declarations, and GHC never loads its interface on
account of a wired-in thing (GHC.Builtin.Modules.isWiredInOnlyModule);
see Note [Loading instances for wired-in things] in GHC.Iface.Load.
The individual boxing data constructors are deliberately left as an
internal implementation detail, and not exported. The intended API is
via the two new magic 'Id's:
box :: forall {r} (a :: TYPE r). a -> Box a
unbox :: forall {r} (a :: TYPE r). Box a -> a
exported from 'GHC.PrimOps' (in 'ghc-experimental'). The old boxing
data types (IntBox, WordBox, FloatBox, DoubleBox, DictBox) are no longer
exported from base (CLC proposal #421).
We use this new design to consistently desugar:
- parallel comprehensions (GHC.HsToCore.ListComp.{deListComp,dsMcStmt})
- then/group/using statements (GHC.HsToCore.ListComp.{dsTransStmt,dsMcStmt})
- recursive do blocks (mdo/rec) (GHC.HsToCore.Expr.dsDo)
- arrows (GHC.HsToCore.Arrows)
by consistently using 'box'/'unbox' to deal with unboxed types being put
into big tuples. We also adapt 'GHC.Tc.Gen.Match.{tcMcStmt,tcDoStmt}'
to create fresh /representation-polymorphic/ type variables for the
binders that we are going to put into a big tuple (previously, GHC only
allowed lifted types in that position).
These desugaring of box and unbox is explained in
Note [Desugaring box & unbox] in GHC.Core.Make.Box. Roughly speaking,
the desugaring looks like:
box @r @ty e ==> K e
unbox @r @ty e ==> case e of K x -> x
where 'K' is the boxing data constructor at RuntimeRep 'r'. It's
slightly more complicated than that in practice: we first need to
insert a cast (see Note [The canonical type of a RuntimeRep]) using the
new 'CanonicalProv' 'UnivCoProvenance', and unboxed tuples/sums need
recursive logic explained in Note [box/unbox for unboxed tuples and sums],
including a specific 'BoxSum' datatypes for unboxed sum (which also
needed a wired-in type-level list indexing type family (!!)).
The desugaring happens in two ways:
- Occurrences of 'box'/'unbox' emitted by the typechecker are
eliminated in the 'ds_app_var' case of GHC.HsToCore.Expr.
- Other code that needs to box/unbox emits the appropriate code inline.
This includes the big tuple machinery of GHC.Core.Make used by the
desugarer (GHC.HsToCore.{Utils,Binds,Arrows,ListComp}) as well as
the float-out pass (GHC.Core.Opt.SetLevels).
Core Lint checks that no occurrence of 'box'/'unbox' survives desugaring.
On the way, we overhaul the litany of big tuple functions by introducing
data BigTupleLayout = BoxedElements | BareElements
to distinguish the two kinds of "big tuples" that GHC routinely deals
with; for example 'mkBigCoreVarTupSolo' becomes 'mkBigCoreVarTup BareElements'.
All of this code is moved to the new module GHC.Core.Make.BigTuple.
Fixes #20864 #22336 #22473 #25065 #27331
-------------------------
Metric Decrease:
T9872a
-------------------------
- - - - -
70926017 by Evgeny Malyshev at 2026-09-16T06:58:25-04:00
Fix the CompactionFailed documentation link to compact
The old Haddock reference links into base instead of ghc-compact.
Use an explicit URL because ghc-compact depends on base, not vice versa.
Fixes #27558
Assisted-By: OpenAI Codex
- - - - -
136 changed files:
- + changelog.d/T27788-js-selector
- + changelog.d/boxing-family
- + changelog.d/clc-421
- + changelog.d/fix-threadlabel-segfault-27618
- + changelog.d/select-io-manager
- compiler/GHC/Builtin.hs
- compiler/GHC/Builtin/KnownKeys.hs
- compiler/GHC/Builtin/Modules.hs
- compiler/GHC/Builtin/Uniques.hs
- compiler/GHC/Builtin/WiredIn/Ids.hs
- compiler/GHC/Builtin/WiredIn/Prim.hs
- compiler/GHC/Builtin/WiredIn/TypeLits.hs
- compiler/GHC/Builtin/WiredIn/Types.hs
- + compiler/GHC/Builtin/WiredIn/Types/Box.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Coercion/Axiom.hs
- compiler/GHC/Core/DataCon.hs
- compiler/GHC/Core/FamInstEnv.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Make.hs
- + compiler/GHC/Core/Make/BigTuple.hs
- + compiler/GHC/Core/Make/Box.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/TyCo/Ppr.hs
- compiler/GHC/Core/TyCo/Rep.hs
- compiler/GHC/Core/TyCon.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/CoreToStg/AddImplicitBinds.hs
- compiler/GHC/Driver/Main/Compile.hs
- compiler/GHC/Driver/Main/Passes.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore/Arrows.hs
- compiler/GHC/HsToCore/Binds.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/ListComp.hs
- compiler/GHC/HsToCore/Utils.hs
- compiler/GHC/Iface/Decl.hs
- compiler/GHC/Iface/Load.hs
- compiler/GHC/Iface/Rename.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Stg/Lint.hs
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/CodeGen.hs
- compiler/GHC/StgToJS/Symbols.hs
- compiler/GHC/Tc/Deriv.hs
- compiler/GHC/Tc/Deriv/Generate.hs
- compiler/GHC/Tc/Deriv/Generics.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Gen/Match.hs
- compiler/GHC/Tc/Gen/Pat.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Instance/Family.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Solver/Default.hs
- compiler/GHC/Tc/Solver/FunDeps.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Utils/Backpack.hs
- compiler/GHC/Types/CompleteMatch.hs
- compiler/GHC/Types/Id.hs
- compiler/GHC/Types/Id/Info.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/TyThing.hs
- compiler/GHC/Types/TyThing/Ppr.hs
- compiler/GHC/Types/Unique.hs
- compiler/ghc.cabal.in
- docs/users_guide/runtime_control.rst
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/Exts.hs
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/include/RtsIfaceSymbols.h
- + libraries/ghc-internal/src/GHC/Internal/Box.hs
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- libraries/ghc-internal/src/GHC/Internal/TypeNats.hs
- libraries/ghc-internal/src/GHC/Internal/Types.hs
- linters/lint-codes/LintCodes/Static.hs
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/Prelude.h
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/StgMiscClosures.cmm
- rts/configure.ac
- rts/include/rts/Flags.h
- rts/include/rts/RtsToHsIface.h
- rts/include/rts/storage/Closures.h
- rts/include/stg/MiscClosures.h
- rts/posix/Poll.c
- rts/posix/Poll.h
- + rts/posix/SelectBis.c
- + rts/posix/SelectBis.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
- rts/rts.cabal
- rts/sm/Evac.c
- testsuite/tests/arrows/should_run/all.T
- + testsuite/tests/arrows/should_run/arrowrun005.hs
- + testsuite/tests/arrows/should_run/arrowrun005.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/deSugar/should_compile/T25065a.hs
- testsuite/tests/deSugar/should_compile/all.T
- + testsuite/tests/deSugar/should_run/T20864.hs
- + testsuite/tests/deSugar/should_run/T20864.stdout
- + testsuite/tests/deSugar/should_run/T25065b.hs
- + testsuite/tests/deSugar/should_run/T25065b.stdout
- testsuite/tests/deSugar/should_run/all.T
- + testsuite/tests/indexed-types/should_run/T27331.hs
- + testsuite/tests/indexed-types/should_run/T27331.stdout
- + testsuite/tests/indexed-types/should_run/T27331b.hs
- + testsuite/tests/indexed-types/should_run/T27331b.stdout
- + testsuite/tests/indexed-types/should_run/T27331b_Plugin.hs
- testsuite/tests/indexed-types/should_run/all.T
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- + testsuite/tests/javascript/T27788.hs
- + testsuite/tests/javascript/T27788.stdout
- testsuite/tests/javascript/all.T
- testsuite/tests/linters/notes.stdout
- + testsuite/tests/rts/T27618.hs
- + testsuite/tests/rts/T27618.stdout
- testsuite/tests/rts/all.T
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/jsffi/dyld.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a8c030a4393a5c8b55cdd787f4d9b7…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a8c030a4393a5c8b55cdd787f4d9b7…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/10.0.1-backports] 2 commits: driver: enable -finter-module-far-jumps by default
by Zubin (@wz1000) 16 Sep '26
by Zubin (@wz1000) 16 Sep '26
16 Sep '26
Zubin pushed to branch wip/10.0.1-backports at Glasgow Haskell Compiler / GHC
Commits:
046e5e8d by mangoiv at 2026-09-16T15:45:28+05:30
driver: enable -finter-module-far-jumps by default
this fixes a compatibility bug with certain binutils/gcc versions where
we were seeing jump offset overflow errors.
This commit can probably reverted if we stop supporting the problematic
binutils/gcc verions (2.44 and 14.2, respectively)
Reolves #26994
(cherry picked from commit 57c0f32c4e57b8b713611df44e7c51e81ba587c1)
- - - - -
cff5f0af by Zubin Duggal at 2026-09-16T15:45:43+05:30
Prepare 10.0.1-alpha1
- - - - -
84 changed files:
- − changelog.d/27532
- − changelog.d/27626
- − changelog.d/27627
- − changelog.d/27703
- − changelog.d/27704
- − changelog.d/27717
- − changelog.d/T25636
- − changelog.d/T26423
- − changelog.d/T26716
- − changelog.d/T26978
- − changelog.d/T26979
- − changelog.d/T27046
- − changelog.d/T27047
- − changelog.d/T27121.md
- − changelog.d/T27123.md
- − changelog.d/T27124.md
- − changelog.d/T27131
- − changelog.d/T27182.md
- − changelog.d/T27202
- − changelog.d/T27225
- − changelog.d/T27308
- − changelog.d/T27314.md
- − changelog.d/T27359
- − changelog.d/T27360
- − changelog.d/T27386
- − changelog.d/T27440
- − changelog.d/T27455
- − changelog.d/T27456
- − changelog.d/T27583
- − changelog.d/T27586
- − changelog.d/T27629
- − changelog.d/T27639
- − changelog.d/T27705
- − changelog.d/T27749
- − changelog.d/T27764
- − changelog.d/arm_ncg_fixes_T27430
- − changelog.d/bump-process
- − changelog.d/dynamic-trace-flags
- − changelog.d/fix-absent-dict-projection
- − changelog.d/fix-blackhole-handling
- − changelog.d/fix-cmm-atomic-load-store
- − changelog.d/fix-compacting-gc-ap-27434
- − changelog.d/fix-compacting-gc-constr-27649
- − changelog.d/fix-control0-mask-trampoline
- − changelog.d/fix-exponential-case-desugar-27383
- − changelog.d/fix-finalizers-27072
- − changelog.d/fix-layout-stack-fcall
- − changelog.d/fix-parallel-gc-selector-race-27477
- − changelog.d/fix-peekitbl-no-tntc
- − changelog.d/fix-threadlabel-segfault-27618
- − changelog.d/fix-use-std-ap-thunk
- − changelog.d/ghc-pkg-faster-closure
- − changelog.d/hadrian-stale-package-confs-26661
- − changelog.d/ipe-event-class
- − changelog.d/jobserver-leak-fix
- − changelog.d/link-deterministic-order
- − changelog.d/llvm-22
- − changelog.d/llvm-23
- − changelog.d/more-efficient-home-unit-imports-finding
- − changelog.d/reexported-module-errors
- − changelog.d/semaphore-v2
- − changelog.d/tag-inference-27005
- − changelog.d/tcplugin_init.md
- − changelog.d/tcplugins-pmc.md
- − changelog.d/typecheckModule-API.md
- − changelog.d/unit-index
- − changelog.d/unused-type
- − changelog.d/wasm-fix-serviceworker
- − changelog.d/windows-rethrow-overlapped-exception
- − changelog.d/withTcPlugins.md
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Platform/Ways.hs
- docs/users_guide/10.0.1-notes.rst
- docs/users_guide/exts/static_pointers.rst
- docs/users_guide/runtime_control.rst
- docs/users_guide/using-optimisation.rst
- libraries/base/changelog.md
- libraries/ghc-experimental/CHANGELOG.md
- libraries/ghc-internal/CHANGELOG.md
- testsuite/tests/ghci/T27532/Makefile
- − testsuite/tests/ghci/T27532/T27532.stdout
- − testsuite/tests/ghci/T27532/a.script
- testsuite/tests/ghci/T27532/all.T
- − testsuite/tests/ghci/T27532/b.script
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a2287f89693b74176b1ee1868629ea…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a2287f89693b74176b1ee1868629ea…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/romes/multi-threaded-debugger] Make resumeExec receive a Resume as an argument
by Rodrigo Mesquita (@alt-romes) 16 Sep '26
by Rodrigo Mesquita (@alt-romes) 16 Sep '26
16 Sep '26
Rodrigo Mesquita pushed to branch wip/romes/multi-threaded-debugger at Glasgow Haskell Compiler / GHC
Commits:
4242ccb5 by Rodrigo Mesquita at 2026-09-07T15:37:43+01:00
Make resumeExec receive a Resume as an argument
- - - - -
2 changed files:
- compiler/GHC/Runtime/Eval.hs
- ghc/GHCi/UI/Monad.hs
Changes:
=====================================
compiler/GHC/Runtime/Eval.hs
=====================================
@@ -413,65 +413,58 @@ resumeExec :: GhcMonad m
=> SingleStep
-> ThreadBreaksIsolationMode
-> Maybe Int
+ -> Resume
-> m ExecResult
-resumeExec step isolateMode mbCnt
- = do
- hsc_env <- getSession
- let ic = hsc_IC hsc_env
- resume = ic_resume ic
-
- case resume of
- [] -> liftIO $
- throwGhcExceptionIO (ProgramError "not stopped at a breakpoint")
- (r:rs) -> do
- -- unbind the temporary locals by restoring the TypeEnv from
- -- before the breakpoint, and drop this Resume from the
- -- InteractiveContext.
- let (resume_tmp_te,resume_gre_cache) = resumeBindings r
- ic' = ic { ic_tythings = resume_tmp_te,
- ic_gre_cache = resume_gre_cache,
- ic_resume = rs }
- setSession hsc_env{ hsc_IC = ic' }
-
- -- remove any bindings created since the breakpoint from the
- -- linker's environment
- let old_names = map getName resume_tmp_te
- new_names = [ n | thing <- ic_tythings ic
- , let n = getName thing
- , not (n `elem` old_names) ]
- interp = hscInterp hsc_env
- dflags = hsc_dflags hsc_env
- liftIO $ Loader.deleteFromLoadedHomeEnv interp new_names
-
- case r of
- Resume { resumeStmt = expr
- , resumeContext = fhv
- , resumeBindings = bindings
- , resumeFinalIds = final_ids
- , resumeApStack = apStack
- , resumeBreakpointId = mb_brkpt
- , resumeSpan = span
- , resumeHistory = hist } ->
- do
- -- When the user specified a break ignore count, set it
- -- in the interpreter
- case (mb_brkpt, mbCnt) of
- (Just brkpt, Just cnt) -> setupBreakpoint interp brkpt cnt
- _ -> return ()
-
- let eval_opts = (initEvalOpts dflags (enableGhcStepMode step))
- { isolateThreadBreaks = enableIsolateThreadBreaks isolateMode }
- status <- liftIO $ GHCi.resumeStmt interp eval_opts fhv
- let prevHistoryLst = fromListBL 50 hist
- hug = hsc_HUG hsc_env
- hist' = case mb_brkpt of
- Nothing -> pure prevHistoryLst
- Just bi
- | breakHere False step span -> do
- hist1 <- liftIO (mkHistory hug apStack bi)
- return $ hist1 `consBL` fromListBL 50 hist
- | otherwise -> pure prevHistoryLst
- handleRunStatus step isolateMode expr bindings final_ids status =<< hist'
+resumeExec step isolateMode mbCnt r = do
+ hsc_env <- getSession
+ let ic = hsc_IC hsc_env
+ -- unbind the temporary locals by restoring the TypeEnv from
+ -- before the breakpoint, and drop this Resume from the
+ -- InteractiveContext.
+ let (resume_tmp_te,resume_gre_cache) = resumeBindings r
+ ic' = ic { ic_tythings = resume_tmp_te,
+ ic_gre_cache = resume_gre_cache }
+ setSession hsc_env{ hsc_IC = ic' }
+
+ -- remove any bindings created since the breakpoint from the
+ -- linker's environment
+ let old_names = map getName resume_tmp_te
+ new_names = [ n | thing <- ic_tythings ic
+ , let n = getName thing
+ , not (n `elem` old_names) ]
+ interp = hscInterp hsc_env
+ dflags = hsc_dflags hsc_env
+ liftIO $ Loader.deleteFromLoadedHomeEnv interp new_names
+
+ case r of
+ Resume { resumeStmt = expr
+ , resumeContext = fhv
+ , resumeBindings = bindings
+ , resumeFinalIds = final_ids
+ , resumeApStack = apStack
+ , resumeBreakpointId = mb_brkpt
+ , resumeSpan = span
+ , resumeHistory = hist } ->
+ do
+ -- When the user specified a break ignore count, set it
+ -- in the interpreter
+ case (mb_brkpt, mbCnt) of
+ (Just brkpt, Just cnt) -> setupBreakpoint interp brkpt cnt
+ _ -> return ()
+
+ let eval_opts = (initEvalOpts dflags (enableGhcStepMode step))
+ { isolateThreadBreaks = enableIsolateThreadBreaks isolateMode }
+ status <- liftIO $ GHCi.resumeStmt interp eval_opts fhv
+ let prevHistoryLst = fromListBL 50 hist
+ hug = hsc_HUG hsc_env
+ hist' = case mb_brkpt of
+ Nothing -> pure prevHistoryLst
+ Just bi
+ | breakHere False step span -> do
+ hist1 <- liftIO (mkHistory hug apStack bi)
+ return $ hist1 `consBL` fromListBL 50 hist
+ | otherwise -> pure prevHistoryLst
+ handleRunStatus step isolateMode expr bindings final_ids status =<< hist'
setupBreakpoint :: GhcMonad m => Interp -> InternalBreakpointId -> Int -> m () -- #19157
setupBreakpoint interp ibi cnt = do
=====================================
ghc/GHCi/UI/Monad.hs
=====================================
@@ -38,6 +38,7 @@ import GHCi.UI.Info (ModInfo)
import qualified GHC
import GHC.Driver.Monad hiding (liftIO)
import GHC.Utils.Outputable
+import GHC.Utils.Panic
import qualified GHC.Driver.Ppr as Ppr
import GHC.Types.Name.Occurrence
import GHC.Driver.Session
@@ -412,7 +413,12 @@ resume step mbIgnoreCnt = do
withProgName (progname st) $
withArgs (args st) $
reflectGHCi x $ do
- GHC.resumeExec step GHC.SingleThreadedBreaks mbIgnoreCnt
+ GHC.getResumeContext >>= \case
+ [] -> liftIO $
+ throwGhcExceptionIO (GHC.ProgramError "not stopped at a breakpoint")
+ (r:rs) -> do
+ modifySession $ \env -> env{hsc_IC = (hsc_IC env){ ic_resume = rs }}
+ GHC.resumeExec step GHC.SingleThreadedBreaks mbIgnoreCnt r
-- --------------------------------------------------------------------------
-- timing & statistics
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4242ccb50bb63674ba8b4e42e0c21a2…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/4242ccb50bb63674ba8b4e42e0c21a2…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/fendor/has-field-hie] Type of the whole record dot syntax is still recorded
by Hannes Siebenhandl (@fendor) 16 Sep '26
by Hannes Siebenhandl (@fendor) 16 Sep '26
16 Sep '26
Hannes Siebenhandl pushed to branch wip/fendor/has-field-hie at Glasgow Haskell Compiler / GHC
Commits:
8926227e by fendor at 2026-09-16T11:43:40+02:00
Type of the whole record dot syntax is still recorded
- - - - -
3 changed files:
- compiler/GHC/Iface/Ext/Utils.hs
- testsuite/tests/hiefile/should_run/RecordDotTypes.hs
- testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
Changes:
=====================================
compiler/GHC/Iface/Ext/Utils.hs
=====================================
@@ -82,15 +82,19 @@ resolveVisibility kind ty_args
foldType :: (HieType a -> a) -> HieTypeFix -> a
foldType f (Roll t) = f $ fmap (foldType f) t
-selectPoint :: HieFile -> (Int,Int) -> Maybe (HieAST Int)
-selectPoint hf (sl,sc) = getFirst $
+selectPoint :: HieFile -> (Int,Int) -> Maybe (HieAST TypeIndex)
+selectPoint hf p = selectRange hf p p
+
+selectRange :: HieFile -> (Int,Int) -> (Int,Int) -> Maybe (HieAST TypeIndex)
+selectRange hf (sl,sc) (el, ec) = getFirst $
flip foldMap (M.toList (getAsts $ hie_asts hf)) $ \(HiePath fs,ast) -> First $
case selectSmallestContaining (sp fs) ast of
Nothing -> Nothing
Just ast' -> Just ast'
where
sloc fs = mkRealSrcLoc fs sl sc
- sp fs = mkRealSrcSpan (sloc fs) (sloc fs)
+ eloc fs = mkRealSrcLoc fs el ec
+ sp fs = mkRealSrcSpan (sloc fs) (eloc fs)
findEvidenceUse :: NodeIdentifiers a -> [Name]
findEvidenceUse ni = [n | (Right n, dets) <- xs, any isEvidenceUse (identInfo dets)]
=====================================
testsuite/tests/hiefile/should_run/RecordDotTypes.hs
=====================================
@@ -22,6 +22,11 @@ x = MyRecord { a = "Hello", b = 12, c = MyChild { z = "there" } }
y = x.a ++ show x.b ++ x.c.z
-- ^ ^ ^ ^^
-- 1 2 3 45
+-- ^-^ ^-^ ^-^
+-- 6 7 8
+-- ^---^
+-- 9
+
p1,p2,p3,p4 :: (Int,Int)
p1 = (22,6)
@@ -30,10 +35,19 @@ p3 = (22,25)
p4 = (22,28)
p5 = (22,29)
+r6 = (p1, (22, 8))
+r7 = ((22,17), p2)
+r8 = (p3, (22, 27))
+r9 = (p3, p5)
+
selectPoint' :: HieFile -> (Int,Int) -> HieAST Int
selectPoint' hf loc =
maybe (error "point not found") id $ selectPoint hf loc
+selectRange' :: HieFile -> ((Int,Int), (Int, Int)) -> HieAST Int
+selectRange' hf (s, e) =
+ maybe (error "range not found") id $ selectRange hf s e
+
main = do
(df, hf) <- readTestHie "RecordDotTypes.hie"
forM_ [p1,p2,p3,p4,p5] $ \point -> do
@@ -41,3 +55,11 @@ main = do
let types = concatMap nodeType $ getSourcedNodeInfo $ sourcedNodeInfo $ selectPoint' hf point
forM_ types $ \typ -> do
putStrLn (renderHieType df $ recoverFullType typ (hie_types hf))
+
+ forM_ [r6, r7, r8, r9] $ \range -> do
+ putStr $ "At " ++ showRange range ++ ", got type: "
+ let types = concatMap nodeType $ getSourcedNodeInfo $ sourcedNodeInfo $ selectRange' hf range
+ forM_ types $ \typ -> do
+ putStrLn (renderHieType df $ recoverFullType typ (hie_types hf))
+ where
+ showRange (p1, p2) = show p1 ++ " - " ++ show p2
=====================================
testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
=====================================
@@ -3,3 +3,7 @@ At (22,20), got type: MyRecord -> Integer
At (22,25), got type: MyRecord
At (22,28), got type: MyChild -> [Char]
At (22,29), got type: MyChild -> [Char]
+At (22,6) - (22,8), got type: [Char]
+At (22,17) - (22,20), got type: Integer
+At (22,25) - (22,27), got type: MyChild
+At (22,25) - (22,29), got type: [Char]
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8926227e75bdaeaf3f2a649f2d1edf6…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/8926227e75bdaeaf3f2a649f2d1edf6…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/fendor/has-field-hie] WIP: Allow any Id as evidence
by Hannes Siebenhandl (@fendor) 16 Sep '26
by Hannes Siebenhandl (@fendor) 16 Sep '26
16 Sep '26
Hannes Siebenhandl pushed to branch wip/fendor/has-field-hie at Glasgow Haskell Compiler / GHC
Commits:
2664d3de by fendor at 2026-09-16T10:56:18+02:00
WIP: Allow any Id as evidence
- - - - -
8 changed files:
- compiler/GHC/Iface/Ext/Ast.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
- + testsuite/tests/hiefile/should_run/HieTypeable.hs
- + testsuite/tests/hiefile/should_run/HieTypeable.stdout
- testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
- testsuite/tests/hiefile/should_run/T23492.stdout
- testsuite/tests/hiefile/should_run/all.T
Changes:
=====================================
compiler/GHC/Iface/Ext/Ast.hs
=====================================
@@ -23,7 +23,6 @@ import GHC.Core.DataCon ( dataConWrapperType )
import GHC.Core.Type ( Type, ForAllTyFlag(..) )
import GHC.Core.TyCon ( TyCon, tyConClass_maybe )
import GHC.Core.InstEnv
-import GHC.Core.Predicate ( isEvId )
import GHC.Hs
import GHC.Hs.Syn.Type
@@ -33,7 +32,7 @@ import GHC.Types.Basic
import GHC.Types.UnresolvedImport ( isGeneratedImport )
import GHC.Types.FieldLabel
import GHC.Types.Avail ( Avails )
-import GHC.Types.Id ( isDataConId_maybe )
+import GHC.Types.Id ( isDataConId_maybe, isId )
import GHC.Types.Name ( Name, nameSrcSpan, nameUnique, wiredInNameTyThing_maybe, getName )
import GHC.Types.Name.Env ( NameEnv, emptyNameEnv, extendNameEnv, lookupNameEnv )
import GHC.Types.Name.Reader ( RecFieldInfo(..), WithUserRdr(..) )
@@ -682,7 +681,7 @@ instance ToHie (Context (Located (WithUserRdr Name))) where
hieEvIdsOfTerm :: EvTerm -> [EvId]
-- Returns only EvIds satisfying relevantEvId
-hieEvIdsOfTerm = runFVSelectiveList isEvId . evTermFVs
+hieEvIdsOfTerm = runFVSelectiveList isId . evTermFVs
instance ToHie (EvBindContext (LocatedA TcEvBinds)) where
toHie (EvBindContext sc sp (L span (EvBinds bs)))
=====================================
testsuite/tests/hiefile/should_run/HasFieldQueries.hs
=====================================
@@ -0,0 +1,52 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+module Main where
+
+import TestUtils
+import GHC.Records
+import GHC.TypeLits
+import Data.Tree
+
+data Thing = Thing {field1 :: Char, field2 :: Bool}
+ deriving (Show, Eq)
+
+foo :: Thing -> String
+foo t = show t.field1
+-- ^ this is the point
+
+testing2 (x :: Thing) = x.field1
+-- ^ this is the point
+-- ^ this is the point
+
+data NestedThing = NestedThing { nested1 :: Thing }
+
+nestedSig :: NestedThing -> Char
+nestedSig n = n.nested1.field1
+-- ^ this is the point
+-- ^ this is the point
+
+nestedNoSig n = n.nested1.field2 :: Bool
+-- ^ this is the point
+-- ^ this is the point
+
+
+withConstraint :: HasField "field1" x Char => x -> Char
+withConstraint x = x.field1
+-- ^ this is the point
+
+points =
+ [ (13,17)
+ , (16,25)
+ , (16,27)
+ , (23,17)
+ , (23,25)
+ , (27,20)
+ , (27,28)
+ , (33,22)
+ ]
+
+main = do
+ (df, hf) <- readTestHie "HasFieldQueries.hie"
+ let refmap = generateReferencesMap $ getAsts $ hie_asts hf
+
+ traverse (explainEv df hf refmap) points
+ return ()
=====================================
testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
=====================================
@@ -0,0 +1,156 @@
+==========================
+At point (13,17), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (16,25), we found:
+==========================
+==========================
+At point (16,27), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:16:1-32, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1]
+│ with scope: LocalScope HasFieldQueries.hs:16:1-32
+│ bound at: HasFieldQueries.hs:16:1-32
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (23,17), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "nested1" NestedThing Thing
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ nested1]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ nested1 at HasFieldQueries.hs:1:1, of type: NestedThing -> Thing
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:20:34
+ └
+
+==========================
+At point (23,25), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (27,20), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:27:1-40
+│ bound at: HasFieldQueries.hs:27:1-40
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
+ │ is an evidence variable bound by a type signature
+ │ with scope: LocalScope HasFieldQueries.hs:27:1-40
+ │ bound at: HasFieldQueries.hs:27:1-40
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (27,28), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:27:1-40
+│ bound at: HasFieldQueries.hs:27:1-40
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
+ │ is an evidence variable bound by a type signature
+ │ with scope: LocalScope HasFieldQueries.hs:27:1-40
+ │ bound at: HasFieldQueries.hs:27:1-40
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (33,22), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:33:1-27
+│ bound at: HasFieldQueries.hs:33:1-27
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
+ │ is an evidence variable bound by a HsWrapper
+ │ with scope: LocalScope HasFieldQueries.hs:33:1-27
+ │ bound at: HasFieldQueries.hs:33:1-27
+ │ Defined at <no location info>
+ └
+
=====================================
testsuite/tests/hiefile/should_run/HieTypeable.hs
=====================================
@@ -0,0 +1,28 @@
+module Main where
+
+import Data.Dynamic
+import Data.Typeable
+import TestUtils
+
+data Thing = Thing {field1 :: Char, field2 :: Bool}
+ deriving (Show, Eq)
+
+castFromDynamic :: Dynamic -> Maybe Thing
+castFromDynamic d = fromDynamic d
+ -- ^ this is the point
+
+rep :: Thing -> TypeRep
+rep d = typeOf d
+ -- ^ this is the point
+
+points =
+ [ (11,21)
+ , (15,10)
+ ]
+
+main = do
+ (df, hf) <- readTestHie "HieTypeable.hie"
+ let refmap = generateReferencesMap $ getAsts $ hie_asts hf
+
+ traverse (explainEv df hf refmap) points
+ return ()
=====================================
testsuite/tests/hiefile/should_run/HieTypeable.stdout
=====================================
@@ -0,0 +1,30 @@
+==========================
+At point (11,21), we found:
+==========================
+┌
+│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+│ is an evidence variable bound by a let, depending on: [$dTypeable]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+ │ is an evidence variable bound by a let, depending on: []
+ │ with scope: ModuleScope
+ │
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (15,10), we found:
+==========================
+┌
+│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+│ is an evidence variable bound by a let, depending on: []
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+
=====================================
testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
=====================================
@@ -1,5 +1,5 @@
At (22,6), got type: MyRecord
-At (22,20), got type: Integer
+At (22,20), got type: MyRecord -> Integer
At (22,25), got type: MyRecord
-At (22,28), got type: String
-At (22,29), got type: String
\ No newline at end of file
+At (22,28), got type: MyChild -> [Char]
+At (22,29), got type: MyChild -> [Char]
=====================================
testsuite/tests/hiefile/should_run/T23492.stdout
=====================================
@@ -4,4 +4,4 @@ PartialFieldSelector
At (18,7), got type: PartialFieldSelector -> Bool
At (23,7), got type: PartialFieldSelector
At (23,8), got type: PartialFieldSelector
-At (23,9), got type: Bool
+At (23,9), got type: PartialFieldSelector -> Bool
=====================================
testsuite/tests/hiefile/should_run/all.T
=====================================
@@ -10,3 +10,5 @@ test('T23120', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUti
test('T24544', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
test('HieGadtConSigs', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
test('T25709', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
+test('HasFieldQueries', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
+test('HieTypeable', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2664d3de393242433ee584f1632c775…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2664d3de393242433ee584f1632c775…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0
[Git][ghc/ghc][wip/fendor/has-field-hie] WIP: Allow any Id as evidence
by Hannes Siebenhandl (@fendor) 16 Sep '26
by Hannes Siebenhandl (@fendor) 16 Sep '26
16 Sep '26
Hannes Siebenhandl pushed to branch wip/fendor/has-field-hie at Glasgow Haskell Compiler / GHC
Commits:
b372f2b2 by fendor at 2026-09-16T10:52:33+02:00
WIP: Allow any Id as evidence
- - - - -
8 changed files:
- compiler/GHC/Iface/Ext/Ast.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
- + testsuite/tests/hiefile/should_run/HieTypeable.hs
- + testsuite/tests/hiefile/should_run/HieTypeable.stdout
- testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
- testsuite/tests/hiefile/should_run/T23492.stdout
- testsuite/tests/hiefile/should_run/all.T
Changes:
=====================================
compiler/GHC/Iface/Ext/Ast.hs
=====================================
@@ -33,7 +33,7 @@ import GHC.Types.Basic
import GHC.Types.UnresolvedImport ( isGeneratedImport )
import GHC.Types.FieldLabel
import GHC.Types.Avail ( Avails )
-import GHC.Types.Id ( isDataConId_maybe )
+import GHC.Types.Id ( isDataConId_maybe, isId )
import GHC.Types.Name ( Name, nameSrcSpan, nameUnique, wiredInNameTyThing_maybe, getName )
import GHC.Types.Name.Env ( NameEnv, emptyNameEnv, extendNameEnv, lookupNameEnv )
import GHC.Types.Name.Reader ( RecFieldInfo(..), WithUserRdr(..) )
@@ -682,7 +682,7 @@ instance ToHie (Context (Located (WithUserRdr Name))) where
hieEvIdsOfTerm :: EvTerm -> [EvId]
-- Returns only EvIds satisfying relevantEvId
-hieEvIdsOfTerm = runFVSelectiveList isEvId . evTermFVs
+hieEvIdsOfTerm = runFVSelectiveList isId . evTermFVs
instance ToHie (EvBindContext (LocatedA TcEvBinds)) where
toHie (EvBindContext sc sp (L span (EvBinds bs)))
=====================================
testsuite/tests/hiefile/should_run/HasFieldQueries.hs
=====================================
@@ -0,0 +1,52 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+module Main where
+
+import TestUtils
+import GHC.Records
+import GHC.TypeLits
+import Data.Tree
+
+data Thing = Thing {field1 :: Char, field2 :: Bool}
+ deriving (Show, Eq)
+
+foo :: Thing -> String
+foo t = show t.field1
+-- ^ this is the point
+
+testing2 (x :: Thing) = x.field1
+-- ^ this is the point
+-- ^ this is the point
+
+data NestedThing = NestedThing { nested1 :: Thing }
+
+nestedSig :: NestedThing -> Char
+nestedSig n = n.nested1.field1
+-- ^ this is the point
+-- ^ this is the point
+
+nestedNoSig n = n.nested1.field2 :: Bool
+-- ^ this is the point
+-- ^ this is the point
+
+
+withConstraint :: HasField "field1" x Char => x -> Char
+withConstraint x = x.field1
+-- ^ this is the point
+
+points =
+ [ (13,17)
+ , (16,25)
+ , (16,27)
+ , (23,17)
+ , (23,25)
+ , (27,20)
+ , (27,28)
+ , (33,22)
+ ]
+
+main = do
+ (df, hf) <- readTestHie "HasFieldQueries.hie"
+ let refmap = generateReferencesMap $ getAsts $ hie_asts hf
+
+ traverse (explainEv df hf refmap) points
+ return ()
=====================================
testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
=====================================
@@ -0,0 +1,156 @@
+==========================
+At point (13,17), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (16,25), we found:
+==========================
+==========================
+At point (16,27), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:16:1-32, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1]
+│ with scope: LocalScope HasFieldQueries.hs:16:1-32
+│ bound at: HasFieldQueries.hs:16:1-32
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (23,17), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "nested1" NestedThing Thing
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ nested1]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ nested1 at HasFieldQueries.hs:1:1, of type: NestedThing -> Thing
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:20:34
+ └
+
+==========================
+At point (23,25), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
+│ is an evidence variable bound by a let, depending on: [C:HasField,
+│ field1]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
++- ┌
+| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
+| │ is a usage of an external evidence variable
+| │ Defined in `GHC.Internal.Records'
+| └
+|
+`- ┌
+ │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
+ │ is a usage of an external evidence variable
+ │ Defined at HasFieldQueries.hs:9:21
+ └
+
+==========================
+At point (27,20), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:27:1-40
+│ bound at: HasFieldQueries.hs:27:1-40
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
+ │ is an evidence variable bound by a type signature
+ │ with scope: LocalScope HasFieldQueries.hs:27:1-40
+ │ bound at: HasFieldQueries.hs:27:1-40
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (27,28), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:27:1-40
+│ bound at: HasFieldQueries.hs:27:1-40
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
+ │ is an evidence variable bound by a type signature
+ │ with scope: LocalScope HasFieldQueries.hs:27:1-40
+ │ bound at: HasFieldQueries.hs:27:1-40
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (33,22), we found:
+==========================
+┌
+│ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
+│ is an evidence variable bound by a let, depending on: [$dHasField]
+│ with scope: LocalScope HasFieldQueries.hs:33:1-27
+│ bound at: HasFieldQueries.hs:33:1-27
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
+ │ is an evidence variable bound by a HsWrapper
+ │ with scope: LocalScope HasFieldQueries.hs:33:1-27
+ │ bound at: HasFieldQueries.hs:33:1-27
+ │ Defined at <no location info>
+ └
+
=====================================
testsuite/tests/hiefile/should_run/HieTypeable.hs
=====================================
@@ -0,0 +1,28 @@
+module Main where
+
+import Data.Dynamic
+import Data.Typeable
+import TestUtils
+
+data Thing = Thing {field1 :: Char, field2 :: Bool}
+ deriving (Show, Eq)
+
+castFromDynamic :: Dynamic -> Maybe Thing
+castFromDynamic d = fromDynamic d
+ -- ^ this is the point
+
+rep :: Thing -> TypeRep
+rep d = typeOf d
+ -- ^ this is the point
+
+points =
+ [ (11,21)
+ , (15,10)
+ ]
+
+main = do
+ (df, hf) <- readTestHie "HieTypeable.hie"
+ let refmap = generateReferencesMap $ getAsts $ hie_asts hf
+
+ traverse (explainEv df hf refmap) points
+ return ()
=====================================
testsuite/tests/hiefile/should_run/HieTypeable.stdout
=====================================
@@ -0,0 +1,30 @@
+==========================
+At point (11,21), we found:
+==========================
+┌
+│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+│ is an evidence variable bound by a let, depending on: [$dTypeable]
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+|
+`- ┌
+ │ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+ │ is an evidence variable bound by a let, depending on: []
+ │ with scope: ModuleScope
+ │
+ │ Defined at <no location info>
+ └
+
+==========================
+At point (15,10), we found:
+==========================
+┌
+│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
+│ is an evidence variable bound by a let, depending on: []
+│ with scope: ModuleScope
+│
+│ Defined at <no location info>
+└
+
=====================================
testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
=====================================
@@ -1,5 +1,5 @@
At (22,6), got type: MyRecord
-At (22,20), got type: Integer
+At (22,20), got type: MyRecord -> Integer
At (22,25), got type: MyRecord
-At (22,28), got type: String
-At (22,29), got type: String
\ No newline at end of file
+At (22,28), got type: MyChild -> [Char]
+At (22,29), got type: MyChild -> [Char]
=====================================
testsuite/tests/hiefile/should_run/T23492.stdout
=====================================
@@ -4,4 +4,4 @@ PartialFieldSelector
At (18,7), got type: PartialFieldSelector -> Bool
At (23,7), got type: PartialFieldSelector
At (23,8), got type: PartialFieldSelector
-At (23,9), got type: Bool
+At (23,9), got type: PartialFieldSelector -> Bool
=====================================
testsuite/tests/hiefile/should_run/all.T
=====================================
@@ -10,3 +10,5 @@ test('T23120', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUti
test('T24544', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
test('HieGadtConSigs', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
test('T25709', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
+test('HasFieldQueries', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
+test('HieTypeable', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/b372f2b20954ba10687ab473269f0cb…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/b372f2b20954ba10687ab473269f0cb…
You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
1
0