|
24 | 24 | import ch.njol.skript.lang.Expression;
|
25 | 25 | import ch.njol.skript.lang.SkriptParser.ParseResult;
|
26 | 26 | import ch.njol.skript.registrations.Classes;
|
| 27 | +import ch.njol.skript.util.Utils; |
27 | 28 | import ch.njol.util.Checker;
|
28 | 29 | import ch.njol.util.Kleenean;
|
29 | 30 | import ch.njol.util.coll.CollectionUtils;
|
@@ -96,24 +97,31 @@ public ConvertedExpression(Expression<? extends F> source, Class<T> to, Collecti
|
96 | 97 | @Nullable
|
97 | 98 | public static <F, T> ConvertedExpression<F, T> newInstance(Expression<F> from, Class<T>... to) {
|
98 | 99 | assert !CollectionUtils.containsSuperclass(to, from.getReturnType());
|
99 |
| - // we track a list of converters that may work |
100 |
| - List<ConverterInfo<? super F, ? extends T>> converters = new ArrayList<>(); |
101 |
| - for (Class<T> type : to) { // REMIND try more converters? -> also change WrapperExpression (and maybe ExprLoopValue) |
102 |
| - assert type != null; |
103 |
| - // casting <? super ? extends F> to <? super F> is wrong, but since the converter is only used for values returned by the expression |
104 |
| - // (which are instances of "<? extends F>") this won't result in any ClassCastExceptions. |
105 |
| - for (Class<? extends F> checking : from.possibleReturnTypes()) { |
106 |
| - //noinspection unchecked |
107 |
| - ConverterInfo<? super F, ? extends T> converter = (ConverterInfo<? super F, ? extends T>) Converters.getConverterInfo(checking, type); |
108 |
| - if (converter != null) |
109 |
| - converters.add(converter); |
| 100 | + |
| 101 | + // we might be able to cast some (or all) of the possible return types to T |
| 102 | + // for possible return types that can't be directly cast, regular converters will be used |
| 103 | + List<ConverterInfo<? extends F, ? extends T>> infos = new ArrayList<>(); |
| 104 | + for (Class<? extends F> type : from.possibleReturnTypes()) { |
| 105 | + if (CollectionUtils.containsSuperclass(to, type)) { // this type is of T, build a converter simply casting |
| 106 | + // noinspection unchecked - 'type' is a desired type in 'to' |
| 107 | + Class<T> toType = (Class<T>) type; |
| 108 | + infos.add(new ConverterInfo<>(type, toType, toType::cast, 0)); |
| 109 | + } else { // this possible return type is not included in 'to' |
| 110 | + // build all converters for converting the possible return type into any of the types of 'to' |
| 111 | + for (Class<T> toType : to) { |
| 112 | + ConverterInfo<? extends F, T> converter = Converters.getConverterInfo(type, toType); |
| 113 | + if (converter != null) |
| 114 | + infos.add(converter); |
| 115 | + } |
110 | 116 | }
|
111 |
| - int size = converters.size(); |
112 |
| - if (size == 1) // if there is only one info, there is no need to wrap it in a list |
113 |
| - return new ConvertedExpression<>(from, type, converters.get(0)); |
114 |
| - if (size > 1) |
115 |
| - return new ConvertedExpression<>(from, type, converters, true); |
116 | 117 | }
|
| 118 | + if (!infos.isEmpty()) { // there are converters for (at least some of) the return types |
| 119 | + // a note: casting <? extends F> to <? super F> is wrong, but since the converter is used only for values |
| 120 | + // returned by the expression (which are instances of <? extends F>), this won't result in any CCEs |
| 121 | + // noinspection rawtypes, unchecked |
| 122 | + return new ConvertedExpression(from, Utils.getSuperType(infos.stream().map(ConverterInfo::getTo).toArray(Class[]::new)), infos, true); |
| 123 | + } |
| 124 | + |
117 | 125 | return null;
|
118 | 126 | }
|
119 | 127 |
|
|
0 commit comments