From e852cde9e9b5473589bae07931e226f7bd750f46 Mon Sep 17 00:00:00 2001 From: Stan Hebben Date: Fri, 18 Oct 2024 21:37:17 +0200 Subject: [PATCH] Fix compilation of generic classes or interfaces with generic base types --- .../codemodel/compilation/CastedEval.java | 2 +- .../compilation/CastedExpression.java | 14 ++++++- .../codemodel/compilation/CompileErrors.java | 4 ++ .../compilation/MatchedCallArguments.java | 2 +- .../codemodel/type/InvalidTypeID.java | 5 +++ .../zenscript/codemodel/type/TypeID.java | 5 +++ .../compiler/ArrayHelperType.java | 2 +- .../compiler/ArrayInitializerHelper.java | 2 +- .../compiler/JavaExpressionVisitor.java | 4 +- .../compiler/JavaMethodBytecodeCompiler.java | 41 +++++++++++++++---- .../JavaNonPushingExpressionVisitor.java | 33 ++++++++++----- .../compiler/JavaStatementVisitor.java | 7 +++- .../compiler/JavaTypeExpressionVisitor.java | 6 ++- .../definitions/JavaMemberVisitor.java | 2 + .../openzen/zencode/java/ScriptingEngine.java | 12 ++++-- .../java/module/JavaRuntimeMethod.java | 5 +++ .../javashared/JavaBuiltinMethod.java | 5 +++ .../zenscript/javashared/JavaMethod.java | 1 + .../javashared/JavaMethodCompiler.java | 2 + .../javashared/JavaNativeMethod.java | 5 +++ .../javashared/JavaSpecialMethod.java | 5 +++ .../prepare/JavaPrepareDefinitionVisitor.java | 15 ++++--- .../parser/definitions/ParsedClass.java | 6 ++- .../parser/definitions/ParsedInterface.java | 4 +- .../expression/ParsedExpressionBinary.java | 2 +- .../expression/ParsedExpressionFunction.java | 6 ++- .../expression/ParsedExpressionIndex.java | 4 +- .../expression/ParsedExpressionUnary.java | 2 +- .../classes/class_extends_generic_1.zc | 18 ++++++++ .../zencode_tests/joined_tests/collections.zc | 2 - 30 files changed, 173 insertions(+), 50 deletions(-) create mode 100644 ScriptingEngineTester/src/main/resources/zencode_tests/classes/class_extends_generic_1.zc diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedEval.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedEval.java index 296c0f7e9..9a44f4a77 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedEval.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedEval.java @@ -31,7 +31,7 @@ public CastedExpression of(Expression value) { if (value.type.equals(type) || type == BasicTypeID.UNDETERMINED) return new CastedExpression(CastedExpression.Level.EXACT, value); if (value.type.isInvalid()) - return CastedExpression.invalid(value); + return CastedExpression.invalidType(value); ResolvedType resolvedTargetType = compiler.resolve(type); diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedExpression.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedExpression.java index d49e0b213..e20c235fe 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedExpression.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedExpression.java @@ -39,8 +39,12 @@ public static CastedExpression invalid(CodePosition position, CompileError error return new CastedExpression(position, error); } - public static CastedExpression invalid(Expression expression) { - return new CastedExpression(Level.INVALID, expression); + public static CastedExpression invalid(Expression expression, CompileError error) { + return new CastedExpression(Level.INVALID, expression, error); + } + + public static CastedExpression invalidType(Expression expression) { + return new CastedExpression(Level.INVALID, expression, expression.type.asInvalid().error); } public final Level level; @@ -59,6 +63,12 @@ public CastedExpression(CodePosition position, CompileError error) { this.error = error; } + private CastedExpression(Level level, Expression value, CompileError error) { + this.level = level; + this.value = value; + this.error = error; + } + public boolean isFailed() { return level == Level.INVALID; } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CompileErrors.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CompileErrors.java index 340bc0129..69eb677c0 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CompileErrors.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CompileErrors.java @@ -254,6 +254,10 @@ public static CompileError invalidTypeArguments() { return new CompileError(CompileExceptionCode.INVALID_TYPE_ARGUMENTS, "Invalid number of type arguments"); } + public static CompileError invalidType() { + return new CompileError(CompileExceptionCode.INVALID_TYPE, "Invalid type"); + } + public static CompileError noInnerType(TypeID type, String name) { return new CompileError(CompileExceptionCode.NO_SUCH_TYPE, "No such inner type in " + type + ": " + name); } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/MatchedCallArguments.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/MatchedCallArguments.java index 785523d7a..eb78def03 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/MatchedCallArguments.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/MatchedCallArguments.java @@ -105,7 +105,7 @@ public Expression eval(ExpressionBuilder builder, CallEvaluator evaluator) { public CastedExpression cast(ExpressionBuilder builder, CastedEval eval, CallEvaluator evaluator) { if (this.error != null) { - return CastedExpression.invalid(builder.invalid(error)); + return CastedExpression.invalid(builder.invalid(error), error); } else { return eval.of(evaluator.eval(builder, method, arguments)); } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/InvalidTypeID.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/InvalidTypeID.java index b40e8bb8c..8b1150a08 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/InvalidTypeID.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/InvalidTypeID.java @@ -43,6 +43,11 @@ public boolean isInvalid() { return true; } + @Override + public InvalidTypeID asInvalid() { + return this; + } + @Override public ResolvingType resolve() { return MemberSet.create(this).build(); diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/TypeID.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/TypeID.java index de8dddb79..e8ede6c41 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/TypeID.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/type/TypeID.java @@ -2,6 +2,7 @@ import org.openzen.zencode.shared.CodePosition; import org.openzen.zenscript.codemodel.GenericMapper; +import org.openzen.zenscript.codemodel.compilation.CompileErrors; import org.openzen.zenscript.codemodel.compilation.ResolvedType; import org.openzen.zenscript.codemodel.compilation.ResolvingType; import org.openzen.zenscript.codemodel.expression.Expression; @@ -88,6 +89,10 @@ default boolean isInvalid() { return false; } + default InvalidTypeID asInvalid() { + return new InvalidTypeID(CodePosition.UNKNOWN, CompileErrors.invalidType()); + } + default boolean canCastImplicitTo(TypeID other) { return false; } diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayHelperType.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayHelperType.java index c5136358b..04a3a4261 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayHelperType.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayHelperType.java @@ -27,7 +27,7 @@ public ArrayHelperType getWithOneDimensionLess() { public void newArray(JavaWriter javaWriter) { if(elementType instanceof GenericTypeID) { - elementType.accept(javaWriter, new JavaTypeExpressionVisitor(context)); + elementType.accept(javaWriter, new JavaTypeExpressionVisitor(context, false)); javaWriter.swap(); final JavaClass arrayClass = JavaClass.fromInternalName("java/lang/reflect/Array", JavaClass.Kind.CLASS); javaWriter.invokeStatic(JavaNativeMethod.getStatic(arrayClass, "newInstance", "(Ljava/lang/Class;I)Ljava/lang/Object;", 0)); diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayInitializerHelper.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayInitializerHelper.java index 598d7ef27..35d4d9ea9 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayInitializerHelper.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/ArrayInitializerHelper.java @@ -80,7 +80,7 @@ void visitMultiDimArray(JavaWriter javaWriter, int[] sizeLocations, int[] counte final ArrayHelperType elementType = currentArrayType.getWithOneDimensionLess(); if (arrayType.elementType.isGeneric()) { - arrayType.elementType.accept(javaWriter, new JavaTypeExpressionVisitor(context)); + arrayType.elementType.accept(javaWriter, new JavaTypeExpressionVisitor(context, false)); javaWriter.loadInt(currentArraySizeLocation); javaWriter.invokeStatic(ARRAY_NEWINSTANCE); javaWriter.checkCast(context.getInternalName(arrayType)); diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java index edd8a5286..b379312c6 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java @@ -49,7 +49,7 @@ public class JavaExpressionVisitor implements ExpressionVisitor { private final JavaUnboxingTypeVisitor unboxingTypeVisitor; private final JavaUnboxingTypeVisitor optionalUnwrappingTypeVisitor; private final JavaFieldBytecodeCompiler fieldCompiler; - private final JavaMethodBytecodeCompiler methodCompiler; + public final JavaMethodBytecodeCompiler methodCompiler; private final CapturedExpressionVisitor capturedExpressionVisitor; public JavaExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter, JavaMangler javaMangler) { @@ -105,7 +105,7 @@ public Void visitAndAnd(AndAndExpression expression) { public Void visitArray(ArrayExpression expression) { Type type = context.getType(expression.arrayType.elementType); if (expression.arrayType.elementType.isGeneric()) { - expression.arrayType.elementType.accept(javaWriter, new JavaTypeExpressionVisitor(context)); + expression.arrayType.elementType.accept(javaWriter, new JavaTypeExpressionVisitor(context, false)); javaWriter.constant(expression.expressions.length); javaWriter.invokeStatic(ARRAY_NEWINSTANCE); javaWriter.checkCast(context.getInternalName(expression.arrayType)); diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaMethodBytecodeCompiler.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaMethodBytecodeCompiler.java index 6fc5d4557..ab214f69d 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaMethodBytecodeCompiler.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaMethodBytecodeCompiler.java @@ -149,14 +149,32 @@ public Void nativeConstructor(JavaNativeMethod method, TypeID type, CallArgument AtomicInteger typeArguments = new AtomicInteger(0); if (method.compile) { type.asDefinition().ifPresent(definitionType -> { - final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context); + final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context, false); typeArguments.set(definitionType.typeArguments.length); for (TypeID typeParameter : definitionType.typeArguments) { typeParameter.accept(javaWriter, javaTypeExpressionVisitor); } }); } - handleArguments(typeArguments.get(), method, arguments, false); + handleArguments(typeArguments.get(), method, arguments, false, false); + javaWriter.invokeSpecial(method); + return null; + } + + @Override + public Void nativeBaseConstructor(JavaNativeMethod method, TypeID type, CallArguments arguments) { + javaWriter.loadObject(0); + AtomicInteger typeArguments = new AtomicInteger(0); + if (method.compile) { + type.asDefinition().ifPresent(definitionType -> { + final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context, true); + typeArguments.set(definitionType.typeArguments.length); + for (TypeID typeParameter : definitionType.typeArguments) { + typeParameter.accept(javaWriter, javaTypeExpressionVisitor); + } + }); + } + handleArguments(typeArguments.get(), method, arguments, false, false); javaWriter.invokeSpecial(method); return null; } @@ -164,7 +182,7 @@ public Void nativeConstructor(JavaNativeMethod method, TypeID type, CallArgument @Override public Void nativeVirtualMethod(JavaNativeMethod method, TypeID returnType, Expression target, CallArguments arguments) { if (arguments.expansionTypeArguments.length > 0) { - final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context); + final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context, false); for (int i = 0; i < arguments.expansionTypeArguments.length; i++) { arguments.expansionTypeArguments[i].accept(javaWriter, javaTypeExpressionVisitor); } @@ -181,7 +199,7 @@ public Void nativeStaticMethod(JavaNativeMethod method, TypeID returnType, CallA } public void nativeMethod(JavaNativeMethod method, TypeID returnType, CallArguments arguments, boolean asStatic) { - handleArguments(arguments.typeArguments.length, method, arguments, asStatic); + handleArguments(arguments.typeArguments.length, method, arguments, asStatic, false); if (method.kind == JavaNativeMethod.Kind.STATIC) { javaWriter.invokeStatic(method); @@ -209,14 +227,19 @@ public void nativeMethod(JavaNativeMethod method, TypeID returnType, CallArgumen @Override public Void nativeSpecialMethod(JavaNativeMethod method, TypeID returnType, Expression target, CallArguments arguments) { target.accept(expressionVisitor); - handleArguments(arguments.typeArguments.length, method, arguments, false); + handleArguments(arguments.typeArguments.length, method, arguments, false, false); javaWriter.invokeSpecial(method); return null; } - private void handleArguments(int typeArguments, JavaNativeMethod method, CallArguments arguments, boolean asStatic) { + private void handleArguments( + int typeArguments, + JavaNativeMethod method, + CallArguments arguments, + boolean asStatic, + boolean insideConstructor) { if (method.compile) { - handleTypeArguments(method, arguments); + handleTypeArguments(method, arguments, insideConstructor); } // This happens e.g. for Strings where compareTo is a static method in zencode but a virtual one in Java @@ -236,8 +259,8 @@ private void handleArguments(int typeArguments, JavaNativeMethod method, CallArg } } - private void handleTypeArguments(JavaNativeMethod method, CallArguments arguments) { - final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context); + private void handleTypeArguments(JavaNativeMethod method, CallArguments arguments, boolean insideConstructor) { + final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context, insideConstructor); if (arguments.typeArguments.length != method.typeParameterArguments.length) throw new IllegalArgumentException("Number of type parameters doesn't match"); diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java index f40b25b49..35c3ed358 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java @@ -14,6 +14,7 @@ import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javabytecode.compiler.JavaModificationExpressionVisitor.PushOption; import org.openzen.zenscript.javashared.JavaCompiledModule; +import org.openzen.zenscript.javashared.JavaNativeMethod; import org.openzen.zenscript.javashared.JavaParameterInfo; import org.openzen.zenscript.javashared.expressions.JavaFunctionInterfaceCastExpression; @@ -27,14 +28,22 @@ public class JavaNonPushingExpressionVisitor implements ExpressionVisitor private final JavaExpressionVisitor original; private final JavaFieldBytecodeCompiler fieldCompiler; private final JavaMangler mangler; - - public JavaNonPushingExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter, JavaMangler mangler, JavaExpressionVisitor original) { + private final JavaMethodBytecodeCompiler methodCompiler; + + public JavaNonPushingExpressionVisitor( + JavaBytecodeContext context, + JavaCompiledModule module, + JavaWriter javaWriter, + JavaMangler mangler, + JavaExpressionVisitor original + ) { this.context = context; this.module = module; this.javaWriter = javaWriter; this.original = original; this.mangler = mangler; fieldCompiler = new JavaFieldBytecodeCompiler(javaWriter, original, false); + this.methodCompiler = original.methodCompiler; } @Override @@ -198,27 +207,29 @@ public Void visitConstructorThisCall(ConstructorThisCallExpression expression) { javaWriter.loadInt(2); } + context.getJavaMethod(expression.constructor).compileBaseConstructor( + methodCompiler, + expression.constructor.getTarget(), + expression.arguments); + + /*methodCompiler.handleArguments(0, expression.constructor.getHeader(), expression.arguments, false); for (Expression argument : expression.arguments.arguments) { argument.accept(original); } String internalName = context.getInternalName(expression.objectType); javaWriter.invokeSpecial(internalName, "", javaWriter.forDefinition.isEnum() ? context.getEnumConstructorDescriptor(expression.constructor.getHeader()) - : context.getMethodDescriptor(expression.constructor.getHeader().withReturnType(BasicTypeID.VOID))); + : context.getMethodDescriptor(expression.constructor.getHeader().withReturnType(BasicTypeID.VOID)));*/ return null; } @Override public Void visitConstructorSuperCall(ConstructorSuperCallExpression expression) { javaWriter.loadObject(0); - for (Expression argument : expression.arguments.arguments) { - argument.accept(original); - } - //No super calls in enums possible, and that's already handled in the enum constructor itself. - javaWriter.invokeSpecial( - context.getInternalName(expression.constructor.getTarget()), - "", - context.getMethodDescriptor(expression.constructor.getHeader().withReturnType(BasicTypeID.VOID))); + context.getJavaMethod(expression.constructor).compileBaseConstructor( + methodCompiler, + expression.constructor.getTarget(), + expression.arguments); CompilerUtils.writeDefaultFieldInitializers(context, javaWriter, javaWriter.forDefinition, mangler, false); return null; diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java index d4f8fb1a9..7980fbec5 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java @@ -34,7 +34,12 @@ public JavaStatementVisitor(JavaBytecodeContext context, JavaExpressionVisitor e this.javaWriter = expressionVisitor.getJavaWriter(); this.context = context; this.expressionVisitor = expressionVisitor; - this.nonPushingExpressionVisitor = new JavaNonPushingExpressionVisitor(expressionVisitor.context, expressionVisitor.module, expressionVisitor.javaWriter, javaMangler, expressionVisitor); + this.nonPushingExpressionVisitor = new JavaNonPushingExpressionVisitor( + expressionVisitor.context, + expressionVisitor.module, + expressionVisitor.javaWriter, + javaMangler, + expressionVisitor); } @Override diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaTypeExpressionVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaTypeExpressionVisitor.java index da9fd7395..580ee4a8a 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaTypeExpressionVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaTypeExpressionVisitor.java @@ -15,9 +15,11 @@ */ public class JavaTypeExpressionVisitor implements TypeVisitorWithContext { private final JavaBytecodeContext context; + private final boolean insideConstructor; - public JavaTypeExpressionVisitor(JavaBytecodeContext context) { + public JavaTypeExpressionVisitor(JavaBytecodeContext context, boolean insideConstructor) { this.context = context; + this.insideConstructor = insideConstructor; } @Override @@ -98,7 +100,7 @@ public Void visitDefinition(JavaWriter writer, DefinitionTypeID definition) { @Override public Void visitGeneric(JavaWriter writer, GenericTypeID generic) { JavaTypeParameterInfo info = context.target.getTypeParameterInfo(generic.parameter); - if (info.field != null) { + if (info.field != null && !insideConstructor) { writer.loadObject(0); // this writer.getField(info.field); } else { diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java index 2268474fe..f04586e22 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java @@ -94,6 +94,8 @@ public Void visitConstructor(ConstructorMember member) { constructorWriter.nameParameter(0, "index"); } + // TODO: these must be initialized after calling the super constructor (it now ends up before it) + // this seems to work fine, but it might break for (TypeParameter typeParameter : definition.typeParameters) { constructorWriter.nameParameter(0, "typeof" + typeParameter.name); constructorWriter.nameVariable( diff --git a/JavaIntegration/src/main/java/org/openzen/zencode/java/ScriptingEngine.java b/JavaIntegration/src/main/java/org/openzen/zencode/java/ScriptingEngine.java index 57031e1eb..853cceed4 100644 --- a/JavaIntegration/src/main/java/org/openzen/zencode/java/ScriptingEngine.java +++ b/JavaIntegration/src/main/java/org/openzen/zencode/java/ScriptingEngine.java @@ -78,15 +78,21 @@ public ScriptingEngine(ScriptingEngineLogger logger, Function T compileConstructor(JavaMethodCompiler compiler, TypeID type, Cal return compiler.nativeConstructor(method, type, arguments); } + @Override + public T compileBaseConstructor(JavaMethodCompiler compiler, TypeID type, CallArguments arguments) { + return compiler.nativeBaseConstructor(method, type, arguments); + } + @Override public T compileVirtual(JavaMethodCompiler compiler, TypeID returnType, Expression target, CallArguments arguments) { return compiler.nativeVirtualMethod(method, returnType, target, arguments); diff --git a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaBuiltinMethod.java b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaBuiltinMethod.java index cce98e618..0c78b12c2 100644 --- a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaBuiltinMethod.java +++ b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaBuiltinMethod.java @@ -18,6 +18,11 @@ public T compileConstructor(JavaMethodCompiler compiler, TypeID type, Cal return compiler.builtinConstructor(method, type, arguments); } + @Override + public T compileBaseConstructor(JavaMethodCompiler compiler, TypeID type, CallArguments arguments) { + throw new UnsupportedOperationException("Not supported for builtin methods"); + } + @Override public T compileVirtual(JavaMethodCompiler compiler, TypeID returnType, Expression target, CallArguments arguments) { return compiler.builtinVirtualMethod(method, target, arguments); diff --git a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethod.java b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethod.java index e09ccc5e2..5f68a6fc1 100644 --- a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethod.java +++ b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethod.java @@ -7,6 +7,7 @@ public interface JavaMethod { T compileConstructor(JavaMethodCompiler compiler, TypeID type, CallArguments arguments); + T compileBaseConstructor(JavaMethodCompiler compiler, TypeID type, CallArguments arguments); T compileVirtual(JavaMethodCompiler compiler, TypeID returnType, Expression target, CallArguments arguments); T compileVirtualWithTargetOnTopOfStack(JavaMethodCompiler compiler, TypeID returnType, CallArguments arguments); T compileStatic(JavaMethodCompiler compiler, TypeID returnType, CallArguments arguments); diff --git a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethodCompiler.java b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethodCompiler.java index 7948028bc..0f681bb63 100644 --- a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethodCompiler.java +++ b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaMethodCompiler.java @@ -8,6 +8,8 @@ public interface JavaMethodCompiler { T nativeConstructor(JavaNativeMethod method, TypeID type, CallArguments arguments); + T nativeBaseConstructor(JavaNativeMethod method, TypeID type, CallArguments arguments); + T nativeVirtualMethod(JavaNativeMethod method, TypeID returnType, Expression target, CallArguments arguments); T nativeStaticMethod(JavaNativeMethod method, TypeID returnType, CallArguments arguments); diff --git a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaNativeMethod.java b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaNativeMethod.java index 8a2b65583..92eb03979 100644 --- a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaNativeMethod.java +++ b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaNativeMethod.java @@ -132,6 +132,11 @@ public T compileConstructor(JavaMethodCompiler compiler, TypeID type, Cal return compiler.nativeConstructor(this, type, arguments); } + @Override + public T compileBaseConstructor(JavaMethodCompiler compiler, TypeID type, CallArguments arguments) { + return compiler.nativeBaseConstructor(this, type, arguments); + } + @Override public T compileVirtual(JavaMethodCompiler compiler, TypeID returnType, Expression target, CallArguments arguments) { return compiler.nativeVirtualMethod(this, returnType, target, arguments); diff --git a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaSpecialMethod.java b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaSpecialMethod.java index 9884ebbc7..c4605d18f 100644 --- a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaSpecialMethod.java +++ b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaSpecialMethod.java @@ -24,6 +24,11 @@ public T compileConstructor(JavaMethodCompiler compiler, TypeID type, Cal return compiler.specialConstructor(this, type, arguments); } + @Override + public T compileBaseConstructor(JavaMethodCompiler compiler, TypeID type, CallArguments arguments) { + throw new UnsupportedOperationException("Not supported for special methods"); + } + @Override public T compileVirtual(JavaMethodCompiler compiler, TypeID returnType, Expression target, CallArguments arguments) { return compiler.specialVirtualMethod(this, target, arguments); diff --git a/JavaShared/src/main/java/org/openzen/zenscript/javashared/prepare/JavaPrepareDefinitionVisitor.java b/JavaShared/src/main/java/org/openzen/zenscript/javashared/prepare/JavaPrepareDefinitionVisitor.java index 98d4d91c4..bbcfe6a56 100644 --- a/JavaShared/src/main/java/org/openzen/zenscript/javashared/prepare/JavaPrepareDefinitionVisitor.java +++ b/JavaShared/src/main/java/org/openzen/zenscript/javashared/prepare/JavaPrepareDefinitionVisitor.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; /** * @author Hoofdgebruiker @@ -299,8 +300,9 @@ public JavaClass visitInterface(InterfaceDefinition definition) { if (isPrepared(definition)) return module.getClass(definition).compiled; - for (TypeID baseType : definition.baseInterfaces) - prepare(baseType); + for (TypeID baseType : definition.baseInterfaces) { + getTypeInOwnModule(baseType).ifPresent(this::prepare); + } return visitClassCompiled(definition, true, JavaClass.Kind.INTERFACE); } @@ -373,9 +375,7 @@ public JavaClass visitVariant(VariantDefinition variant) { private JavaClass visitClassCompiled(HighLevelDefinition definition, boolean startsEmpty, JavaClass.Kind kind) { if (definition.getSuperType() != null) { // don't perform this step on definitions from other modules - it should already have been performed there - definition.getSuperType().asDefinition() - .filter(superDefinition -> module.module.module.equals(superDefinition.definition.getModule())) - .ifPresent(this::prepare); + getTypeInOwnModule(definition.getSuperType()).ifPresent(this::prepare); } NativeTag nativeTag = definition.getTag(NativeTag.class); @@ -426,4 +426,9 @@ private JavaClass visitClassCompiled(HighLevelDefinition definition, boolean sta return cls; } + + private Optional getTypeInOwnModule(TypeID type) { + return type.asDefinition() + .filter(superDefinition -> module.module.module.equals(superDefinition.definition.getModule())); + } } diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedClass.java b/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedClass.java index 4135f9130..21292268c 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedClass.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedClass.java @@ -83,8 +83,10 @@ public Compiling(DefinitionCompiler compiler, ClassDefinition compiled, boolean @Override public void linkTypes() { ParsedTypeParameter.compile(compiler.types(), compiled.typeParameters, parameters); - if (superclass != null) - compiled.setSuperType(superclass.compile(compiler.types())); + if (superclass != null) { + TypeBuilder typesWithGenericParameters = compiler.types().withGeneric(compiled.typeParameters); + compiled.setSuperType(superclass.compile(typesWithGenericParameters)); + } super.linkTypes(); } diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedInterface.java b/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedInterface.java index 6b4e42c4f..e0e1836db 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedInterface.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/definitions/ParsedInterface.java @@ -6,6 +6,7 @@ import org.openzen.zenscript.codemodel.compilation.CompilingDefinition; import org.openzen.zenscript.codemodel.compilation.CompilingExpansion; import org.openzen.zenscript.codemodel.compilation.DefinitionCompiler; +import org.openzen.zenscript.codemodel.compilation.TypeBuilder; import org.openzen.zenscript.codemodel.context.CompilingPackage; import org.openzen.zenscript.codemodel.definition.InterfaceDefinition; import org.openzen.zenscript.codemodel.identifiers.TypeSymbol; @@ -97,8 +98,9 @@ public Compiling(DefinitionCompiler compiler, InterfaceDefinition compiled, bool @Override public void linkTypes() { ParsedTypeParameter.compile(compiler.types(), compiled.typeParameters, typeParameters); + TypeBuilder typesWithGenericParameters = compiler.types().withGeneric(compiled.typeParameters); for (IParsedType type : superInterfaces) - compiled.baseInterfaces.add(type.compile(compiler.types())); + compiled.baseInterfaces.add(type.compile(typesWithGenericParameters)); super.linkTypes(); } diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionBinary.java b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionBinary.java index a10859492..513906f58 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionBinary.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionBinary.java @@ -58,7 +58,7 @@ public Expression eval() { public CastedExpression cast(CastedEval cast) { Expression leftValue = this.left.eval(); if (leftValue.type.isInvalid()) - return CastedExpression.invalid(leftValue); + return CastedExpression.invalidType(leftValue); ResolvedType resolved = compiler.resolve(leftValue.type); return resolved.findOperator(operator) diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionFunction.java b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionFunction.java index 3c1668769..b309a48ee 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionFunction.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionFunction.java @@ -1,5 +1,6 @@ package org.openzen.zenscript.parser.expression; +import org.openzen.zencode.shared.CompileError; import org.openzen.zenscript.codemodel.compilation.expression.AbstractCompilingExpression; import org.openzen.zencode.shared.CodePosition; import org.openzen.zenscript.codemodel.FunctionHeader; @@ -67,8 +68,9 @@ public CastedExpression cast(CastedEval cast) { header = header.forTypeParameterInference(); }*/ - if(header.hasInvalidTypes()) { - return CastedExpression.invalid(compiler.at(position).invalid(CompileErrors.invalidLambdaHeader(header))); + if (header.hasInvalidTypes()) { + CompileError error = CompileErrors.invalidLambdaHeader(header); + return CastedExpression.invalid(compiler.at(position).invalid(error), error); } LambdaClosure closure = new LambdaClosure(); diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionIndex.java b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionIndex.java index 6bde16311..8dc400183 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionIndex.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionIndex.java @@ -62,7 +62,7 @@ public Expression eval() { public CastedExpression cast(CastedEval cast) { Expression value = this.value.eval(); if (value.type.isInvalid()) - return CastedExpression.invalid(value); + return CastedExpression.invalidType(value); ResolvedType resolved = compiler.resolve(value.type); return resolved.findOperator(OperatorType.INDEXGET) @@ -116,7 +116,7 @@ public Expression eval() { public CastedExpression cast(CastedEval cast) { Expression instance = this.instance.eval(); if (instance.type.isInvalid()) - return CastedExpression.invalid(instance); + return CastedExpression.invalidType(instance); return compiler.resolve(instance.type).findOperator(OperatorType.INDEXSET) .map(operator -> operator.cast(compiler, position, cast, instance, TypeID.NONE, arguments)) diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionUnary.java b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionUnary.java index a41d5e4ae..ac1d20350 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionUnary.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionUnary.java @@ -53,7 +53,7 @@ public Expression eval() { public CastedExpression cast(CastedEval cast) { Expression value = this.value.eval(); if (value.type.isInvalid()) - return CastedExpression.invalid(value); + return CastedExpression.invalidType(value); ResolvedType resolvedType = compiler.resolve(value.type); return resolvedType.findOperator(operator) diff --git a/ScriptingEngineTester/src/main/resources/zencode_tests/classes/class_extends_generic_1.zc b/ScriptingEngineTester/src/main/resources/zencode_tests/classes/class_extends_generic_1.zc new file mode 100644 index 000000000..49710437a --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode_tests/classes/class_extends_generic_1.zc @@ -0,0 +1,18 @@ +#output: Hello World + +virtual class BaseClass { + val value as T; + + this(value: T) { + this.value = value; + } +} + +class Subclass : BaseClass { + this(value: T) { + super(value); + } +} + +val instance = new Subclass("Hello World"); +println(instance.value); diff --git a/ScriptingEngineTester/src/main/resources/zencode_tests/joined_tests/collections.zc b/ScriptingEngineTester/src/main/resources/zencode_tests/joined_tests/collections.zc index 9dd5d43f9..ea08848eb 100644 --- a/ScriptingEngineTester/src/main/resources/zencode_tests/joined_tests/collections.zc +++ b/ScriptingEngineTester/src/main/resources/zencode_tests/joined_tests/collections.zc @@ -1,5 +1,3 @@ -#disabled: Blocked because collections currently don't depend on stdlib -#disabled: Blocked because collections cannot expand the exception type from stdlib (see stdlib/exception_subtype_0.zc) #dependency: stdlib #dependency: collections #output: 3