Skip to content

Commit

Permalink
Improve Typemaker return type checking
Browse files Browse the repository at this point in the history
  • Loading branch information
out-of-phaze committed Feb 23, 2025
1 parent 61e1e90 commit a021030
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 50 deletions.
95 changes: 48 additions & 47 deletions DMCompiler/DM/Builders/DMProcBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,25 +164,52 @@ public void ProcessStatement(DMASTProcStatement statement) {
}
}

public void ProcessStatementExpression(DMASTProcStatementExpression statement) {
_exprBuilder.Emit(statement.Expression, out var expr);
var checkedExpression = statement.Expression.GetUnwrapped();

/// <summary>
/// Returns true if the expression has DMASTCallableSelf as the leftmost innermost expression.
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
public void HandleCallableSelfLeft(DMASTExpression expr, ref DMComplexValueType currentReturnType, DMExpression realExpr, out bool isTemporary, bool checkConditions = false) {
isTemporary = false;
var checkedExpression = expr.GetUnwrapped();
switch (checkedExpression) {
case DMASTNot:
DMASTUnary astUnary = (DMASTUnary)checkedExpression;
UnaryOp unaryExpr = (UnaryOp)realExpr;
HandleCallableSelfLeft(astUnary.Value.GetUnwrapped(), ref currentReturnType, unaryExpr.Expr, out var _);
break;
case DMASTEqual astEqual: // a special case: we don't set it but we know lhs = rhs inside this block anyway
if (!checkConditions) break;
if (astEqual.LHS.GetUnwrapped() is DMASTCallableSelf) {
isTemporary = true; // signal to the caller that this should be reset once we leave the current scope
if (realExpr is IsNull) {
// hate this, remove when it uses a bytecode op instead
currentReturnType = DMValueType.Null;
break;
}
Equal equalExpr = (Equal)realExpr;
currentReturnType = equalExpr.RHS.ValType;
}
break;
case DMASTAssign astAssignment:
if (astAssignment.LHS is DMASTCallableSelf)
CurrentReturnType = expr.ValType;
Assignment assignExpr = (Assignment)realExpr;
if (astAssignment.LHS.GetUnwrapped() is DMASTCallableSelf)
currentReturnType = assignExpr.RHS.ValType;
break;
case DMASTAppend:
case DMASTLogicalOrAssign:
DMASTBinary astBinary = (DMASTBinary)checkedExpression;
if (astBinary.LHS is not DMASTCallableSelf)
if (astBinary.LHS.GetUnwrapped() is not DMASTCallableSelf)
break;
if (CurrentReturnType.Type != DMValueType.Null)
if (currentReturnType.Type != DMValueType.Null)
break;
CurrentReturnType = DMComplexValueType.MergeComplexValueTypes(compiler, CurrentReturnType, expr.ValType);
currentReturnType = DMComplexValueType.MergeComplexValueTypes(compiler, currentReturnType, realExpr.ValType);
break;
}
}

public void ProcessStatementExpression(DMASTProcStatementExpression statement) {
_exprBuilder.Emit(statement.Expression, out var expr);
HandleCallableSelfLeft(statement.Expression, ref CurrentReturnType, expr, out var _);
proc.Pop();
}

Expand Down Expand Up @@ -474,24 +501,9 @@ public void ProcessStatementReturn(DMASTProcStatementReturn statement) {

public void ProcessStatementIf(DMASTProcStatementIf statement) {
_exprBuilder.Emit(statement.Condition, out var expr);
var checkedCondition = statement.Condition.GetUnwrapped();

switch (checkedCondition) {
case DMASTAssign astAssignment:
if (astAssignment.LHS is DMASTCallableSelf)
CurrentReturnType = expr.ValType;
break;
case DMASTAppend:
case DMASTLogicalOrAssign:
DMASTBinary astBinary = (DMASTBinary)checkedCondition;
if (astBinary.LHS is not DMASTCallableSelf)
break;
if (CurrentReturnType.Type != DMValueType.Null)
break;
CurrentReturnType = DMComplexValueType.MergeComplexValueTypes(compiler, CurrentReturnType, expr.ValType);
break;
}
var oldReturnType = CurrentReturnType;
var prevReturnType = CurrentReturnType;
HandleCallableSelfLeft(statement.Condition, ref CurrentReturnType, expr, out var isTemporary, checkConditions: true);
var condReturnType = CurrentReturnType;

if (statement.ElseBody == null) {
string endLabel = proc.NewLabelName();
Expand All @@ -500,7 +512,7 @@ public void ProcessStatementIf(DMASTProcStatementIf statement) {
proc.StartScope();
ProcessBlockInner(statement.Body);
proc.EndScope();
CurrentReturnType = oldReturnType;
CurrentReturnType = condReturnType;
proc.AddLabel(endLabel);
} else {
string elseLabel = proc.NewLabelName();
Expand All @@ -511,7 +523,9 @@ public void ProcessStatementIf(DMASTProcStatementIf statement) {
proc.StartScope();
ProcessBlockInner(statement.Body);
proc.EndScope();
CurrentReturnType = oldReturnType;
CurrentReturnType = condReturnType;
if (isTemporary)
CurrentReturnType = prevReturnType;
proc.Jump(endLabel);

proc.AddLabel(elseLabel);
Expand All @@ -522,6 +536,8 @@ public void ProcessStatementIf(DMASTProcStatementIf statement) {
proc.EndScope();
proc.AddLabel(endLabel);
}
if (isTemporary)
CurrentReturnType = prevReturnType;
}

public void ProcessStatementFor(DMASTProcStatementFor statementFor) {
Expand Down Expand Up @@ -876,23 +892,8 @@ public void ProcessStatementSwitch(DMASTProcStatementSwitch statementSwitch) {
DMASTProcBlockInner? defaultCaseBody = null;

_exprBuilder.Emit(statementSwitch.Value, out var expr);
var checkedValue = statementSwitch.Value.GetUnwrapped();

switch (checkedValue) {
case DMASTAssign astAssignment:
if (astAssignment.LHS is DMASTCallableSelf)
CurrentReturnType = expr.ValType;
break;
case DMASTAppend:
case DMASTLogicalOrAssign:
DMASTBinary astBinary = (DMASTBinary)checkedValue;
if (astBinary.LHS is not DMASTCallableSelf)
break;
if (CurrentReturnType.Type != DMValueType.Null)
break;
CurrentReturnType = DMComplexValueType.MergeComplexValueTypes(compiler, CurrentReturnType, expr.ValType);
break;
}
HandleCallableSelfLeft(statementSwitch.Value, ref CurrentReturnType, expr, out var _);
// todo: some sort of return type inference based on cases for conditions switching on .
foreach (DMASTProcStatementSwitch.SwitchCase switchCase in statementSwitch.Cases) {
if (switchCase is DMASTProcStatementSwitch.SwitchCaseValues switchCaseValues) {
string caseLabel = proc.NewLabelName();
Expand Down
4 changes: 2 additions & 2 deletions DMCompiler/DM/Expressions/Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
namespace DMCompiler.DM.Expressions;

internal abstract class BinaryOp(Location location, DMExpression lhs, DMExpression rhs) : DMExpression(location) {
protected DMExpression LHS { get; } = lhs;
protected DMExpression RHS { get; } = rhs;
public DMExpression LHS { get; } = lhs;
public DMExpression RHS { get; } = rhs;

public override DMComplexValueType ValType => LHS.ValType;
public override bool PathIsFuzzy => true;
Expand Down
2 changes: 1 addition & 1 deletion DMCompiler/DM/Expressions/Unary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace DMCompiler.DM.Expressions;

internal abstract class UnaryOp(Location location, DMExpression expr) : DMExpression(location) {
protected DMExpression Expr { get; } = expr;
public DMExpression Expr { get; } = expr;
}

// -x
Expand Down

0 comments on commit a021030

Please sign in to comment.