diff --git a/DMCompiler/DM/Builders/DMProcBuilder.cs b/DMCompiler/DM/Builders/DMProcBuilder.cs
index f8e3ac2e18..3db97c0294 100644
--- a/DMCompiler/DM/Builders/DMProcBuilder.cs
+++ b/DMCompiler/DM/Builders/DMProcBuilder.cs
@@ -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();
-
+ ///
+ /// Returns true if the expression has DMASTCallableSelf as the leftmost innermost expression.
+ ///
+ ///
+ ///
+ 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();
}
@@ -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();
@@ -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();
@@ -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);
@@ -522,6 +536,8 @@ public void ProcessStatementIf(DMASTProcStatementIf statement) {
proc.EndScope();
proc.AddLabel(endLabel);
}
+ if (isTemporary)
+ CurrentReturnType = prevReturnType;
}
public void ProcessStatementFor(DMASTProcStatementFor statementFor) {
@@ -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();
diff --git a/DMCompiler/DM/Expressions/Binary.cs b/DMCompiler/DM/Expressions/Binary.cs
index 78a5f92504..c519baf187 100644
--- a/DMCompiler/DM/Expressions/Binary.cs
+++ b/DMCompiler/DM/Expressions/Binary.cs
@@ -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;
diff --git a/DMCompiler/DM/Expressions/Unary.cs b/DMCompiler/DM/Expressions/Unary.cs
index 889e23a25c..4e6a0704ee 100644
--- a/DMCompiler/DM/Expressions/Unary.cs
+++ b/DMCompiler/DM/Expressions/Unary.cs
@@ -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