Skip to content

Commit 3e464f8

Browse files
committed
Add tests for numeric promotions
1 parent 5e03e71 commit 3e464f8

File tree

5 files changed

+344
-11
lines changed

5 files changed

+344
-11
lines changed

src/Ramstack.ExpressionParser/ExpressionBuilder.Helpers.cs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,28 @@ private static Expression ApplyBinaryExpression(Identifier op, Func<Expression,
186186
return result;
187187
}
188188

189-
//
190-
// 12.4.7 Numeric promotions
191-
// https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#1247-numeric-promotions
192-
//
193189
private static void ApplyBinaryNumericPromotions(Identifier op, ref Expression lhs, ref Expression rhs)
194190
{
191+
//
192+
// 12.4.7.3 Binary numeric promotions
193+
// https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#12473-binary-numeric-promotions
194+
//
195+
// Binary numeric promotion implicitly converts both operands to a common type which,
196+
// in case of the non-relational operators, also becomes the result type of the operation.
197+
// Binary numeric promotion consists of applying the following rules, in the order they appear here:
198+
//
199+
// * If either operand is of type decimal, the other operand is converted to type decimal,
200+
// or a binding-time error occurs if the other operand is of type float or double.
201+
// * Otherwise, if either operand is of type double, the other operand is converted to type double.
202+
// * Otherwise, if either operand is of type float, the other operand is converted to type float.
203+
// * Otherwise, if either operand is of type ulong, the other operand is converted to type ulong,
204+
// or a binding-time error occurs if the other operand is of type sbyte, short, int, or long.
205+
// * Otherwise, if either operand is of type long, the other operand is converted to type long.
206+
// * Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int,
207+
// both operands are converted to type long.
208+
// * Otherwise, if either operand is of type uint, the other operand is converted to type uint.
209+
// * Otherwise, both operands are converted to type int.
210+
195211
var lhsType = lhs.Type;
196212
var rhsType = rhs.Type;
197213

@@ -221,8 +237,10 @@ private static void ApplyBinaryNumericPromotions(Identifier op, ref Expression l
221237

222238
if (conversionType == typeof(decimal))
223239
{
240+
//
224241
// If either operand is of type decimal, the other operand is converted to type decimal,
225242
// or a compile-time error occurs if the other operand is of type float or double.
243+
//
226244
if (lhsType == typeof(double)
227245
|| lhsType == typeof(float)
228246
|| rhsType == typeof(double)
@@ -231,8 +249,10 @@ private static void ApplyBinaryNumericPromotions(Identifier op, ref Expression l
231249
}
232250
else if (conversionType == typeof(ulong))
233251
{
234-
// if either operand is of type ulong, the other operand is converted to type ulong,
252+
//
253+
// If either operand is of type ulong, the other operand is converted to type ulong,
235254
// or a compile-time error occurs if the other operand is of type sbyte, short, int, or long.
255+
//
236256
if (lhsType == typeof(sbyte)
237257
|| lhsType == typeof(short)
238258
|| lhsType == typeof(int)
@@ -245,8 +265,10 @@ private static void ApplyBinaryNumericPromotions(Identifier op, ref Expression l
245265
}
246266
else if (conversionType == typeof(uint))
247267
{
248-
// if either operand is of type uint and the other operand is of type sbyte, short, or int,
268+
//
269+
// If either operand is of type uint and the other operand is of type sbyte, short, or int,
249270
// both operands are converted to type long.
271+
//
250272
if (lhsType == typeof(sbyte)
251273
|| lhsType == typeof(short)
252274
|| lhsType == typeof(int)

src/Ramstack.ExpressionParser/ExpressionParser.Parser.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ private static Parser<Expr> CreateParser()
4242
).Void();
4343

4444
var number_literal =
45-
ConstantNumberParser.NumericLiteral
45+
ConstantNumberParser
46+
.NumericLiteral
4647
.Do(Expr (v) => new Expr.Literal(v));
4748

4849
var string_literal =
@@ -262,8 +263,8 @@ static Expr HijackMemberExpression(Expr result, Expr value)
262263
}
263264

264265
private static Identifier CreateIdentifier(string v) =>
265-
new(v);
266+
new Identifier(v);
266267

267268
private static Identifier CreateIdentifier(char v) =>
268-
new(new string(v, 1));
269+
new Identifier(v.ToString());
269270
}

tests/Rmastack.ExpressionParser.Tests/Data/Errors.txt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,46 @@ Ambiguous match found:\n Char Chars [Int32] (in System.String)
8787

8888
StringSplitOptions.None | StringComparison.Ordinal
8989
Operator '|' cannot be applied to operands of type 'System.StringSplitOptions' and 'System.StringComparison'.
90+
91+
#######################################
92+
###### Binary Numeric Promotions ######
93+
#######################################
94+
95+
#######################################
96+
# If either operand is of type decimal, a binding-time error occurs
97+
# if the other operand is of type float or double.
98+
99+
1.0 + 2.0m
100+
Operator '+' cannot be applied to operands of type 'System.Double' and 'System.Decimal'.
101+
102+
1.0m + 2.0d
103+
Operator '+' cannot be applied to operands of type 'System.Decimal' and 'System.Double'.
104+
105+
1.0f + 2.0m
106+
Operator '+' cannot be applied to operands of type 'System.Single' and 'System.Decimal'.
107+
108+
1.0m + 2.0f
109+
Operator '+' cannot be applied to operands of type 'System.Decimal' and 'System.Single'.
110+
111+
#######################################
112+
# If either operand is of type ulong, a binding-time error occurs
113+
# if the other operand is of type sbyte, short, int, or long.
114+
115+
1ul + 2:sbyte
116+
Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.SByte'.
117+
118+
1ul + 2:short
119+
Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.Int16'.
120+
121+
1ul + 2:int
122+
Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.Int32'.
123+
124+
1ul + 2:long
125+
Operator '+' cannot be applied to operands of type 'System.UInt64' and 'System.Int64'.
126+
127+
#######################################
128+
###### Unary Numeric Promotions ######
129+
#######################################
130+
131+
-1ul
132+
Unary operator '-' cannot be applied to operand of type 'System.UInt64'.

0 commit comments

Comments
 (0)