Skip to content

Commit 5dce04a

Browse files
Return type accuracy and usage improvements (SkriptLang#7891)
* Return type improvements * Silly debug statement * Safety improvements * Type resolution improvements * Use possibleReturnTypes in ExprFunctionCall * Implement return type logic on more expressions * Implement return type logic on even more expressions Hopefully this is it
1 parent 39fd829 commit 5dce04a

35 files changed

Lines changed: 353 additions & 189 deletions

src/main/java/ch/njol/skript/effects/EffToggle.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ private enum Type {
5353

5454
/**
5555
* Determines the appropriate Type based on the return type of an expression.
56-
* @param returnType The class representing the return type
56+
* @param expression The expression to determine the type of.
5757
* @return The corresponding Type
5858
*/
59-
public static Type fromClass(Class<?> returnType) {
60-
boolean isBlockType = Block.class.isAssignableFrom(returnType);
61-
boolean isBooleanType = Boolean.class.isAssignableFrom(returnType);
59+
public static Type fromClass(Expression<?> expression) {
60+
boolean isBlockType = expression.canReturn(Block.class);
61+
boolean isBooleanType = expression.canReturn(Boolean.class);
6262

6363
if (isBlockType && !isBooleanType) {
6464
return BLOCKS;
@@ -90,7 +90,7 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
9090
action = patterns.getInfo(matchedPattern);
9191

9292
// Determine expression type using the enum method
93-
type = Type.fromClass(togglables.getReturnType());
93+
type = Type.fromClass(togglables);
9494

9595
// Validate based on type
9696
if (type == Type.BOOLEANS &&

src/main/java/ch/njol/skript/effects/EffVisualEffect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
7979
Skript.warning("Entity effects are visible to all players");
8080
if (!hasLocationEffect && !direction.isDefault())
8181
Skript.warning("Entity effects are always played on an entity");
82-
if (hasEntityEffect && !Entity.class.isAssignableFrom(where.getReturnType())) {
82+
if (hasEntityEffect && !where.canReturn(Entity.class)) {
8383
Skript.error("Entity effects can only be played on entities");
8484
return false;
8585
}

src/main/java/ch/njol/skript/events/EvtClick.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public class EvtClick extends SkriptEvent {
8080
public boolean init(Literal<?>[] args, int matchedPattern, ParseResult parseResult) {
8181
click = parseResult.mark == 0 ? ANY : parseResult.mark;
8282
type = args[matchedPattern];
83-
if (type != null && !ItemType.class.isAssignableFrom(type.getReturnType()) && !BlockData.class.isAssignableFrom(type.getReturnType())) {
83+
if (type != null && !type.canReturn(ItemType.class) && !type.canReturn(BlockData.class)) {
8484
Literal<EntityData<?>> entitydata = (Literal<EntityData<?>>) type;
8585
if (click == LEFT) {
8686
if (Vehicle.class.isAssignableFrom(entitydata.getSingle().getType())) {

src/main/java/ch/njol/skript/expressions/ExprAge.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public class ExprAge extends SimplePropertyExpression<Object, Integer> {
4747
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
4848
isMax = parseResult.hasTag("max");
4949
setExpr(exprs[0]);
50-
if (isMax && Entity.class.isAssignableFrom(getExpr().getReturnType())) {
50+
if (isMax && !getExpr().canReturn(Block.class)) {
5151
Skript.error("Cannot use 'max age' expression with entities, use just the 'age' expression instead");
5252
return false;
5353
}

src/main/java/ch/njol/skript/expressions/ExprAttacker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected Entity[] get(Event e) {
6161
}
6262

6363
@Nullable
64-
private static Entity getAttacker(@Nullable Event e) {
64+
static Entity getAttacker(@Nullable Event e) {
6565
if (e == null)
6666
return null;
6767
if (e instanceof EntityDamageByEntityEvent) {

src/main/java/ch/njol/skript/expressions/ExprBannerPatterns.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -218,20 +218,24 @@ private Consumer<Banner> getAllBlockChanger(ChangeMode mode, List<Pattern> patte
218218

219219
@Override
220220
public void change(Event event, Object @Nullable [] delta, ChangeMode mode) {
221-
Pattern[] patterns = (Pattern[]) delta;
222-
int placement = patternNumber == null ? 0 : patternNumber.getSingle(event);
223-
List<Pattern> patternList = patterns != null ? Arrays.stream(patterns).toList() : new ArrayList<>();
224-
225-
Consumer<BannerMeta> metaChanger = null;
226-
Consumer<Banner> blockChanger = null;
221+
int placement = 0;
222+
if (patternNumber != null) {
223+
Integer patternNum = patternNumber.getSingle(event);
224+
if (patternNum != null) {
225+
placement = patternNum;
226+
}
227+
}
228+
List<Pattern> patterns = delta != null ? Arrays.stream(delta).map(Pattern.class::cast).toList() : new ArrayList<>();
227229

230+
Consumer<BannerMeta> metaChanger;
231+
Consumer<Banner> blockChanger;
228232
if (placement >= 1) {
229-
Pattern pattern = patternList.size() == 1 ? patternList.get(0) : null;
233+
Pattern pattern = patterns.size() == 1 ? patterns.get(0) : null;
230234
metaChanger = getPlacementMetaChanger(mode, placement, pattern);
231235
blockChanger = getPlacementBlockChanger(mode, placement, pattern);
232236
} else {
233-
metaChanger = getAllMetaChanger(mode, patternList);
234-
blockChanger = getAllBlockChanger(mode, patternList);
237+
metaChanger = getAllMetaChanger(mode, patterns);
238+
blockChanger = getAllBlockChanger(mode, patterns);
235239
}
236240

237241
for (Object object : objects.getArray(event)) {

src/main/java/ch/njol/skript/expressions/ExprBeaconValues.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,12 @@ public boolean isSingle() {
189189
}
190190

191191
@Override
192-
public Class<Object> getReturnType() {
193-
return Object.class;
192+
public Class<?> getReturnType() {
193+
return switch (valueType) {
194+
case PRIMARY, SECONDARY -> PotionEffectType.class;
195+
case RANGE -> Double.class;
196+
case TIER -> Integer.class;
197+
};
194198
}
195199

196200
@Override

src/main/java/ch/njol/skript/expressions/ExprColorOf.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,27 +92,19 @@ protected Color[] get(Event event, Object[] source) {
9292

9393
@Override
9494
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
95-
Class<?> returnType = getExpr().getReturnType();
95+
Expression<?> expression = getExpr();
9696

97-
if (returnType.isAssignableFrom(FireworkEffect.class))
97+
if (expression.canReturn(FireworkEffect.class))
9898
return CollectionUtils.array(Color[].class);
9999

100-
// double assignable checks are to allow both parent and child types, since variables return Object
101-
// This does mean we have to be more stringent in checking the validity of the change mode in change() itself.
102-
if ((returnType.isAssignableFrom(Display.class) || Display.class.isAssignableFrom(returnType)) && (mode == ChangeMode.RESET || mode == ChangeMode.SET))
100+
if ((mode == ChangeMode.RESET || mode == ChangeMode.SET) && expression.canReturn(Display.class))
103101
return CollectionUtils.array(Color.class);
104102

105-
// the following only support SET
106-
if (mode != ChangeMode.SET)
107-
return null;
108-
if (returnType.isAssignableFrom(Entity.class)
109-
|| Entity.class.isAssignableFrom(returnType)
110-
|| returnType.isAssignableFrom(Block.class)
111-
|| Block.class.isAssignableFrom(returnType)
112-
|| returnType.isAssignableFrom(ItemType.class)
113-
) {
103+
if (mode == ChangeMode.SET &&
104+
(expression.canReturn(Entity.class) || expression.canReturn(Block.class) || expression.canReturn(ItemType.class))) {
114105
return CollectionUtils.array(Color.class);
115106
}
107+
116108
return null;
117109
}
118110

src/main/java/ch/njol/skript/expressions/ExprDefaultValue.java

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,93 +9,77 @@
99
import ch.njol.skript.lang.ExpressionType;
1010
import ch.njol.skript.lang.SkriptParser;
1111
import ch.njol.skript.lang.util.SimpleExpression;
12-
import org.skriptlang.skript.lang.converter.Converters;
1312
import ch.njol.skript.util.LiteralUtils;
1413
import ch.njol.skript.util.Utils;
1514
import ch.njol.util.Kleenean;
1615
import org.bukkit.event.Event;
17-
import org.jetbrains.annotations.Nullable;
1816

19-
import java.lang.reflect.Array;
17+
import java.util.Arrays;
18+
import java.util.Collections;
19+
import java.util.HashSet;
20+
import java.util.Set;
2021

2122
@Name("Default Value")
2223
@Description("A shorthand expression for giving things a default value. If the first thing isn't set, the second thing will be returned.")
2324
@Examples({"broadcast {score::%player's uuid%} otherwise \"%player% has no score!\""})
2425
@Since("2.2-dev36")
25-
@SuppressWarnings("null")
26-
public class ExprDefaultValue<T> extends SimpleExpression<T> {
26+
public class ExprDefaultValue extends SimpleExpression<Object> {
2727

2828
static {
2929
Skript.registerExpression(ExprDefaultValue.class, Object.class, ExpressionType.COMBINED,
3030
"%objects% (otherwise|?) %objects%");
3131
}
3232

33-
private final ExprDefaultValue<?> source;
34-
private final Class<? extends T>[] types;
35-
private final Class<T> superType;
36-
@Nullable
37-
private Expression<Object> first;
38-
@Nullable
39-
private Expression<Object> second;
33+
private Class<?>[] types;
34+
private Class<?> superType;
4035

41-
@SuppressWarnings("unchecked")
42-
public ExprDefaultValue() {
43-
this(null, (Class<? extends T>) Object.class);
44-
}
45-
46-
@SuppressWarnings("unchecked")
47-
private ExprDefaultValue(ExprDefaultValue<?> source, Class<? extends T>... types) {
48-
this.source = source;
49-
if (source != null) {
50-
this.first = source.first;
51-
this.second = source.second;
52-
}
53-
this.types = types;
54-
this.superType = (Class<T>) Utils.getSuperType(types);
55-
}
36+
private Expression<Object> values;
37+
private Expression<Object> defaultValues;
5638

5739
@Override
5840
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
59-
first = LiteralUtils.defendExpression(exprs[0]);
60-
second = LiteralUtils.defendExpression(exprs[1]);
61-
return LiteralUtils.canInitSafely(first, second);
62-
}
63-
64-
@Override
65-
@SuppressWarnings("unchecked")
66-
protected T[] get(Event e) {
67-
Object[] first = this.first.getArray(e);
68-
Object values[] = first.length != 0 ? first : second.getArray(e);
69-
try {
70-
return Converters.convert(values, types, superType);
71-
} catch (ClassCastException e1) {
72-
return (T[]) Array.newInstance(superType, 0);
41+
values = LiteralUtils.defendExpression(exprs[0]);
42+
defaultValues = LiteralUtils.defendExpression(exprs[1]);
43+
if (!LiteralUtils.canInitSafely(values, defaultValues)) {
44+
return false;
7345
}
46+
47+
Set<Class<?>> types = new HashSet<>();
48+
Collections.addAll(types, values.possibleReturnTypes());
49+
Collections.addAll(types, defaultValues.possibleReturnTypes());
50+
this.types = types.toArray(new Class<?>[0]);
51+
this.superType = Utils.getSuperType(this.types);
52+
53+
return true;
7454
}
7555

7656
@Override
77-
public <R> Expression<? extends R> getConvertedExpression(Class<R>... to) {
78-
return new ExprDefaultValue<>(this, to);
57+
protected Object[] get(Event event) {
58+
Object[] values = this.values.getArray(event);
59+
if (values.length != 0) {
60+
return values;
61+
}
62+
return defaultValues.getArray(event);
7963
}
8064

8165
@Override
82-
public Expression<?> getSource() {
83-
return source == null ? this : source;
66+
public boolean isSingle() {
67+
return values.isSingle() && defaultValues.isSingle();
8468
}
8569

8670
@Override
87-
public Class<? extends T> getReturnType() {
71+
public Class<?> getReturnType() {
8872
return superType;
8973
}
9074

9175
@Override
92-
public boolean isSingle() {
93-
return first.isSingle() && second.isSingle();
76+
public Class<?>[] possibleReturnTypes() {
77+
return Arrays.copyOf(types, types.length);
9478
}
9579

9680
@Override
97-
public String toString(Event e, boolean debug) {
98-
return first.toString(e, debug) + " or else " + second.toString(e, debug);
81+
public String toString(Event event, boolean debug) {
82+
return values.toString(event, debug) + " or else " + defaultValues.toString(event, debug);
9983
}
10084

10185
}

src/main/java/ch/njol/skript/expressions/ExprElement.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,22 @@ public Class<? extends T> getReturnType() {
237237
return expr.getReturnType();
238238
}
239239

240+
@Override
241+
public Class<? extends T>[] possibleReturnTypes() {
242+
if (!queue) {
243+
return expr.possibleReturnTypes();
244+
}
245+
return super.possibleReturnTypes();
246+
}
247+
248+
@Override
249+
public boolean canReturn(Class<?> returnType) {
250+
if (!queue) {
251+
return expr.canReturn(returnType);
252+
}
253+
return super.canReturn(returnType);
254+
}
255+
240256
@Override
241257
public String toString(@Nullable Event event, boolean debug) {
242258
String prefix;

0 commit comments

Comments
 (0)