Skip to content

Commit f599007

Browse files
Fix ExprArithmetic Type Resolutions (#7976)
1 parent fa2ba88 commit f599007

File tree

3 files changed

+60
-14
lines changed

3 files changed

+60
-14
lines changed

src/main/java/ch/njol/skript/expressions/arithmetic/ExprArithmetic.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -164,31 +164,29 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
164164
} else { // first needs converting
165165
// attempt to convert <first> to types that make valid operations with <second>
166166
Class<?> secondClass = second.getReturnType();
167-
Class[] leftTypes = Arithmetics.getOperations(operator).stream()
168-
.filter(info -> info.getRight().isAssignableFrom(secondClass))
169-
.map(OperationInfo::getLeft)
170-
.toArray(Class[]::new);
171-
if (leftTypes.length == 0) { // no known operations with second's type
167+
List<? extends OperationInfo<?, ?, ?>> operations = Arithmetics.lookupRightOperations(operator, secondClass);
168+
if (operations.isEmpty()) { // no known operations with second's type
172169
if (secondClass != Object.class) // there won't be any operations
173170
return error(first.getReturnType(), secondClass);
174171
first = (Expression<L>) first.getConvertedExpression(Object.class);
175172
} else {
176-
first = (Expression<L>) first.getConvertedExpression(leftTypes);
173+
first = (Expression<L>) first.getConvertedExpression(operations.stream()
174+
.map(OperationInfo::getLeft)
175+
.toArray(Class[]::new));
177176
}
178177
}
179178
} else if (second instanceof UnparsedLiteral) { // second needs converting
180179
// attempt to convert <second> to types that make valid operations with <first>
181180
Class<?> firstClass = first.getReturnType();
182-
List<? extends OperationInfo<?, ?, ?>> operations = Arithmetics.getOperations(operator, firstClass);
181+
List<? extends OperationInfo<?, ?, ?>> operations = Arithmetics.lookupLeftOperations(operator, firstClass);
183182
if (operations.isEmpty()) { // no known operations with first's type
184183
if (firstClass != Object.class) // there won't be any operations
185184
return error(firstClass, second.getReturnType());
186185
second = (Expression<R>) second.getConvertedExpression(Object.class);
187186
} else {
188187
second = (Expression<R>) second.getConvertedExpression(operations.stream()
189188
.map(OperationInfo::getRight)
190-
.toArray(Class[]::new)
191-
);
189+
.toArray(Class[]::new));
192190
}
193191
}
194192

@@ -223,14 +221,13 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
223221
Class<?>[] returnTypes = null;
224222
if (!(firstClass == Object.class && secondClass == Object.class)) { // both aren't object
225223
if (firstClass == Object.class) {
226-
returnTypes = Arithmetics.getOperations(operator).stream()
227-
.filter(info -> info.getRight().isAssignableFrom(secondClass))
224+
returnTypes = Arithmetics.lookupRightOperations(operator, secondClass).stream()
228225
.map(OperationInfo::getReturnType)
229226
.toArray(Class[]::new);
230227
} else { // secondClass is Object
231-
returnTypes = Arithmetics.getOperations(operator, firstClass).stream()
232-
.map(OperationInfo::getReturnType)
233-
.toArray(Class[]::new);
228+
returnTypes = Arithmetics.lookupLeftOperations(operator, firstClass).stream()
229+
.map(OperationInfo::getReturnType)
230+
.toArray(Class[]::new);
234231
}
235232
}
236233
if (returnTypes == null) { // both are object; can't determine anything

src/main/java/org/skriptlang/skript/lang/arithmetic/Arithmetics.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.List;
1313
import java.util.Map;
1414
import java.util.Collection;
15+
import java.util.Objects;
1516
import java.util.Set;
1617
import java.util.HashSet;
1718
import java.util.function.Supplier;
@@ -83,6 +84,47 @@ public static boolean operationExists(Operator operator, Class<?> leftClass, Cla
8384
.collect(Collectors.toList());
8485
}
8586

87+
/**
88+
* Returns all valid operations from {@code operator} and {@code leftClass}.
89+
* Unlike {@link #getOperations(Operator, Class)}, this method considers Converters.
90+
* @param operator The operator for the desired operations
91+
* @param leftClass Class representing the desired left-hand argument type
92+
* @return A list containing all valid operations from {@code operator} and {@code leftClass}.
93+
* @param <L> The type of the left-hand argument
94+
*/
95+
@SuppressWarnings({"unchecked", "rawtypes"})
96+
public static <L> List<OperationInfo<L, ?, ?>> lookupLeftOperations(Operator operator, Class<L> leftClass) {
97+
return (List) getOperations(operator).stream()
98+
.map(info -> {
99+
if (info.getLeft().isAssignableFrom(leftClass)) {
100+
return info;
101+
}
102+
return info.getConverted(leftClass, info.getRight(), info.getReturnType());
103+
})
104+
.filter(Objects::nonNull)
105+
.collect(Collectors.toList());
106+
}
107+
108+
/**
109+
* Returns all valid operations from {@code operator} and {@code rightClass}.
110+
* @param operator The operator for the desired operations
111+
* @param rightClass Class representing the desired right-hand argument type
112+
* @return A list containing all valid operations from {@code operator} and {@code rightClass}.
113+
* @param <R> The type of the right-hand argument
114+
*/
115+
@SuppressWarnings({"unchecked", "rawtypes"})
116+
public static <R> List<OperationInfo<?, R, ?>> lookupRightOperations(Operator operator, Class<R> rightClass) {
117+
return (List) getOperations(operator).stream()
118+
.map(info -> {
119+
if (info.getRight().isAssignableFrom(rightClass)) {
120+
return info;
121+
}
122+
return info.getConverted(info.getLeft(), rightClass, info.getReturnType());
123+
})
124+
.filter(Objects::nonNull)
125+
.collect(Collectors.toList());
126+
}
127+
86128
@Nullable
87129
@SuppressWarnings("unchecked")
88130
public static <L, R, T> OperationInfo<L, R, T> getOperationInfo(Operator operator, Class<L> leftClass, Class<R> rightClass, Class<T> returnType) {

src/test/skript/tests/syntaxes/expressions/ExprArithmetic.sk

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,10 @@ test "arithmetic type switcheroo":
278278
loop 2 times:
279279
set {_x} to {_a} + {_b}
280280
set {_b} to 5
281+
282+
local function arithmetic_xp() returns experience:
283+
return 5 xp
284+
285+
test "arithmetic parse time conversion":
286+
set {_x} to arithmetic_xp() + 5
287+
assert {_x} is 10 with "failed to calculate experience + number"

0 commit comments

Comments
 (0)