REF: Refactor assert_index_equal
There are currently some issues in `_check_dtypes` in `assert_index_equal` related to #41153:
* `assert_attr_equal("dtype", left, right, obj=obj)` currently isn't run if `check_categorical` is False (even if the indexes are not CategoricalIndexes)
* `assert_class_equal` with `exact='equiv'` should not be restricted to accept equivalence of `Int64Index` and `RangeIndex`, but should accept equivalence of all subclasses of `NumericIndex` (in preparation for #41153).

So, comparing numeric indexes with `assert_index_equal(idx1, idx2, exact="equiv")`  we should for otherwise equal content have:
* RangeIndex and Int64Index should pass, because they're both numeric indexes and have the same dtype
* Int64Index and Float64Index should  fail, because even though they're both numeric indexes, they have different dtypes
* Int64Index and NumericIndex[int64] should pass, because they're both numeric indexes and have the same dtype
* RangeIndex and NumericIndex[int64] should pass, because they're both numeric indexes and have the same dtype
* Float64Index and NumericIndex[int64] should fail, because even though they're both numeric indexes, they have different dtypes

Conversely, with `exact=True` class comparison should be strict, so:
* RangeIndex and Int64Index should fail, because they're different classes, even though they have the same dtype
* Int64Index and NumericIndex[int64] should fail, because they're different classes, even though they have the same dtype
* etc.

This refactoring does not change behaviour in master, but will make #41153 easier.
Everything passes localy, so seems like the CI failurees are unrelated. Rebased. thanks @topper-123 