Looks like the function get_actual_variable_range() was written with the knowledge that virtual/hypothetical indexes may exist, but the assumption seems wrong.
One one hand get_actual_variable_range() expects that virtual indexes do not have an OID assigned, on the other hand explain_get_index_name_hook() is handed just an index's OID to get its name back; IMHO these are based on two conflicting assumptions about whether a virtual index will have an OID assigned.
Attached patch fix_get_actual_variable_range.patch tries to fix this by introducing a new hook that can help Postgres decide if an index is fictitious or not.
The new hook takes an index oid as argument, so I gather that you resolved the contradiction by deciding that fictitious indexes have OIDs. How do you assign those OIDs? Do fictitious indexes have entries in pg_index?
No, a fictitious index does not touch pg_index. The Index Advisor uses GetNewOid(pg_class) to generate a new OID for the fictitious index.
An OID is the only way we can identify one fictitious index from the list of all the others fictitious ones when explain_get_index_name_hook() is called. I don't see any other way the Postgres server can ask the for the details of a fictitious index.