Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Inferred array elements omit Partial evidence applications

Open
#610 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
58/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
javascript, node.js, rust

Research direction

Start in compiler-frontend/checking/src/source/terms/collections.rs, especially array_core in ArrayMode::Infer, then inspect expression-aware instantiation or subtyping and the evidence handling in forms.rs. Reproduce the issue with the described temporary fixture using just t compiler 1790461440 --verbose and the Node assertion. Done means inferred array elements no longer retain an extra Partial dictionary and the runtime coverage passes without removing the #605 abstractions.

Written by the indexing model from the issue text.

Description

Problem

A runtime regression discovered while independently reviewing #605: inferred array elements retain a dictionary abstraction without applying its evidence. This is distinct from Granite’s duplicate-Partial inline finding on that PR.

Confirmed on PR #605 head ef33df090. The PR is currently open; this report does not claim the regression is present on main or in a released version.

Minimal reproducer

module Main where

data Choice = Chosen Int | Other

fs = [\(Chosen value) -> value]

Iris infers:

fs :: Partial => Array (Choice -> Int)

Against freshly generated output, this Node assertion fails:

import { strictEqual } from "node:assert/strict";
import * as Main from "./output/Main/index.js";

strictEqual(Main.fs({})[0](Main.Chosen(17)), 17);

Expected: 17.

Actual on the PR head:

AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected

+ [Function: $closure$1]
- 17

The semantic tree exposes the missing application:

fs = \{partialDict} -> [\{partialDict1} -> \(Chosen value) -> value]

There is one external Partial dictionary, but each array element incorrectly still expects another dictionary before accepting its Choice argument.

Verification and isolation

I created a temporary compiler fixture with the source above and a verify.mjs containing the assertion, then ran:

just t compiler 1790461440 --verbose
  • PR head: Node verification fails with the function-versus-17 assertion above.
  • With only the six added lines in compiler-frontend/checking/src/source/terms/forms.rs restored to their pre-fix version: the identical fixture passes (1 passed, no pending snapshots).

This isolates the regression to the new evidence abstractions interacting with array-element elaboration. The PR head was restored afterward. The temporary investigation fixture was removed; the timestamp above records the executed command, not a fixture currently committed to the repository.

Cause and proposed direction

In compiler-frontend/checking/src/source/terms/collections.rs, array_core in ArrayMode::Infer infers each expression, calls type-only unification::subtype, and retains the original expression. Constraint handling at the type level does not add an EvidenceApplication to that expression.

Before #605, an inferred partial lambda lacked its required abstraction and happened to work in this path. After #605 correctly supplies that abstraction, the array path leaves it unapplied.

Investigate expression-aware instantiation/subtyping for inferred array elements and add compiler-fixture runtime coverage. Do not remove the evidence abstractions from #605: that would restore the original unsafePartial case-section crash.

Reference result from purs 0.15.15

Compiled the exact five-line Main.purs above with the official Linux release of purs 0.15.15, with no library dependencies:

purs --version
# 0.15.15
purs compile Main.purs --output output

Compilation succeeds. Its only warning is MissingTypeDeclaration, reporting the same inferred type:

Partial => Array (Choice -> Int)

Actual generated fs from output/Main/index.js:

var fs = function (dictPartial) {
    return [ function (v) {
        if (v instanceof Chosen) {
            return v.value0;
        };
        throw new Error("Failed pattern match at Main (line 5, column 7 - line 5, column 31): " + [ v.constructor.name ]);
    } ];
};

The array element accepts Choice directly; it has no extra dictionary parameter. Executed with Node.js v22.23.2:

node --input-type=module -e '
import { strictEqual } from "node:assert/strict";
import * as Main from "./output/Main/index.js";
const result = Main.fs({})[0](new Main.Chosen(17));
strictEqual(result, 17);
console.log(result);
'

Actual stdout is 17; exit status is 0. The constructor call uses purs’s own representation (new Main.Chosen(17)), rather than Iris’s Main.Chosen(17), so neither runtime receives a value from the other compiler’s representation.

Investigation: https://ampcode.com/threads/T-01a0df1f-526b-71ab-a932-9dac42222d89

Dominant language
Rust
Stars
117
Forks
11
Avg merge
4h 27m
Merged PRs (30d)
123

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from purefunctor/purescript-iris

All issues in purefunctor/purescript-iris

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.