Skip to content

Commit 3369c2b

Browse files
committed
ToCsharpCode: format block inside expression in {}
It's not valid C# code, but neither was it valid before this change. This makes the code eaiser to read (IMHO), since the block scope is clearly visible.
1 parent 49cfc95 commit 3369c2b

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

Diff for: src/FastExpressionCompiler/FastExpressionCompiler.cs

+17-7
Original file line numberDiff line numberDiff line change
@@ -6760,7 +6760,7 @@ internal static StringBuilder ToCSharpString(this Expression e, StringBuilder sb
67606760
{
67616761
var x = (ConstantExpression)e;
67626762
if (x.Value == null)
6763-
return x.Type != null
6763+
return x.Type != null && x.Type.IsValueType
67646764
? sb.Append("default(").Append(x.Type.ToCode(stripNamespace, printType)).Append(')')
67656765
: sb.Append("null");
67666766

@@ -6948,7 +6948,8 @@ internal static StringBuilder ToCSharpString(this Expression e, StringBuilder sb
69486948
sb.NewLineIdentCs(body, EnclosedIn.LambdaBody, lineIdent + identSpaces, stripNamespace, printType, identSpaces, notRecognizedToCode);
69496949
else
69506950
{
6951-
sb.NewLine(lineIdent, identSpaces).Append('{');
6951+
sb.NewLineIdent(lineIdent).Append('{');
6952+
69526953
// Body handles `;` itself
69536954
if (body is BlockExpression bb)
69546955
bb.BlockToCSharpString(sb, lineIdent + identSpaces, stripNamespace, printType, identSpaces, notRecognizedToCode,
@@ -6959,7 +6960,7 @@ internal static StringBuilder ToCSharpString(this Expression e, StringBuilder sb
69596960
if (isBodyExpression)
69606961
sb.AddSemicolonIfFits();
69616962
}
6962-
sb.NewLine(lineIdent, identSpaces).Append('}');
6963+
sb.NewLineIdent(lineIdent).Append('}');
69636964
}
69646965
return sb.Append(')');
69656966
}
@@ -7011,7 +7012,14 @@ internal static StringBuilder ToCSharpString(this Expression e, StringBuilder sb
70117012
}
70127013
case ExpressionType.Block:
70137014
{
7014-
return BlockToCSharpString((BlockExpression)e, sb, lineIdent, stripNamespace, printType, identSpaces, notRecognizedToCode: notRecognizedToCode);
7015+
if (enclosedIn == EnclosedIn.Block)
7016+
return BlockToCSharpString((BlockExpression)e, sb, lineIdent, stripNamespace, printType, identSpaces, notRecognizedToCode: notRecognizedToCode);
7017+
else
7018+
{
7019+
sb.Append('{');
7020+
BlockToCSharpString((BlockExpression)e, sb, lineIdent + identSpaces, stripNamespace, printType, identSpaces, notRecognizedToCode: notRecognizedToCode);
7021+
return sb.AddSemicolonIfFits().NewLineIdent(lineIdent).Append('}');
7022+
}
70157023
}
70167024
case ExpressionType.Loop:
70177025
{
@@ -7162,11 +7170,12 @@ void PrintPart(Expression part)
71627170
}
71637171
case ExpressionType.Default:
71647172
{
7165-
return e.Type == typeof(void) ? sb // `default(void)` does not make sense in the C#
7166-
: sb.Append("default(").Append(e.Type.ToCode(stripNamespace, printType)).Append(')');
7173+
return e.Type == typeof(void) ? sb : // `default(void)` does not make sense in the C#
7174+
!e.Type.IsValueType && !e.Type.IsGenericParameter ? sb.Append("null") :
7175+
sb.Append("default(").Append(e.Type.ToCode(stripNamespace, printType)).Append(')');
71677176
}
71687177
case ExpressionType.TypeIs:
7169-
case ExpressionType.TypeEqual:
7178+
case ExpressionType.TypeEqual: // TODO: type equal
71707179
{
71717180
var x = (TypeBinaryExpression)e;
71727181
sb.Append('(');
@@ -8118,3 +8127,4 @@ public RequiresUnreferencedCodeAttribute(string message)
81188127
}
81198128
}
81208129
#endif
8130+
}

Diff for: test/FastExpressionCompiler.UnitTests/FastExpressionCompiler.UnitTests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>net472;net7.0</TargetFrameworks>
4+
<TargetFrameworks>net472;net6.0</TargetFrameworks>
45
</PropertyGroup>
56

67
<ItemGroup>

Diff for: test/FastExpressionCompiler.UnitTests/ToCSharpStringTests.cs

+30-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,35 @@ public void Outputs_closed_generic_type_constant_correctly()
3131
Assert.AreEqual(typeof(A<string>), f());
3232
}
3333

34+
[Test]
35+
public void Outputs_default_reference_type_is_just_null()
36+
{
37+
var cs = Default(typeof(string)).ToCSharpString();
38+
Assert.AreEqual("null;", cs);
39+
40+
cs = Default(typeof(System.Collections.Generic.List<string>)).ToCSharpString();
41+
Assert.AreEqual("null;", cs);
42+
}
43+
44+
[Test]
45+
public void Somehow_handles_block_in_expression()
46+
{
47+
// it's probably not possible to output compilable C# for expressions like this, but at least it can be easy to read
48+
var variable = Parameter(typeof(int), "variable");
49+
var cs = Add(Constant(1), Block(new [] { variable },
50+
Assign(variable, Constant(2)),
51+
variable
52+
)).ToCSharpString();
53+
Assert.AreEqual("""
54+
(1 + {
55+
int variable;
56+
variable = 2;
57+
variable;
58+
});
59+
""", cs);
60+
}
61+
62+
3463
class A<X> {}
3564
}
36-
}
65+
}

0 commit comments

Comments
 (0)