Skip to content

Instantly share code, notes, and snippets.

@mpickering
Created January 28, 2026 16:24
Show Gist options
  • Select an option

  • Save mpickering/2a41aaa61dbf45ca6cb70615dc1d5364 to your computer and use it in GitHub Desktop.

Select an option

Save mpickering/2a41aaa61dbf45ca6cb70615dc1d5364 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
if ! command -v icdiff >/dev/null 2>&1; then
echo "error: icdiff is required to compare interface files" >&2
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GHC_BIN="${GHC_BIN:-${SCRIPT_DIR}/../_build/stage1/bin/ghc}"
if [[ ! -x "$GHC_BIN" ]]; then
echo "error: set GHC_BIN to a built ghc (current: '$GHC_BIN')" >&2
exit 1
fi
SRC="${SCRIPT_DIR}/ProcessTop.hs"
if [[ ! -f "$SRC" ]]; then
echo "error: expected $SRC to exist" >&2
exit 1
fi
WORKDIR="$(mktemp -d "${TMPDIR:-/tmp}/five-hi-XXXXXX")"
trap 'rm -rf "$WORKDIR"' EXIT
SRC_DIR="$(dirname "$SRC")"
UUID_COMMON="$SRC_DIR/UUIDCommon.hs"
MID_MODULES=(
"$SRC_DIR/ProcessAlpha.hs"
"$SRC_DIR/ProcessBeta.hs"
)
build_iface () {
local label="$1"
local order="$2"
shift 2
local dir="${WORKDIR}/${label}"
mkdir -p "$dir"
local modules=("$UUID_COMMON")
if [[ "$order" == "normal" ]]; then
modules+=("${MID_MODULES[@]}")
else
for ((idx=${#MID_MODULES[@]}-1; idx>=0; idx--)); do
modules+=("${MID_MODULES[idx]}")
done
fi
modules+=("$SRC")
"$GHC_BIN" -j -ddump-ds-preopt -fwrite-if-simplified-core -fforce-recomp --make "${modules[@]}" -outputdir "$dir" -hidir "$dir" -odir "$dir" "$@" >&2
"$GHC_BIN" --show-iface "${dir}/ProcessTop.hi" > "${dir}/ProcessTop.iface"
echo "${dir}/ProcessTop.iface"
}
for run in {1..1}; do
echo "=== Run $run ==="
iface_normal=$(build_iface "normal_$run" normal)
iface_reverse=$(build_iface "reverse_$run" reverse -dinitial-unique=16777215 -dunique-increment=-1)
icdiff "$iface_normal" "$iface_reverse" || true
echo
echo "=== KindRep bindings from normal interface (run $run) ==="
rg -n "\$krep" -n "$iface_normal" || true
cp "$iface_normal" "$SCRIPT_DIR/ProcessTop.normal.run${run}.iface"
cp "$iface_reverse" "$SCRIPT_DIR/ProcessTop.reverse.run${run}.iface"
done
{-# LANGUAGE DataKinds #-}
module ProcessAlpha where
import UUIDCommon
type AlphaProcessId = UUID "AlphaProcess"
{-# LANGUAGE DataKinds #-}
module ProcessBeta where
import UUIDCommon
type BetaAccountId = UUID "BetaAccount"
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
module ProcessTop where
import ProcessAlpha (AlphaProcessId)
import ProcessBeta (BetaAccountId)
import UUIDCommon
-- Minimal reproducer for nondeterministic Typeable KindRep ordering:
-- these tycons share identical kinds (AlphaProcessId or BetaTransactionId).
-- Different unique supplies or module orders reshuffle the shared KindRep
-- bindings in the resulting interface file.
data AlphaProcessCarrier (ref :: AlphaProcessId) = AlphaProcessCarrier
data BetaTransactionMirror (ref :: BetaAccountId) = BetaTransactionMirror
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
module UUIDCommon
( UUID(..)
) where
import GHC.TypeLits (Symbol)
-- | Simple phantom UUID type indexed by a type-level label.
data UUID (label :: Symbol) = UUID
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment