Note the dest_class case didn't actually check dyn_cast success until after using the pointer. That's the case I noticed first, but also cleaning up a couple other small related things.
Add a generic mechanism to decompose a `Value` and rebuild it, and use that to implement `Substitute`'s recursive transformation of values instead of a hand-rolled decomposition. This means `Substitute` now covers all kinds of values, whereas previously it used to be unable to transform some values, and should be less work to add new kinds of value.
We can use the same mechanism for various other things: structural dumping of values, equality comparisons, and value instantiation in the interpreter would all benefit from this. But in this change I'm just switching `Substitute` to this as a first step.
Features:
* Split `Member` class into 3 dedicated classes covering named, positional, and a new "base class" element
Changes:
* Rename `Member` to `Element` to better reflect the variants covered
* Add `NamedElement`, `PositionalElement`, and `BaseElement` child classes for `Element`
* Split `GetMember` into 3 function variants based on available attributes (index, name, nothing).
* Add some unit tests to provide coverage of core features
Motivation:
This changeset splits Member into (currently 2) classes, as we see the need for more Member variants (base class access needed for #2378, possibly unnamed mixins, ...), which in addition to the current ones, also have significantly different attributes. This will allow supporting more Member types in the future cleanly.
Alternatives considered:
The alternative solution, "one class for positional, named & base class access", would expose unused or unavailable attributes depending on the Member actual type (`index()` only for positional, `name()` only for named, and neither for base class access).