Class GenericInputVarietyWidener

java.lang.Object
org.ek9lang.compiler.phase5.GenericInputVarietyWidener
All Implemented Interfaces:
Consumer<CompilableProgram>

final class GenericInputVarietyWidener extends Object implements Consumer<CompilableProgram>
Widens a GENERIC construct's input-variety denominator to span the types it is actually parameterised with (design D11/W5b).

The problem. InputVarietyDenominatorRecorder scores each dimension through EquivalenceClassModel, which has no model for a conceptual T and so returns its FLOOR — 2 classes at ClassConfidence.SET_UNSET_ONLY. A T-typed dimension therefore saturates after two calls: Holder.Holder read floor 2, driven 2, drivenPercent 100.0 however many types the generic was used with. The metric said "fully varied" about the one dimension it understood least.

The rule. A T dimension's opportunity space is the SUM of the class counts of every type the generic is actually parameterised with in this program. Driving Holder of String with a String and Holder of Integer with an Integer are two genuinely different input situations, and the denominator should say so.

⚠️ The trade-off this accepts. The floor now depends on parameterisations anywhere in the program, so adding a Holder of Date lowers every Holder percentage — including in code that never touches Date. That is deliberate: the metric answers "of all the input situations this generic could be put in, how many did you try?", and a new parameterisation genuinely enlarges that space. The alternative (a row per parameterisation) keeps rows independent but fragments the union the numerator achieves. Variety is display-only and never gates, so neither choice can change a build outcome.

Only conceptual dimensions widen. A receiver typed as the generic itself is NOT widened: a user class admits set/unset whatever its type argument is, so widening it would inflate without discriminating. The rule is about T, not about "anything mentioning T".

Why a post-pass, and why here. Parameterisations are created during resolution and live in whichever module scope first referenced them, so finding them needs a program-wide sweep — and ModuleScope.getSymbolsForThisScope() is PER FILE, so a per-source listener cannot see them all. This phase already holds compilableProgramAccess and already runs post-passes, and by the time it does every per-source recorder has squirrelled its base floor. 🔑 The generic's own getGenericSymbolReferences() looks like the answer and is NOT — it is never populated (measured: refs=0 for a generic with two live parameterisations), which its own author's "still in two minds about adding these references" comment foreshadows.