Skip to content

Enforcement of absence of field does not work at the toplevel of the dune selector #178

Description

@mbarbin

Bug report from Claude Opus 4.6 below:

Bug: (dune (not (has_field lint))) fails to auto-fix, while (dune (library (not (has_field lint)))) works

Description

When using (not (has_field <field>)) as a shorthand at the dune predicate level, dunolint reports an enforce failure with no automatic fix available, even though the documentation states that negation of has_field should suggest removing the field.

Steps to reproduce

Given a library stanza with a lint field:

  (library
   (name catch_the_bunny_stdlib)
   (public_name catch-the-bunny.stdlib)
   (flags :standard -w +a-4-40-41-42-44-45-48-66 -warn-error +a)
   (libraries dyn ordering pp)
   (instrumentation
    (backend ppx_windtrap))
   (lint (pps))
   (preprocess no_preprocessing))

Using the rule (dune (not (has_field lint))) produces:

Error: Enforce Failure.
The following condition does not hold: (not (has_field lint))
Dunolint is able to suggest automatic modifications to satisfy linting rules
when a strategy is implemented, however in this case there is none available.
Hint: You need to attend and fix manually.

Workaround

Wrapping the condition in library (...) works correctly:

(dune (library (not (has_field lint))))

This correctly suggests removing the lint field.

Root cause and implementation notes

In library.ml (and executable.ml), the outer Linter.enforce function handles all Not cases with a blanket Not _ -> Eval fallthrough, which bypasses the inner Top.enforce that correctly handles Not (has_field _) by removing the field.

The T (positive) branch correctly delegates shorthand predicates like T (has_field _)toTop.enforce, but the corresponding Notbranch does not. This affects allhas_field variants (lint, instrumentation, preprocess, name, public_name) when used as shorthands at the dune` predicate level.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions