Skip to content

Track type equivalences - #97

Draft
fantazio wants to merge 7 commits into
LexiFi:masterfrom
fantazio:eq_types
Draft

Track type equivalences#97
fantazio wants to merge 7 commits into
LexiFi:masterfrom
fantazio:eq_types

Conversation

@fantazio

@fantazio fantazio commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Fix #79, #80, #81, #82

Context

The aforementioned issues are all related to the same pitfall : if a module re-exports a type as its own (no explicit link with the original one), then the analyzer believes that it is indeed a new type definition.
Consequently, if a constructor/field is used via one type but not another equivalent, then it is reported as unused for the latter.

Solution

We introduce a new associative list DeadType.equivalences to keep track of explicit equivalences (type t2 = t1 = ...) found in implementations, and implicit ones (due to includes and module aliases).
The list is later used in post-analysis and pre-report (in DeadType.prepare_report), to resolve all the equivalences and propagate uses of each member of an equivalence class to all the other members. As a result, if A.t = B.t but both are exported as new definitions, the reported components of both types are the same.
This sort of breaks the "independence" of the reports (i.e. each report line can be processed independently) because we report the same component multiple times (at different locations). A future improvement could be to only report the components of the original type. I.e. if t2 = t1 and t3 = t2, only report the components of t1.

In addition to this associative list, we also remember temporarily (as long as we analyze a compilation unit) the types of exported module types (in DeadSign.exported_modules, reset via DeadSign.eof). This is necessary to associate exported type components with a module alias because the module types on module aliases are reduced to Mty_alias without further info than the alias.

Tests

Tests for the corresponding issues have been introduced and the results show that they are now working as expected.

The changes in results on Opam and Frama-C are coherent. However, the performance is very negatively impacted (more than 70% slower on some benchmarks). Some cleanup and debugging is still expected.

Docs

Not up to date

In addition to documentation, examples are written and expected results
are updated accordingly.
This adds a lot of false positives in the tests, and as many false
negatives (misplacements) for the threshold test scenarios
The tracking is very naive (using an assoc list), and equivalent classes
are only resolved at the end in the new `DeadType.prepare_report`
function.
The role of this new function is to merge all the references of an
equivalent class and propagate the result back to its members.

As a result, the FP/FN related to type equations are now resolved.

The code still needs to be cleaned up but gives the direction to fix the
other FP/FN in the `equal_types` limitation.
When an include is encountered, all the type components defined in the
included module and in the ucrrent compilation unit are considered
equivalent.
Although the equivalence is not necessarily true (e.g. the current
implementation could redefine the same type explicitly and without
equation right after the include), this is a good effort towards
actionable results in the presence of type equalities.

This fixes include-related FP and FN in the `equal_types` limitation.
This requires more changes than anticipated. The module types available
in the .cmt where the aliasing occurs ar Mty_alias, and the surrounding
Env.t do not help retrieving a more detailed information.
Thus, we recreate in `DeadSign.exported_modules` what we hoped to find
in environments : the association from path to module type.
With this information, we are able to process a module alias's types and
fill out our equivalences list.

This fixes the remaining FP and FN (related to module aliases) of
limitation `equal_types`.
This specific example tests the handling of type equivalences within a
single compilation unit, with only one of the types exported.
All the internal types are equivalent, by means of eqcplicit equations,
hidden equations, module alias and include.
This relies on the use of the available env to retrieve the module types
of local aliases.
Internal type equivalences are stored with all the other equivalences
and resolved at the end.

This fixes the FP/FN of eq_types' all_internal examples.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Constructors uses are not tracked through type equations

1 participant