|
| 1 | +- Start Date: 2024-01-08 |
| 2 | +- RFC PR: [amaranth-lang/rfcs#39](https://github.com/amaranth-lang/rfcs/pull/39) |
| 3 | +- Amaranth Issue: [amaranth-lang/amaranth#1021](https://github.com/amaranth-lang/amaranth/issues/1021) |
| 4 | + |
| 5 | +# Change semantics of no-argument `m.Case()` |
| 6 | + |
| 7 | +## Summary |
| 8 | +[summary]: #summary |
| 9 | + |
| 10 | +Change the semantics of `with m.Case():` (without any arguments) from always-true conditional to always-false conditional. Likewise, change `value.matches()` from returning `C(1)` to returning `C(0)`. |
| 11 | + |
| 12 | +## Motivation |
| 13 | +[motivation]: #motivation |
| 14 | + |
| 15 | +Currently, `with m.Case():` results in an always-true conditional, and `value.matches()` likewise returns a const-1 value. However, this is not consistent with what would be expected from extrapolating the non-empty case. |
| 16 | + |
| 17 | +In all non-empty cases, the semantics are equivalent to an OR of equality comparisons with all specified values: |
| 18 | + |
| 19 | +`value.matches(1, 2, 3) =def= (value == 1) | (value == 2) | (value == 3)` |
| 20 | + |
| 21 | +`value.matches(1, 2, 3) =def= Const(0) | (value == 1) | (value == 2) | (value == 3)` |
| 22 | + |
| 23 | +Extrapolating from this, one would expect `value.matches()` to be the empty OR, ie. `Const(0)`. |
| 24 | + |
| 25 | +It is unlikely that any manually written code will rely on this, but this can be a dangerous trap for machine-generated code that doesn't take the empty case into account. |
| 26 | + |
| 27 | +## Guide-level explanation |
| 28 | +[guide-level-explanation]: #guide-level-explanation |
| 29 | + |
| 30 | +The semantics of `m.Case()` change from always matching to never matching. Likewise, the semantics of `value.matches()` change from always-1 to always-0. The change is committed to the current `main` branch and will be included in Amaranth 0.5. |
| 31 | + |
| 32 | +Amaranth 0.4.1 is released with the old semantics, but a deprecation warning is emitted whenever `m.Case()` or `value.matches()` is used. |
| 33 | + |
| 34 | +## Reference-level explanation |
| 35 | +[reference-level-explanation]: #reference-level-explanation |
| 36 | + |
| 37 | +See above. |
| 38 | + |
| 39 | +## Drawbacks |
| 40 | +[drawbacks]: #drawbacks |
| 41 | + |
| 42 | +Obviously backwards-incompatible, changes the semantics of a language construct to the direct opposite. |
| 43 | + |
| 44 | +## Rationale and alternatives |
| 45 | +[rationale-and-alternatives]: #rationale-and-alternatives |
| 46 | + |
| 47 | +It is unlikely anyone actually uses `value.matches()` directly, since this is just a constant. For generated code, the current semantics is much more likely to be a bug that intended behavior. |
| 48 | + |
| 49 | +For `m.Case()` the situation is similar: it is redundant with `m.Default()`, which should be used instead. It is somewhat possible that there is code out there written by someone who didn't know about `m.Default()` and ended up using `m.Case()` instead (the official documentation didn't include either for a long time). This code will need to be fixed. |
| 50 | + |
| 51 | +An alternative, if the empty case is deemed too confusing or insufficiently useful, is to make the semantics a hard error instead. |
| 52 | + |
| 53 | +## Prior art |
| 54 | +[prior-art]: #prior-art |
| 55 | + |
| 56 | +The current behavior is likely taken directly from RTLIL, which exhibits a similar inconsistency. |
| 57 | + |
| 58 | +## Unresolved questions |
| 59 | +[unresolved-questions]: #unresolved-questions |
| 60 | + |
| 61 | +Should we include more warnings about the change? This RFC proposes a warning in the 0.4.1 release, but this will never be seen by someone always using amaranth from git main. |
| 62 | + |
| 63 | +## Future possibilities |
| 64 | +[future-possibilities]: #future-possibilities |
| 65 | + |
| 66 | +None. |
0 commit comments