@PublicEvolving
    public static <IN, OUT> TypeInformation<OUT> getMapReturnTypes(
            MapFunction<IN, OUT> mapInterface, TypeInformation<IN> inType) {
        return getMapReturnTypes(mapInterface, inType, null, false);
    }
@SuppressWarnings({"unchecked", "rawtypes"})
    @Test
    void testNestedTupleGenerics2() {
        RichMapFunction<?, ?> function =
                new RichMapFunction<Nested2<Boolean>, Nested2<Boolean>>() {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public Nested2<Boolean> map(Nested2<Boolean> value) throws Exception {
                        return null;
                    }
                };

        TypeInformation<?> ti =
                TypeExtractor.getMapReturnTypes(
                        function,
                        (TypeInformation)
                                TypeInformation.of(
                                        new TypeHint<
                                                Tuple2<
                                                        Boolean,
                                                        Tuple2<
                                                                Tuple2<
                                                                        Integer,
                                                                        Tuple2<Boolean, Boolean>>,
                                                                Tuple2<
                                                                        Integer,
                                                                        Tuple2<
                                                                                Boolean,
                                                                                Boolean>>>>>() {}));

        // Should be
        // Tuple2<Boolean, Tuple2<Tuple2<Integer, Tuple2<Boolean, Boolean>>, Tuple2<Integer,
        // Tuple2<Boolean, Boolean>>>>

        // 1st nested level
        assertThat(ti.isTupleType()).isTrue();
        assertThat(ti.getArity()).isEqualTo(2);
        TupleTypeInfo<?> tti = (TupleTypeInfo<?>) ti;
        assertThat(tti.getTypeAt(0)).isEqualTo(BasicTypeInfo.BOOLEAN_TYPE_INFO);
        assertThat(tti.getTypeAt(1).isTupleType()).isTrue();

        // 2nd nested level
        TupleTypeInfo<?> tti2 = (TupleTypeInfo<?>) tti.getTypeAt(1);
        assertThat(tti2.getTypeAt(0).isTupleType()).isTrue();
        assertThat(tti2.getTypeAt(1).isTupleType()).isTrue();

        // 3rd nested level
        TupleTypeInfo<?> tti3 = (TupleTypeInfo<?>) tti2.getTypeAt(0);
        assertThat(tti3.getTypeAt(0)).isEqualTo(BasicTypeInfo.INT_TYPE_INFO);
        assertThat(tti3.getTypeAt(1).isTupleType()).isTrue();

        // 4th nested level
        TupleTypeInfo<?> tti4 = (TupleTypeInfo<?>) tti3.getTypeAt(1);
        assertThat(tti4.getTypeAt(0)).isEqualTo(BasicTypeInfo.BOOLEAN_TYPE_INFO);
        assertThat(tti4.getTypeAt(1)).isEqualTo(BasicTypeInfo.BOOLEAN_TYPE_INFO);
    }