From 910a63214e395ecae6993d8e0487384c725b3dd3 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 26 Jun 2023 21:46:55 +0100 Subject: [PATCH] Make Generic methods per-ComputerContext - Move the class cache out of Generator into MethodSupplierImpl. This means we cache class generation globally (that's really expensive!), but the class -> method list lookup is local. - Move the global GenericSource/GenericMethod registry out of core, passing in the list of generic methods to the ComputerContext. I'm not entirely thrilled by the slight overlap of MethodSupplierImpl and Generator here, something to clean up in the future. --- .../impl/AbstractComputerCraftAPI.java | 3 +- .../computercraft/impl/ApiFactories.java | 11 ++- .../computercraft/impl/GenericSources.java | 34 +++++++ .../shared/computer/core/ServerContext.java | 2 + .../computercraft/core/ComputerContext.java | 21 +++- .../computercraft/core/asm/Generator.java | 65 +----------- .../computercraft/core/asm/GenericMethod.java | 31 ++---- .../core/asm/LuaMethodSupplier.java | 15 ++- .../core/asm/MethodSupplierImpl.java | 99 ++++++++++++++++++- .../core/asm/PeripheralMethodSupplier.java | 11 ++- .../core/apis/ObjectWrapper.java | 3 +- .../computercraft/core/asm/GeneratorTest.java | 3 +- 12 files changed, 193 insertions(+), 105 deletions(-) create mode 100644 projects/common/src/main/java/dan200/computercraft/impl/GenericSources.java diff --git a/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java b/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java index b6ba303f8..dc4ca4f7a 100644 --- a/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java +++ b/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java @@ -19,7 +19,6 @@ import dan200.computercraft.api.redstone.BundledRedstoneProvider; import dan200.computercraft.api.turtle.TurtleRefuelHandler; import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser; -import dan200.computercraft.core.asm.GenericMethod; import dan200.computercraft.core.filesystem.WritableFileMount; import dan200.computercraft.impl.detail.DetailRegistryImpl; import dan200.computercraft.impl.network.wired.WiredNodeImpl; @@ -78,7 +77,7 @@ public final WritableMount createSaveDirMount(MinecraftServer server, String sub @Override public final void registerGenericSource(GenericSource source) { - GenericMethod.register(source); + GenericSources.register(source); } @Override diff --git a/projects/common/src/main/java/dan200/computercraft/impl/ApiFactories.java b/projects/common/src/main/java/dan200/computercraft/impl/ApiFactories.java index ef96738ef..388854fce 100644 --- a/projects/common/src/main/java/dan200/computercraft/impl/ApiFactories.java +++ b/projects/common/src/main/java/dan200/computercraft/impl/ApiFactories.java @@ -11,19 +11,24 @@ import java.util.LinkedHashSet; import java.util.Objects; +/** + * The global factory for {@link ILuaAPIFactory}s. + * + * @see dan200.computercraft.core.ComputerContext.Builder#apiFactories(Collection) + * @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) + */ public final class ApiFactories { private ApiFactories() { } private static final Collection factories = new LinkedHashSet<>(); - private static final Collection factoriesView = Collections.unmodifiableCollection(factories); - public static synchronized void register(ILuaAPIFactory factory) { + static synchronized void register(ILuaAPIFactory factory) { Objects.requireNonNull(factory, "provider cannot be null"); factories.add(factory); } public static Collection getAll() { - return factoriesView; + return Collections.unmodifiableCollection(factories); } } diff --git a/projects/common/src/main/java/dan200/computercraft/impl/GenericSources.java b/projects/common/src/main/java/dan200/computercraft/impl/GenericSources.java new file mode 100644 index 000000000..0ba250c9c --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/impl/GenericSources.java @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.impl; + +import dan200.computercraft.api.lua.GenericSource; +import dan200.computercraft.core.asm.GenericMethod; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Objects; + +/** + * The global registry for {@link GenericSource}s. + * + * @see dan200.computercraft.core.ComputerContext.Builder#genericMethods(Collection) + * @see dan200.computercraft.api.ComputerCraftAPI#registerGenericSource(GenericSource) + */ +public final class GenericSources { + private GenericSources() { + } + + private static final Collection sources = new LinkedHashSet<>(); + + static synchronized void register(GenericSource source) { + Objects.requireNonNull(source, "provider cannot be null"); + sources.add(source); + } + + public static Collection getAllMethods() { + return sources.stream().flatMap(GenericMethod::getMethods).toList(); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerContext.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerContext.java index 108c95483..64480353b 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerContext.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerContext.java @@ -18,6 +18,7 @@ import dan200.computercraft.core.methods.PeripheralMethod; import dan200.computercraft.impl.AbstractComputerCraftAPI; import dan200.computercraft.impl.ApiFactories; +import dan200.computercraft.impl.GenericSources; import dan200.computercraft.shared.CommonHooks; import dan200.computercraft.shared.computer.metrics.GlobalMetrics; import dan200.computercraft.shared.config.ConfigSpec; @@ -74,6 +75,7 @@ private ServerContext(MinecraftServer server) { .mainThreadScheduler(mainThread) .luaFactory(luaMachine) .apiFactories(ApiFactories.getAll()) + .genericMethods(GenericSources.getAllMethods()) .build(); idAssigner = new IDAssigner(storageDir.resolve("ids.json")); } diff --git a/projects/core/src/main/java/dan200/computercraft/core/ComputerContext.java b/projects/core/src/main/java/dan200/computercraft/core/ComputerContext.java index 75a6cac6d..b7fefae86 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/ComputerContext.java +++ b/projects/core/src/main/java/dan200/computercraft/core/ComputerContext.java @@ -5,6 +5,7 @@ package dan200.computercraft.core; import dan200.computercraft.api.lua.ILuaAPIFactory; +import dan200.computercraft.core.asm.GenericMethod; import dan200.computercraft.core.asm.LuaMethodSupplier; import dan200.computercraft.core.asm.PeripheralMethodSupplier; import dan200.computercraft.core.computer.ComputerThread; @@ -165,6 +166,7 @@ public static class Builder { private @Nullable MainThreadScheduler mainThreadScheduler; private @Nullable ILuaMachine.Factory luaFactory; private @Nullable List apiFactories; + private @Nullable List genericMethods; Builder(GlobalEnvironment environment) { this.environment = environment; @@ -225,6 +227,21 @@ public Builder apiFactories(Collection apis) { return this; } + /** + * Set the set of {@link GenericMethod}s used by the {@linkplain MethodSupplier method suppliers}. + * + * @param genericMethods A list of API factories. + * @return {@code this}, for chaining + * @see ComputerContext#luaMethods() + * @see ComputerContext#peripheralMethods() + */ + public Builder genericMethods(Collection genericMethods) { + Objects.requireNonNull(genericMethods); + if (this.genericMethods != null) throw new IllegalStateException("Main-thread scheduler already specified"); + this.genericMethods = List.copyOf(genericMethods); + return this; + } + /** * Create a new {@link ComputerContext}. * @@ -237,8 +254,8 @@ public ComputerContext build() { mainThreadScheduler == null ? new NoWorkMainThreadScheduler() : mainThreadScheduler, luaFactory == null ? CobaltLuaMachine::new : luaFactory, apiFactories == null ? List.of() : apiFactories, - LuaMethodSupplier.create(), - PeripheralMethodSupplier.create() + LuaMethodSupplier.create(genericMethods == null ? List.of() : genericMethods), + PeripheralMethodSupplier.create(genericMethods == null ? List.of() : genericMethods) ); } } diff --git a/projects/core/src/main/java/dan200/computercraft/core/asm/Generator.java b/projects/core/src/main/java/dan200/computercraft/core/asm/Generator.java index 4b79e0060..7a973f5b3 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/asm/Generator.java +++ b/projects/core/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -10,8 +10,6 @@ import com.google.common.primitives.Primitives; import com.google.common.reflect.TypeToken; import dan200.computercraft.api.lua.*; -import dan200.computercraft.api.peripheral.PeripheralType; -import dan200.computercraft.core.methods.NamedMethod; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; @@ -21,11 +19,8 @@ import javax.annotation.Nullable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; @@ -55,10 +50,6 @@ final class Generator { private final Function wrap; - private final LoadingCache, List>> classCache = CacheBuilder - .newBuilder() - .build(CacheLoader.from(catching(this::build, Collections.emptyList()))); - private final LoadingCache> methodCache = CacheBuilder .newBuilder() .build(CacheLoader.from(catching(this::build, Optional.empty()))); @@ -75,58 +66,8 @@ final class Generator { this.methodDesc = methodDesc.toString(); } - public List> getMethods(Class klass) { - try { - return classCache.get(klass); - } catch (ExecutionException e) { - LOG.error("Error getting methods for {}.", klass.getName(), e.getCause()); - return Collections.emptyList(); - } - } - - private List> build(Class klass) { - ArrayList> methods = null; - for (var method : klass.getMethods()) { - var annotation = method.getAnnotation(LuaFunction.class); - if (annotation == null) continue; - - if (Modifier.isStatic(method.getModifiers())) { - LOG.warn("LuaFunction method {}.{} should be an instance method.", method.getDeclaringClass(), method.getName()); - continue; - } - - var instance = methodCache.getUnchecked(method).orElse(null); - if (instance == null) continue; - - if (methods == null) methods = new ArrayList<>(); - addMethod(methods, method, annotation, null, instance); - } - - for (var method : GenericMethod.all()) { - if (!method.target.isAssignableFrom(klass)) continue; - - var instance = methodCache.getUnchecked(method.method).orElse(null); - if (instance == null) continue; - - if (methods == null) methods = new ArrayList<>(); - addMethod(methods, method.method, method.annotation, method.peripheralType, instance); - } - - if (methods == null) return Collections.emptyList(); - methods.trimToSize(); - return Collections.unmodifiableList(methods); - } - - private void addMethod(List> methods, Method method, LuaFunction annotation, @Nullable PeripheralType genericType, T instance) { - var names = annotation.value(); - var isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); - if (names.length == 0) { - methods.add(new NamedMethod<>(method.getName(), instance, isSimple, genericType)); - } else { - for (var name : names) { - methods.add(new NamedMethod<>(name, instance, isSimple, genericType)); - } - } + Optional getMethod(Method method) { + return methodCache.getUnchecked(method); } private Optional build(Method method) { @@ -337,7 +278,7 @@ private Boolean loadArg(MethodVisitor mw, Class target, Method method, boolea } @SuppressWarnings("Guava") - private static com.google.common.base.Function catching(Function function, U def) { + static com.google.common.base.Function catching(Function function, U def) { return x -> { try { return function.apply(x); diff --git a/projects/core/src/main/java/dan200/computercraft/core/asm/GenericMethod.java b/projects/core/src/main/java/dan200/computercraft/core/asm/GenericMethod.java index d7a8468bf..1e18b0a0b 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/asm/GenericMethod.java +++ b/projects/core/src/main/java/dan200/computercraft/core/asm/GenericMethod.java @@ -14,16 +14,14 @@ import javax.annotation.Nullable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Objects; import java.util.stream.Stream; /** * A generic method is a method belonging to a {@link GenericSource} with a known target. */ -public class GenericMethod { +public final class GenericMethod { private static final Logger LOG = LoggerFactory.getLogger(GenericMethod.class); final Method method; @@ -31,37 +29,24 @@ public class GenericMethod { final Class target; final @Nullable PeripheralType peripheralType; - private static final List sources = new ArrayList<>(); - private static @Nullable List cache; - - GenericMethod(Method method, LuaFunction annotation, Class target, @Nullable PeripheralType peripheralType) { + private GenericMethod(Method method, LuaFunction annotation, Class target, @Nullable PeripheralType peripheralType) { this.method = method; this.annotation = annotation; this.target = target; this.peripheralType = peripheralType; } + public String name() { + return method.getName(); + } + /** * Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}. * + * @param source The given generic source. * @return All available generic methods. */ - static List all() { - if (cache != null) return cache; - return cache = sources.stream().flatMap(GenericMethod::getMethods).toList(); - } - - public static synchronized void register(GenericSource source) { - Objects.requireNonNull(source, "Source cannot be null"); - - if (cache != null) { - LOG.warn("Registering a generic source {} after cache has been built. This source will be ignored.", cache); - } - - sources.add(source); - } - - private static Stream getMethods(GenericSource source) { + public static Stream getMethods(GenericSource source) { Class klass = source.getClass(); var type = source instanceof GenericPeripheral generic ? generic.getType() : null; diff --git a/projects/core/src/main/java/dan200/computercraft/core/asm/LuaMethodSupplier.java b/projects/core/src/main/java/dan200/computercraft/core/asm/LuaMethodSupplier.java index 626e9a329..11f8e4310 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/asm/LuaMethodSupplier.java +++ b/projects/core/src/main/java/dan200/computercraft/core/asm/LuaMethodSupplier.java @@ -6,16 +6,21 @@ import dan200.computercraft.api.lua.IDynamicLuaObject; import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.core.ComputerContext; import dan200.computercraft.core.methods.LuaMethod; import dan200.computercraft.core.methods.MethodSupplier; -import org.jetbrains.annotations.VisibleForTesting; import java.util.List; import java.util.Objects; +/** + * Provides a {@link MethodSupplier} for {@link LuaMethod}s. + *

+ * This is used by {@link ComputerContext} to construct {@linkplain ComputerContext#peripheralMethods() the context-wide + * method supplier}. It should not be used directly. + */ public final class LuaMethodSupplier { - @VisibleForTesting - static final Generator GENERATOR = new Generator<>(LuaMethod.class, List.of(ILuaContext.class), + private static final Generator GENERATOR = new Generator<>(LuaMethod.class, List.of(ILuaContext.class), m -> (target, context, args) -> context.executeMainThreadTask(() -> ResultHelpers.checkNormalResult(m.apply(target, context, args.escapes()))) ); private static final IntCache DYNAMIC = new IntCache<>( @@ -25,8 +30,8 @@ public final class LuaMethodSupplier { private LuaMethodSupplier() { } - public static MethodSupplier create() { - return new MethodSupplierImpl<>(GENERATOR, DYNAMIC, x -> x instanceof IDynamicLuaObject dynamic + public static MethodSupplier create(List genericMethods) { + return new MethodSupplierImpl<>(genericMethods, GENERATOR, DYNAMIC, x -> x instanceof IDynamicLuaObject dynamic ? Objects.requireNonNull(dynamic.getMethodNames(), "Dynamic methods cannot be null") : null ); diff --git a/projects/core/src/main/java/dan200/computercraft/core/asm/MethodSupplierImpl.java b/projects/core/src/main/java/dan200/computercraft/core/asm/MethodSupplierImpl.java index 1e532d713..44e5775e4 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/asm/MethodSupplierImpl.java +++ b/projects/core/src/main/java/dan200/computercraft/core/asm/MethodSupplierImpl.java @@ -4,17 +4,49 @@ package dan200.computercraft.core.asm; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.peripheral.PeripheralType; import dan200.computercraft.core.methods.MethodSupplier; +import dan200.computercraft.core.methods.NamedMethod; import dan200.computercraft.core.methods.ObjectSource; +import org.jetbrains.annotations.VisibleForTesting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.function.Function; +import static dan200.computercraft.core.asm.Generator.catching; + final class MethodSupplierImpl implements MethodSupplier { + private static final Logger LOG = LoggerFactory.getLogger(MethodSupplierImpl.class); + + private final List genericMethods; private final Generator generator; private final IntCache dynamic; private final Function dynamicMethods; - MethodSupplierImpl(Generator generator, IntCache dynamic, Function dynamicMethods) { + private final LoadingCache, List>> classCache = CacheBuilder + .newBuilder() + .build(CacheLoader.from(catching(this::getMethodsImpl, List.of()))); + + MethodSupplierImpl( + List genericMethods, + Generator generator, + IntCache dynamic, + Function dynamicMethods + ) { + this.genericMethods = genericMethods; this.generator = generator; this.dynamic = dynamic; this.dynamicMethods = dynamicMethods; @@ -22,7 +54,7 @@ final class MethodSupplierImpl implements MethodSupplier { @Override public boolean forEachSelfMethod(Object object, UntargetedConsumer consumer) { - var methods = generator.getMethods(object.getClass()); + var methods = getMethods(object.getClass()); for (var method : methods) consumer.accept(method.name(), method.method(), method); var dynamicMethods = this.dynamicMethods.apply(object); @@ -35,14 +67,14 @@ public boolean forEachSelfMethod(Object object, UntargetedConsumer consumer) @Override public boolean forEachMethod(Object object, TargetedConsumer consumer) { - var methods = generator.getMethods(object.getClass()); + var methods = getMethods(object.getClass()); for (var method : methods) consumer.accept(object, method.name(), method.method(), method); var hasMethods = !methods.isEmpty(); if (object instanceof ObjectSource source) { for (var extra : source.getExtra()) { - var extraMethods = generator.getMethods(extra.getClass()); + var extraMethods = getMethods(extra.getClass()); if (!extraMethods.isEmpty()) hasMethods = true; for (var method : extraMethods) consumer.accept(object, method.name(), method.method(), method); } @@ -58,4 +90,63 @@ public boolean forEachMethod(Object object, TargetedConsumer consumer) { return hasMethods; } + + @VisibleForTesting + List> getMethods(Class klass) { + try { + return classCache.get(klass); + } catch (ExecutionException e) { + LOG.error("Error getting methods for {}.", klass.getName(), e.getCause()); + return List.of(); + } + } + + private List> getMethodsImpl(Class klass) { + ArrayList> methods = null; + + // Find all methods on the current class + for (var method : klass.getMethods()) { + var annotation = method.getAnnotation(LuaFunction.class); + if (annotation == null) continue; + + if (Modifier.isStatic(method.getModifiers())) { + LOG.warn("LuaFunction method {}.{} should be an instance method.", method.getDeclaringClass(), method.getName()); + continue; + } + + var instance = generator.getMethod(method).orElse(null); + if (instance == null) continue; + + if (methods == null) methods = new ArrayList<>(); + addMethod(methods, method, annotation, null, instance); + } + + // Inject generic methods + for (var method : genericMethods) { + if (!method.target.isAssignableFrom(klass)) continue; + + var instance = generator.getMethod(method.method).orElse(null); + if (instance == null) continue; + + if (methods == null) methods = new ArrayList<>(); + addMethod(methods, method.method, method.annotation, method.peripheralType, instance); + } + + if (methods == null) return List.of(); + methods.trimToSize(); + return Collections.unmodifiableList(methods); + } + + private void addMethod(List> methods, Method method, LuaFunction annotation, @Nullable PeripheralType genericType, T instance) { + var names = annotation.value(); + var isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); + if (names.length == 0) { + methods.add(new NamedMethod<>(method.getName(), instance, isSimple, genericType)); + } else { + for (var name : names) { + methods.add(new NamedMethod<>(name, instance, isSimple, genericType)); + } + } + } + } diff --git a/projects/core/src/main/java/dan200/computercraft/core/asm/PeripheralMethodSupplier.java b/projects/core/src/main/java/dan200/computercraft/core/asm/PeripheralMethodSupplier.java index 5010449c9..174b4ef19 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/asm/PeripheralMethodSupplier.java +++ b/projects/core/src/main/java/dan200/computercraft/core/asm/PeripheralMethodSupplier.java @@ -7,12 +7,19 @@ import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IDynamicPeripheral; +import dan200.computercraft.core.ComputerContext; import dan200.computercraft.core.methods.MethodSupplier; import dan200.computercraft.core.methods.PeripheralMethod; import java.util.List; import java.util.Objects; +/** + * Provides a {@link MethodSupplier} for {@link PeripheralMethod}s. + *

+ * This is used by {@link ComputerContext} to construct {@linkplain ComputerContext#peripheralMethods() the context-wide + * method supplier}. It should not be used directly. + */ public class PeripheralMethodSupplier { private static final Generator GENERATOR = new Generator<>(PeripheralMethod.class, List.of(ILuaContext.class, IComputerAccess.class), m -> (target, context, computer, args) -> context.executeMainThreadTask(() -> ResultHelpers.checkNormalResult(m.apply(target, context, computer, args.escapes()))) @@ -21,8 +28,8 @@ public class PeripheralMethodSupplier { method -> (instance, context, computer, args) -> ((IDynamicPeripheral) instance).callMethod(computer, context, method, args) ); - public static MethodSupplier create() { - return new MethodSupplierImpl<>(GENERATOR, DYNAMIC, x -> x instanceof IDynamicPeripheral dynamic + public static MethodSupplier create(List genericMethods) { + return new MethodSupplierImpl<>(genericMethods, GENERATOR, DYNAMIC, x -> x instanceof IDynamicPeripheral dynamic ? Objects.requireNonNull(dynamic.getMethodNames(), "Dynamic methods cannot be null") : null ); diff --git a/projects/core/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java b/projects/core/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java index 6b389a1e8..7c8ebedde 100644 --- a/projects/core/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java +++ b/projects/core/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java @@ -12,10 +12,11 @@ import dan200.computercraft.core.methods.LuaMethod; import dan200.computercraft.core.methods.MethodSupplier; +import java.util.List; import java.util.Map; public class ObjectWrapper implements ILuaContext { - private static final MethodSupplier LUA_METHODS = LuaMethodSupplier.create(); + private static final MethodSupplier LUA_METHODS = LuaMethodSupplier.create(List.of()); private final Object object; private final Map methodMap; diff --git a/projects/core/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java b/projects/core/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java index cc504eb27..9fc6620e5 100644 --- a/projects/core/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java +++ b/projects/core/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -23,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class GeneratorTest { - private static final Generator GENERATOR = LuaMethodSupplier.GENERATOR; + private static final MethodSupplierImpl GENERATOR = (MethodSupplierImpl) LuaMethodSupplier.create(List.of()); @Test public void testBasic() {