Skip to content

[checking] Generate Foldable derived members - #231

Merged
purefunctor merged 3 commits into
traversable-derivingfrom
foldable-deriving
Aug 1, 2026
Merged

[checking] Generate Foldable derived members#231
purefunctor merged 3 commits into
traversable-derivingfrom
foldable-deriving

Conversation

@purefunctor

Copy link
Copy Markdown
Owner

Summary

Complete derived Foldable and Bifoldable dictionaries using the canonical PureScript definitions:

  • Foldable: foldr, foldl, and foldMap
  • Bifoldable: bifoldr, bifoldl, and bifoldMap

The checking prelude now includes the canonical Semigroup and Monoid definitions required by foldMap and bifoldMap. Generated members support products, sums, records, recursive types, nested unary applications, and nested binary applications while preserving the expected fold direction and field order.

PureScript compatibility

For a right-only occurrence such as p Int a, upstream purs can derive through either a unary instance for the partial application (Foldable (p Int) / Traversable (p Int)) or a binary instance for the constructor (Bifoldable p / Bitraversable p). Alexandrite previously required the unary route even when only the canonical binary evidence was available.

This change matches purs by:

  • preferring the unary partially-applied instance when both strategies are available
  • falling back to the binary class when the unary instance is unavailable
  • considering explicit constraints, expanded superclass constraints, and visible declared, derived, and imported instance heads when selecting a strategy
  • representing binary recipes explicitly as first-only, second-only, or both-argument traversals

The compatibility failure is preserved in an earlier commit in this PR, followed by the implementation that turns those snapshots into successful derived instances.

Implementation decisions

  • Reuse variance-analysis recipes across Functor, Foldable, and Traversable generation rather than duplicating structural type analysis.
  • Keep Foldable generation in a dedicated emitter because directional accumulator threading and monoidal folds differ from mapping and applicative reconstruction.
  • Resolve all canonical class members by known-term identity and emit the dictionary only when every required member can be generated.
  • Use the binary class only as a compatibility fallback for right-only applications; this preserves the behavior of an explicitly available unary instance.
  • Keep instance-head discovery local to variance analysis because it is used only to choose the structurally valid recipe.
  • Reject function-shaped occurrences for Foldable and Bifoldable rather than silently producing incomplete members.

Tests

Semantic fixtures cover:

  • identity, optional, product, nested, recursive, and record-shaped Foldable types
  • left-only, right-only, and both-argument binary applications
  • Bifoldable sums, products, unary and binary nesting, and records
  • right-only evidence from binary constraints, superclass-expanded constraints, and concrete visible instance heads
  • unary-instance preference when unary and binary strategies are both available
  • rejection of function-shaped folds

Validation completed:

  • just format
  • git diff --check
  • just t checking
  • just t semantic
  • cargo check -p checking --tests
  • cargo nextest run -p checking (30 tests passed)

The final implementation was reviewed by Oracle and approved with no blockers.

Stack

This PR is based on and should be reviewed after #230. Its base branch is traversable-deriving; once #230 lands, this PR can be retargeted to main.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@purefunctor, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 57 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: edc8b9fe-8182-4889-8489-3e7ead95e40d

📥 Commits

Reviewing files that changed from the base of the PR and between 3bd35e0 and 60f5c57.

⛔ Files ignored due to path filters (36)
  • tests-integration/fixtures/checking/1785484200_derive_traversable_function_rejection/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/checking/1785518760_derive_bifoldable_function_rejection/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/checking/1785518760_derive_foldable_function_rejection/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_bitraversable_either_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_bitraversable_nested_binary_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_bitraversable_nested_unary_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_bitraversable_pair_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_bitraversable_record_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_binary_both_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_binary_left_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_const_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_identity_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_maybe_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_nested_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_product_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_record_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_recursive_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_either_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_nested_binary_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_nested_unary_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_pair_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_record_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_binary_both_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_binary_left_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_binary_right_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_identity_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_maybe_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_nested_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_product_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_record_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_recursive_body/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785522600_derive_foldable_right_bifoldable_context/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785522600_derive_traversable_right_bitraversable_context/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785523440_derive_foldable_right_binary_superclass_context/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785523440_derive_foldable_right_concrete_instance_heads/Main.snap is excluded by !**/*.snap
  • tests-integration/fixtures/semantic/1785523440_derive_foldable_right_prefers_unary_context/Main.snap is excluded by !**/*.snap
📒 Files selected for processing (36)
  • compiler-core/checking/src/context.rs
  • compiler-core/checking/src/source/derive/foldable.rs
  • compiler-core/checking/src/source/derive/generate.rs
  • compiler-core/checking/src/source/derive/generate/foldable.rs
  • compiler-core/checking/src/source/derive/generate/functor.rs
  • compiler-core/checking/src/source/derive/generate/traversable.rs
  • compiler-core/checking/src/source/derive/member.rs
  • compiler-core/checking/src/source/derive/variance.rs
  • tests-integration/fixtures/checking/1785484200_derive_traversable_function_rejection/Main.purs
  • tests-integration/fixtures/checking/1785518760_derive_bifoldable_function_rejection/Main.purs
  • tests-integration/fixtures/checking/1785518760_derive_foldable_function_rejection/Main.purs
  • tests-integration/fixtures/checking/prelude/Data.Bifoldable.purs
  • tests-integration/fixtures/checking/prelude/Data.Foldable.purs
  • tests-integration/fixtures/checking/prelude/Data.Monoid.purs
  • tests-integration/fixtures/checking/prelude/Data.Semigroup.purs
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_binary_both_body/Main.purs
  • tests-integration/fixtures/semantic/1785484440_derive_traversable_binary_left_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_either_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_nested_binary_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_nested_unary_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_pair_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_bifoldable_record_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_binary_both_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_binary_left_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_binary_right_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_identity_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_maybe_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_nested_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_product_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_record_body/Main.purs
  • tests-integration/fixtures/semantic/1785518760_derive_foldable_recursive_body/Main.purs
  • tests-integration/fixtures/semantic/1785522600_derive_foldable_right_bifoldable_context/Main.purs
  • tests-integration/fixtures/semantic/1785522600_derive_traversable_right_bitraversable_context/Main.purs
  • tests-integration/fixtures/semantic/1785523440_derive_foldable_right_binary_superclass_context/Main.purs
  • tests-integration/fixtures/semantic/1785523440_derive_foldable_right_concrete_instance_heads/Main.purs
  • tests-integration/fixtures/semantic/1785523440_derive_foldable_right_prefers_unary_context/Main.purs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.39262% with 164 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.67%. Comparing base (3bd35e0) to head (60f5c57).

Files with missing lines Patch % Lines
...re/checking/src/source/derive/generate/foldable.rs 78.62% 78 Missing and 46 partials ⚠️
...mpiler-core/checking/src/source/derive/variance.rs 81.51% 13 Missing and 9 partials ⚠️
compiler-core/checking/src/context.rs 50.00% 0 Missing and 8 partials ⚠️
...checking/src/source/derive/generate/traversable.rs 63.63% 2 Missing and 2 partials ⚠️
...mpiler-core/checking/src/source/derive/generate.rs 80.00% 3 Missing ⚠️
...ore/checking/src/source/derive/generate/functor.rs 66.66% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@                   Coverage Diff                    @@
##           traversable-deriving     #231      +/-   ##
========================================================
- Coverage                 83.78%   83.67%   -0.12%     
========================================================
  Files                       158      159       +1     
  Lines                     34700    35439     +739     
  Branches                  34700    35439     +739     
========================================================
+ Hits                      29075    29655     +580     
- Misses                     3036     3131      +95     
- Partials                   2589     2653      +64     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@purefunctor

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@purefunctor
purefunctor merged commit 7849883 into main Aug 1, 2026
13 of 15 checks passed
@purefunctor
purefunctor deleted the foldable-deriving branch August 1, 2026 08:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant