Skip to content

Commit

Permalink
- Fix default constructors in classes + supported them for subclasses
Browse files Browse the repository at this point in the history
- Implemented super calls
  • Loading branch information
stanhebben committed Mar 8, 2024
1 parent 768f1f8 commit f325e2f
Show file tree
Hide file tree
Showing 34 changed files with 321 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public int getNumberOfGenericParameters() {
return typeParameters == null ? 0 : typeParameters.length;
}

public void addDefaultMembers() {}

public void setOuterDefinition(HighLevelDefinition outerDefinition) {
this.outerDefinition = outerDefinition;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ public SemanticModule normalize() {
expansions.stream()
).forEach(annotationProcessor::process);


return new SemanticModule(
module,
dependencies,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ public static CompileError notStaticCallableMethod(MethodID id) {
return new CompileError(CompileExceptionCode.CANNOT_CALL, "Cannot call this method statically: " + id + "(" + id.getKind() + ")");
}

public static CompileError notSuperCallableMethod(MethodID id) {
return new CompileError(CompileExceptionCode.CANNOT_CALL, "Cannot call this method on super: " + id + "(" + id.getKind() + ")");
}

public static CompileError constructorForwardOutsideConstructor() {
return new CompileError(CompileExceptionCode.CONSTRUCTOR_FORWARD_OUTSIDE_CONSTRUCTOR, "Can only forward constructors inside constructors");
}
Expand Down Expand Up @@ -497,7 +501,7 @@ public static CompileError superclassNotVirtual(TypeID type) {
}

public static CompileError typeNotDetermined(String display) {
return new CompileError(CompileExceptionCode.INVALID_TYPE, display + " could not be inferred");
return new CompileError(CompileExceptionCode.TYPE_NOT_INFERRED, display + " could not be inferred");
}

public static CompileError invalidArrayDimension(int dimension) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public interface ExpressionBuilder {

Expression callVirtual(MethodInstance method, Expression target, CallArguments arguments);

Expression callSuper(MethodInstance method, Expression target, CallArguments arguments);

Expression coalesce(Expression left, Expression right);

Expression constant(boolean value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.stream.Stream;

public final class InstanceCallable {
private final List<InstanceCallableMethod> overloads;
public final List<InstanceCallableMethod> overloads;

public InstanceCallable(List<InstanceCallableMethod> overloads) {
this.overloads = overloads;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public Optional<CompileError> getError() {
}

@FunctionalInterface
interface CallEvaluator<T> {
public interface CallEvaluator<T> {
Expression eval(ExpressionBuilder builder, T method, CallArguments arguments);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ public Optional<FunctionHeader> getSingleHeader() {
return overloads.size() == 1 ? Optional.of(overloads.get(0).getHeader()) : Optional.empty();
}

public Optional<StaticCallableMethod> getSingleOverload() {
return overloads.size() == 1 ? Optional.of(overloads.get(0)) : Optional.empty();
}

private Expression call(ExpressionBuilder builder, StaticCallableMethod method, CallArguments arguments) {
return method.call(builder, arguments);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.openzen.zenscript.codemodel.compilation.impl;

import org.openzen.zencode.shared.CodePosition;
import org.openzen.zenscript.codemodel.compilation.*;
import org.openzen.zenscript.codemodel.expression.Expression;
import org.openzen.zenscript.codemodel.identifiers.instances.MethodInstance;
import org.openzen.zenscript.codemodel.type.TypeID;

import java.math.MathContext;

public class BoundSuperCallable implements CompilingCallable {
private final ExpressionCompiler compiler;
private final InstanceCallable method;
private final Expression target;
private final TypeID[] typeArguments;

public BoundSuperCallable(ExpressionCompiler compiler, InstanceCallable method, Expression target, TypeID[] typeArguments) {
this.compiler = compiler;
this.method = method;
this.target = target;
this.typeArguments = typeArguments;
}

@Override
public Expression call(CodePosition position, CompilingExpression[] arguments) {
MatchedCallArguments<InstanceCallableMethod> matched = MatchedCallArguments.match(compiler, position, method.overloads, null, typeArguments, arguments);
return matched.eval(compiler.at(position), (builder, method, args) -> builder.callSuper((MethodInstance) method, target, args));
}

@Override
public CastedExpression casted(CodePosition position, CastedEval cast, CompilingExpression[] arguments) {
MatchedCallArguments<InstanceCallableMethod> matched = MatchedCallArguments.match(compiler, position, method.overloads, cast.type, typeArguments, arguments);
return matched.cast(compiler.at(position), cast, (builder, method, args) -> builder.callSuper((MethodInstance) method, target, args));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ public Expression callVirtual(MethodInstance method, Expression target, CallArgu
return new CallExpression(position, target, method, arguments);
}

@Override
public Expression callSuper(MethodInstance method, Expression target, CallArguments arguments) {
return new CallSuperExpression(position, target, method, arguments);
}

@Override
public Expression coalesce(Expression left, Expression right) {
return new CoalesceExpression(position, left, right);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@

import org.openzen.zencode.shared.CodePosition;
import org.openzen.zenscript.codemodel.*;
import org.openzen.zenscript.codemodel.compilation.AnyMethod;
import org.openzen.zenscript.codemodel.expression.*;
import org.openzen.zenscript.codemodel.identifiers.ModuleSymbol;
import org.openzen.zenscript.codemodel.identifiers.TypeSymbol;
import org.openzen.zenscript.codemodel.identifiers.instances.FieldInstance;
import org.openzen.zenscript.codemodel.identifiers.instances.MethodInstance;
import org.openzen.zenscript.codemodel.member.ConstructorMember;
import org.openzen.zenscript.codemodel.member.FieldMember;
import org.openzen.zenscript.codemodel.member.IDefinitionMember;
import org.openzen.zenscript.codemodel.statement.BlockStatement;
import org.openzen.zenscript.codemodel.statement.ExpressionStatement;
import org.openzen.zenscript.codemodel.statement.Statement;
import org.openzen.zenscript.codemodel.type.DefinitionTypeID;
import org.openzen.zenscript.codemodel.type.TypeID;
import org.openzen.zenscript.codemodel.type.builtin.BuiltinMethodSymbol;
import org.openzen.zenscript.codemodel.type.member.MemberSet;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.openzen.zenscript.codemodel.type.BasicTypeID.VOID;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ClassDefinition extends HighLevelDefinition {
public ClassDefinition(CodePosition position, ModuleSymbol module, ZSPackage pkg, String name, Modifiers modifiers) {
this(position, module, pkg, name, modifiers, null);
}

public ClassDefinition(CodePosition position, ModuleSymbol module, ZSPackage pkg, String name, Modifiers modifiers, TypeSymbol outerDefinition) {
super(position, module, pkg, name, modifiers, outerDefinition);
}
Expand All @@ -34,23 +40,73 @@ public <C, R> R accept(C context, DefinitionVisitorWithContext<C, R> visitor) {
}

@Override
protected void resolveAdditional(TypeID type, MemberSet.Builder members, GenericMapper mapper) {
if (members.hasNoConstructor()) {
List<FieldMember> fields = getFields();
boolean noUninitializedFields = true;
if (!fields.isEmpty()) {
FunctionParameter[] parameters = new FunctionParameter[fields.size()];
for (int i = 0; i < parameters.length; i++) {
public void addDefaultMembers() {
super.addDefaultMembers();

boolean hasNoConstructor = members.stream().noneMatch(IDefinitionMember::isConstructor);

Optional<MethodInstance> superConstructor = Optional.ofNullable(getSuperType())
.flatMap(t -> t.resolve().getConstructor().getSingleOverload())
.flatMap(AnyMethod::asMethod);

if (hasNoConstructor) {
TypeID thisType = DefinitionTypeID.createThis(this);

List<FieldMember> fields = getFields().stream().filter(field -> !field.isStatic()).collect(Collectors.toList());
boolean hasSuperParameters = superConstructor.map(c -> c.getHeader().parameters.length > 0).orElse(false);
boolean noUninitializedFields = !hasSuperParameters;
List<Statement> defaultInitializerStatements = new ArrayList<>();
List<Statement> initializerStatements = new ArrayList<>();
List<FunctionParameter> parameters = new ArrayList<>();

superConstructor.ifPresent(constructor -> {
parameters.addAll(Arrays.asList(constructor.getHeader().parameters));

Expression[] superArgumentExpressions = Stream.of(constructor.getHeader().parameters)
.map(parameter -> new GetFunctionParameterExpression(position, parameter))
.toArray(Expression[]::new);
CallArguments superArguments = new CallArguments(superArgumentExpressions);
ExpressionStatement superCall = new ExpressionStatement(position, new ConstructorSuperCallExpression(position, thisType, constructor, superArguments));
defaultInitializerStatements.add(superCall);
initializerStatements.add(superCall);
});

if (hasSuperParameters || !fields.isEmpty()) {
for (int i = 0; i < fields.size(); i++) {
FieldMember field = fields.get(i);
noUninitializedFields &= field.initializer != null;
parameters[i] = new FunctionParameter(field.getType(), field.name, field.initializer, false);
FunctionParameter parameter = new FunctionParameter(field.getType(), field.name, field.initializer, false);
parameters.add(parameter);

initializerStatements.add(new ExpressionStatement(
position,
new SetFieldExpression(
position,
new ThisExpression(position, thisType),
new FieldInstance(field, field.getType()),
new GetFunctionParameterExpression(position, parameter))));
if (field.initializer != null) {
defaultInitializerStatements.add(new ExpressionStatement(
position,
new SetFieldExpression(
position,
new ThisExpression(position, thisType),
new FieldInstance(field, field.getType()),
field.initializer)));
}
}

members.constructor(new MethodInstance(BuiltinMethodSymbol.CLASS_DEFAULT_CONSTRUCTOR, new FunctionHeader(VOID, parameters), type));
ConstructorMember constructor = new ConstructorMember(position, this, Modifiers.PUBLIC, new FunctionHeader(thisType, parameters.toArray(FunctionParameter.NONE)));
BlockStatement block = new BlockStatement(position, initializerStatements.toArray(new Statement[0]));
constructor.setBody(block);
members.add(constructor);
}

if (noUninitializedFields) {
members.constructor(new MethodInstance(BuiltinMethodSymbol.CLASS_DEFAULT_CONSTRUCTOR, new FunctionHeader(type), type));
ConstructorMember constructor = new ConstructorMember(position, this, Modifiers.PUBLIC, new FunctionHeader(thisType));
BlockStatement block = new BlockStatement(position, defaultInitializerStatements.toArray(new Statement[0]));
constructor.setBody(block);
members.add(constructor);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.openzen.zenscript.codemodel.expression;

import org.openzen.zencode.shared.CodePosition;
import org.openzen.zenscript.codemodel.constant.CompileTimeConstant;
import org.openzen.zenscript.codemodel.identifiers.instances.MethodInstance;

import java.util.Optional;

public class CallSuperExpression extends Expression {
public final Expression target;
public final MethodInstance method;
public final CallArguments arguments;

public CallSuperExpression(CodePosition position, Expression target, MethodInstance method, CallArguments arguments) {
super(position, method.getHeader().getReturnType(), multiThrow(position, arguments.arguments));

this.target = target;
this.method = method;
this.arguments = arguments;
}

@Override
public <T> T accept(ExpressionVisitor<T> visitor) {
return visitor.visitCallSuper(this);
}

@Override
public <C, R> R accept(C context, ExpressionVisitorWithContext<C, R> visitor) {
return visitor.visitCallSuper(context, this);
}

@Override
public Expression transform(ExpressionTransformer transformer) {
Expression tTarget = target.transform(transformer);
CallArguments tArguments = arguments.transform(transformer);
return tTarget == target && tArguments == arguments
? this
: new CallSuperExpression(position, tTarget, method, tArguments);
}

@Override
public Optional<CompileTimeConstant> evaluate() {
CompileTimeConstant[] arguments = new CompileTimeConstant[this.arguments.arguments.length];
for (int i = 0; i < arguments.length; i++) {
Optional<CompileTimeConstant> argument = this.arguments.arguments[i].evaluate();
if (argument.isPresent()) {
arguments[i] = argument.get();
} else {
return Optional.empty();
}
}

return method.method.evaluate(this.arguments.typeArguments, arguments);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public interface ExpressionVisitor<T> {

T visitCallStatic(CallStaticExpression expression);

T visitCallSuper(CallSuperExpression expression);

T visitCapturedClosure(CapturedClosureExpression expression);

T visitCapturedLocalVariable(CapturedLocalVariableExpression expression);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public interface ExpressionVisitorWithContext<C, R> {

R visitCallStatic(C context, CallStaticExpression expression);

R visitCallSuper(C context, CallSuperExpression expression);

R visitCapturedClosure(C context, CapturedClosureExpression expression);

R visitCapturedLocalVariable(C context, CapturedLocalVariableExpression expression);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,9 @@ else if (!modifiers.hasAccessModifiers())

return result;
}

@Override
public boolean isConstructor() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ public interface IDefinitionMember {

boolean isAbstract();

default boolean isConstructor() {
return false;
}

FunctionHeader getHeader();
}
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,15 @@ public Void visitCallStatic(CallStaticExpression expression) {
return null;
}

@Override
public Void visitCallSuper(CallSuperExpression expression) {
ModuleSymbol module = expression.method.method.getDefiningType().getModule();
JavaCompiledModule javaCompiledModule = context.getJavaModule(module);
JavaMethod method = javaCompiledModule.getMethodInfo(expression.method.method);
method.compileSpecial(methodCompiler, expression.type, expression.target, expression.arguments);
return null;
}

private void handleReturnValue(TypeID original, TypeID actual) {
if (original.isGeneric()) {
handleGenericReturnValue(actual);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,19 @@ public Void nativeStaticMethod(JavaNativeMethod method, TypeID returnType, CallA
return null;
}

@Override
public Void nativeSpecialMethod(JavaNativeMethod method, TypeID returnType, Expression target, CallArguments arguments) {
target.accept(expressionVisitor);
for (Expression argument : arguments.arguments) {
argument.accept(expressionVisitor);
}
if (method.compile) {
handleTypeArguments(method, arguments);
}
javaWriter.invokeSpecial(method);
return null;
}

private void handleTypeArguments(JavaNativeMethod method, CallArguments arguments) {
final JavaTypeExpressionVisitor javaTypeExpressionVisitor = new JavaTypeExpressionVisitor(context);
if (arguments.typeArguments.length != method.typeParameterArguments.length)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public Void visitCallStatic(CallStaticExpression expression) {
throw new UnsupportedOperationException("Invalid lvalue: static call");
}

@Override
public Void visitCallSuper(CallSuperExpression expression) {
throw new UnsupportedOperationException("Invalid lvalue: super call");
}

@Override
public Void visitCapturedClosure(CapturedClosureExpression expression) {
throw new UnsupportedOperationException("Invalid lvalue: captured closure");
Expand Down
Loading

0 comments on commit f325e2f

Please sign in to comment.