Create MRE — Minimal Reproducible Example
Reduce a third-party Fortran code failure into the smallest possible standalone example that reproduces the LFortran bug. The MRE must compile and run correctly with the reference compiler but fail with LFortran, exhibiting the same error as the original third-party code.
Prerequisites
Before starting, confirm you have:
- A built
lfortran—build/src/bin/lfortranfor a standard in-tree build (seeAGENTS.md). Put it first onPATH, or set$LFORTRANto its path. - A reference Fortran compiler on
PATH.gfortranis the project default — it is whatintegration_testsuses via thegfortranlabel, so prefer it.flangworks too if that is what you have. - Access to the failing third-party code and the exact error message
Inputs to Gather
Ask the user for (if not already provided):
- The third-party project — name, repo URL, or local path
- The exact error — full error message or failure description from LFortran
- How to reproduce — the build command, test command, or steps that trigger the failure
- Failure type — compilation error, runtime crash, or wrong output
- The file(s) involved — which source file(s) trigger the error
If the input is a GitHub issue rather than a third-party project, run the
repro-issue skill first — it produces an RE that this skill then reduces.
If the failure was seen in the browser (the JupyterLite lab at
https://lfortran.github.io/lfortran/lab/index.html) or in a Jupyter notebook
cell, read doc/src/jupyterlite.md first. It explains how to build and serve
the lab locally, how to tell a genuine compiler bug from a stale
service-worker/IndexedDB cache, and the three ways to reproduce a lab bug
(C++ evaluator test, native xeus kernel, full WASM build). Its "Writing a test
for a lab bug" section tells you whether the bug is interactive-mode specific:
if the notebook cells rewritten as one ordinary program still fail, reduce it
as a normal .f90 MRE with the procedure below; if it only fails when split
across cells, the reproducer is a FortranEvaluator::evaluate2() TEST_CASE
in src/lfortran/tests/test_llvm.cpp instead of a .f90 + run.sh pair —
the reduction procedure below applies unchanged, with cells in place of the
Fortran file.
Procedure
Phase 0: Read Project Guidelines
Read AGENTS.md in the repository root for build commands and project
conventions. Follow it, but this SKILL.md takes precedence where they conflict.
Phase 1: Understand the Failure
- Reproduce the original failure with LFortran to capture the exact error message and exit code.
- Identify the error category:
- Compilation error: parser failure, semantic error, codegen crash
- Runtime failure: crash, wrong output, hang
- Note the specific error text — the MRE must trigger this same error.
Phase 2: Isolate the Failing Construct
Use a systematic isolation approach first:
- Read the error message carefully. Identify which Fortran construct is implicated (e.g. a specific intrinsic, derived type feature, array operation, module interaction, I/O statement).
- Identify the minimal source file(s) that contain this construct.
- If the failure involves modules, determine the minimum set of modules needed and their dependency order.
If you are unable to reproduce the error this way, proceed to the next phase.
Phase 3: Reduce via Binary Search
Apply binary-search reduction to shrink the code:
- Start with the isolated file(s) from Phase 2. If you failed to isolate in Phase 2, start with the whole third-party code.
- Remove approximately half of the code that is NOT related to the failing construct (unused subroutines, unrelated variables, comments, etc.).
- Test after each removal:
- Does the reference compiler still compile/run it successfully?
- Does
lfortranstill produce the same error?
- If the error disappears, undo the last removal and try removing a smaller portion.
- Repeat until no further code can be removed without losing the error.
Guard against false reduction. A reduction step is only valid if the reference compiler still accepts the program. If you reduce until both compilers fail, you have most likely produced invalid Fortran rather than isolated an LFortran bug — back up to the last state where the reference compiler succeeded.
Phase 4: Minimize and Clean Up
- Remove all unused:
usestatements and modules- Variables and parameters
- Subroutines and functions
- Arguments and dummy parameters
- Simplify compiler options:
- Remove as many lfortran options as possible, while still reproducing the error
- Simplify remaining code:
- Replace complex expressions with simple literals where possible
- Reduce array sizes to the smallest that still triggers the bug
- Shorten identifier names for clarity (but keep them meaningful)
- Remove all comments, empty lines, etc.
- If multiple files are needed (modules), minimize the number of files. Prefer a single file if possible.
Phase 5: Verify the MRE
Run the final verification:
# Must succeed with the reference compiler
gfortran -o test_ref <mre_file>.f90 && ./test_ref
echo "reference exit code: $?"
# Must fail with lfortran with the SAME error as the original
lfortran <mre_file>.f90
echo "lfortran exit code: $?"
For runtime failures, both compilers must compile successfully, but the lfortran-compiled binary must produce wrong output or crash:
# Both compile
gfortran -o test_ref <mre_file>.f90
lfortran <mre_file>.f90 -o test_lfortran
# reference binary works
./test_ref
# lfortran binary fails
./test_lfortran
Confirm:
- The reference compiler compiles and runs successfully
- LFortran fails with the same (or closely related) error as the original
- No code can be removed without losing the bug
- All MRE files are in the repository root (
./), not in any subdirectory
Phase 6: Produce Output Files
IMPORTANT: All output files MUST be created directly in the repository root
directory (./). Do NOT create a subdirectory (e.g. mre_dir/, mre/,
output/) for MRE files. Every file — .f90 files, run.sh — goes in ./.
These are scratch artifacts, not deliverables. They are ignored via
.gitignore (see the # repro-issue / create-mre scratch artifacts block) so
they never end up in a fix PR. The deliverable is the integration test that
fix-mre adds under integration_tests/. Do not git add -f the MRE files.
1. The MRE Fortran file(s)
Create the .f90 file(s) directly in the repository root (./).
Name the file descriptively based on the bug, e.g.:
./mre_derived_type_alloc.f90./mre_intrinsic_reshape.f90
If multiple files are needed (e.g. module dependencies), name them with a common prefix and number them in compilation order:
./mre_mod1.f90(module)./mre_main.f90(program)
2. ./run.sh — Reproduction script
Create an executable bash script ./run.sh in the repository root
directory (the same directory as CMakeLists.txt). Replace any previous
./run.sh if it exists. Do NOT place it inside any subdirectory:
#!/usr/bin/env bash
set -e
# MRE for: <brief description of the bug>
# Original failure in: <third-party project name>
# Error type: <compilation error | runtime failure | wrong output>
#
# Expected: compiles and runs with the reference compiler
# Actual: fails with lfortran — <brief error description>
LFORTRAN="${LFORTRAN:-lfortran}"
REF="${REF:-gfortran}"
echo "=== Verifying MRE ==="
echo ""
echo "--- $REF (should succeed) ---"
$REF -o test_ref <file(s)>
./test_ref
echo "reference: OK"
echo ""
echo "--- lfortran (should fail) ---"
echo "Expected error: <paste key part of the error message>"
$LFORTRAN <file(s)> 2>&1 || true
echo ""
echo "Done. If lfortran showed the expected error above, the MRE is valid."
# Cleanup
rm -f test_ref test_lfortran a.out *.mod
Make it executable:
chmod +x run.sh
For runtime failures, adjust run.sh to compile with both compilers and
run both binaries, comparing output.
Phase 7: Summary
Print a summary for the user:
MRE created successfully!
Files (all in repository root ./):
<list of .f90 files>
./run.sh
Bug: <one-line description>
Error type: <compilation | runtime | wrong output>
Original project: <name>
To reproduce:
./run.sh
The MRE compiles with the reference compiler but fails with lfortran.
Next step: run the `fix-mre` skill to fix the bug and add an integration test.
Tips
- Module files: If lfortran fails during module compilation, the MRE may
need separate files compiled in order. Reflect this in
run.sh. - Compiler flags: If the bug only manifests with certain flags (e.g.
--fast), include those flags inrun.shand document them. - Multiple errors: If the third-party code has multiple LFortran failures,
create one MRE per distinct bug. Don't combine unrelated issues —
AGENTS.mdrequires one bug = one MRE = one PR. - Fixed-form Fortran: If the original code is fixed-form (
.for.f77), the MRE can use fixed-form too. Adjust file extensions accordingly. - Large codebases: For very large projects, start by identifying which translation unit fails, then reduce that single unit first.
- JupyterLite / notebook bugs: See
doc/src/jupyterlite.md. Before reducing, confirm the bug is real and not stale browser cache (retry in a private window). The command-line REPL is not a substitute for a notebook — it evaluates line by line, so a multi-line cell behaves differently. Keep the original cell split when reducing: that split is often the reproducer.