Very clever! Use dynamic PL/SQL to construct a block. Then try to treat the collection type as string-indexed. If it fails with a VALUE_ERROR exception it must be an integer-indexed collection type!
CREATE OR REPLACE FUNCTION index_type (type_owner VARCHAR2,
type_name VARCHAR2,
type_subname VARCHAR2)
RETURN VARCHAR2
IS
l_result VARCHAR2 (50) := 'UNKNOWN';
BEGIN
EXECUTE IMMEDIATE
q'[
DECLARE
l_result VARCHAR(50);
v "]'
|| type_owner
|| '"."'
|| type_name
|| '"."'
|| type_subname
|| q'[";
BEGIN
BEGIN
v('A') := NULL;
l_result := 'VARCHAR2';
EXCEPTION
WHEN OTHERS THEN
BEGIN
v(1) := NULL;
l_result := 'PLS_INTEGER';
EXCEPTION
WHEN OTHERS THEN l_result := 'UNKNOWN';
END;
END;
:result := l_result;
END;]'
USING OUT l_result;
RETURN l_result;
EXCEPTION
WHEN OTHERS
THEN
RETURN SQLERRM;
END index_type;