Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/System.Management.Automation/engine/LanguagePrimitives.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4446,22 +4446,22 @@ internal static ConversionRank GetConversionRank(Type fromType, Type toType)
}

private static readonly Type[] s_numericTypes = new Type[] {
typeof(Int16), typeof(Int32), typeof(Int64),
typeof(UInt16), typeof(UInt32), typeof(UInt64),
typeof(Int16), typeof(Int32), typeof(Int64), typeof(Int128),
typeof(UInt16), typeof(UInt32), typeof(UInt64), typeof(UInt128),
typeof(sbyte), typeof(byte),
typeof(Single), typeof(double), typeof(decimal),
typeof(BigInteger)
};

private static readonly Type[] s_integerTypes = new Type[] {
typeof(Int16), typeof(Int32), typeof(Int64),
typeof(UInt16), typeof(UInt32), typeof(UInt64),
typeof(Int16), typeof(Int32), typeof(Int64), typeof(Int128),
typeof(UInt16), typeof(UInt32), typeof(UInt64), typeof(UInt128),
typeof(sbyte), typeof(byte)
};

// Do not reorder the elements of these arrays, we depend on them being ordered by increasing size.
private static readonly Type[] s_signedIntegerTypes = new Type[] { typeof(sbyte), typeof(Int16), typeof(Int32), typeof(Int64) };
private static readonly Type[] s_unsignedIntegerTypes = new Type[] { typeof(byte), typeof(UInt16), typeof(UInt32), typeof(UInt64) };
private static readonly Type[] s_signedIntegerTypes = new Type[] { typeof(sbyte), typeof(Int16), typeof(Int32), typeof(Int64), typeof(Int128) };
private static readonly Type[] s_unsignedIntegerTypes = new Type[] { typeof(byte), typeof(UInt16), typeof(UInt32), typeof(UInt64), typeof(UInt128) };

private static readonly Type[] s_realTypes = new Type[] { typeof(Single), typeof(double), typeof(decimal) };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2444,6 +2444,16 @@ private DynamicMetaObject BinaryNumericOp(string methodName, DynamicMetaObject t
argType = typeof(ulong);
}
}
else if (target.LimitType.IsInt128Type() || arg.LimitType.IsInt128Type())
{
opImplType = typeof(Int128Ops);
argType = typeof(Int128);
}
else if (target.LimitType.IsUInt128Type() || arg.LimitType.IsUInt128Type())
{
opImplType = typeof(UInt128Ops);
argType = typeof(UInt128);
}
Comment on lines +2447 to +2456
else if (opTypeCode == TypeCode.Decimal)
{
if (methodName.StartsWith("Compare", StringComparison.Ordinal))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,161 @@ internal static object Remainder(ulong lhs, ulong rhs)
internal static object CompareGe(ulong lhs, ulong rhs) { return (lhs >= rhs) ? Boxed.True : Boxed.False; }
}

internal static class Int128Ops
{
internal static object Add(Int128 lhs, Int128 rhs)
{
Comment on lines +397 to +400
System.Numerics.BigInteger biResult = (System.Numerics.BigInteger)lhs + (System.Numerics.BigInteger)rhs;
if (biResult >= Int128.MinValue && biResult <= Int128.MaxValue)
{
return (Int128)biResult;
}

return (double)biResult;
}
Comment on lines +399 to +408

internal static object Sub(Int128 lhs, Int128 rhs)
{
System.Numerics.BigInteger biResult = (System.Numerics.BigInteger)lhs - (System.Numerics.BigInteger)rhs;
if (biResult >= Int128.MinValue && biResult <= Int128.MaxValue)
{
return (Int128)biResult;
}

return (double)biResult;
}

internal static object Multiply(Int128 lhs, Int128 rhs)
{
System.Numerics.BigInteger biResult = (System.Numerics.BigInteger)lhs * (System.Numerics.BigInteger)rhs;
if (biResult >= Int128.MinValue && biResult <= Int128.MaxValue)
{
return (Int128)biResult;
}

return (double)biResult;
}

internal static object Divide(Int128 lhs, Int128 rhs)
{
if (rhs == 0)
{
DivideByZeroException dbze = new DivideByZeroException();
throw new RuntimeException(dbze.Message, dbze);
}

if (lhs == Int128.MinValue && rhs == -1)
{
return (double)lhs / (double)rhs;
}

if ((lhs % rhs) == 0)
{
return lhs / rhs;
}

return (double)lhs / (double)rhs;
}

internal static object Remainder(Int128 lhs, Int128 rhs)
{
if (rhs == 0)
{
DivideByZeroException dbze = new DivideByZeroException();
throw new RuntimeException(dbze.Message, dbze);
}

return lhs % rhs;
}

internal static object CompareEq(Int128 lhs, Int128 rhs) { return (lhs == rhs) ? Boxed.True : Boxed.False; }

internal static object CompareNe(Int128 lhs, Int128 rhs) { return (lhs != rhs) ? Boxed.True : Boxed.False; }

internal static object CompareLt(Int128 lhs, Int128 rhs) { return (lhs < rhs) ? Boxed.True : Boxed.False; }

internal static object CompareLe(Int128 lhs, Int128 rhs) { return (lhs <= rhs) ? Boxed.True : Boxed.False; }

internal static object CompareGt(Int128 lhs, Int128 rhs) { return (lhs > rhs) ? Boxed.True : Boxed.False; }

internal static object CompareGe(Int128 lhs, Int128 rhs) { return (lhs >= rhs) ? Boxed.True : Boxed.False; }
}

internal static class UInt128Ops
{
internal static object Add(UInt128 lhs, UInt128 rhs)
{
System.Numerics.BigInteger biResult = (System.Numerics.BigInteger)lhs + (System.Numerics.BigInteger)rhs;
if (biResult >= UInt128.MinValue && biResult <= UInt128.MaxValue)
{
return (UInt128)biResult;
}

return (double)biResult;
}

internal static object Sub(UInt128 lhs, UInt128 rhs)
{
System.Numerics.BigInteger biResult = (System.Numerics.BigInteger)lhs - (System.Numerics.BigInteger)rhs;
if (biResult >= UInt128.MinValue && biResult <= UInt128.MaxValue)
{
return (UInt128)biResult;
}

return (double)biResult;
}

internal static object Multiply(UInt128 lhs, UInt128 rhs)
{
System.Numerics.BigInteger biResult = (System.Numerics.BigInteger)lhs * (System.Numerics.BigInteger)rhs;
if (biResult >= UInt128.MinValue && biResult <= UInt128.MaxValue)
{
return (UInt128)biResult;
}

return (double)biResult;
}

internal static object Divide(UInt128 lhs, UInt128 rhs)
{
if (rhs == 0)
{
DivideByZeroException dbze = new DivideByZeroException();
throw new RuntimeException(dbze.Message, dbze);
}

if ((lhs % rhs) == 0)
{
return lhs / rhs;
}

return (double)lhs / (double)rhs;
}

internal static object Remainder(UInt128 lhs, UInt128 rhs)
{
if (rhs == 0)
{
DivideByZeroException dbze = new DivideByZeroException();
throw new RuntimeException(dbze.Message, dbze);
}

return lhs % rhs;
}

internal static object CompareEq(UInt128 lhs, UInt128 rhs) { return (lhs == rhs) ? Boxed.True : Boxed.False; }

internal static object CompareNe(UInt128 lhs, UInt128 rhs) { return (lhs != rhs) ? Boxed.True : Boxed.False; }

internal static object CompareLt(UInt128 lhs, UInt128 rhs) { return (lhs < rhs) ? Boxed.True : Boxed.False; }

internal static object CompareLe(UInt128 lhs, UInt128 rhs) { return (lhs <= rhs) ? Boxed.True : Boxed.False; }

internal static object CompareGt(UInt128 lhs, UInt128 rhs) { return (lhs > rhs) ? Boxed.True : Boxed.False; }

internal static object CompareGe(UInt128 lhs, UInt128 rhs) { return (lhs >= rhs) ? Boxed.True : Boxed.False; }
}

internal static class DecimalOps
{
internal static object Add(decimal lhs, decimal rhs)
Expand Down
10 changes: 7 additions & 3 deletions src/System.Management.Automation/utils/ExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ internal static bool HasDefaultCtor(this Type type)

internal static bool IsNumeric(this Type type)
{
return LanguagePrimitives.IsNumeric(LanguagePrimitives.GetTypeCode(type));
return LanguagePrimitives.IsNumeric(LanguagePrimitives.GetTypeCode(type)) || type.IsInt128Type() || type.IsUInt128Type();
}

internal static bool IsNumericOrPrimitive(this Type type)
{
return type.IsPrimitive || LanguagePrimitives.IsNumeric(LanguagePrimitives.GetTypeCode(type));
return type.IsPrimitive || type.IsInt128Type() || type.IsUInt128Type() || LanguagePrimitives.IsNumeric(LanguagePrimitives.GetTypeCode(type));
}

internal static bool IsSafePrimitive(this Type type)
Expand All @@ -105,9 +105,13 @@ internal static bool IsFloating(this Type type)

internal static bool IsInteger(this Type type)
{
return LanguagePrimitives.IsInteger(LanguagePrimitives.GetTypeCode(type));
return LanguagePrimitives.IsInteger(LanguagePrimitives.GetTypeCode(type)) || type.IsInt128Type() || type.IsUInt128Type();
}

internal static bool IsInt128Type(this Type type) => type == typeof(Int128);

internal static bool IsUInt128Type(this Type type) => type == typeof(UInt128);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static TypeCode GetTypeCode(this Type type)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe "Arithmetic overflow promotion" -Tags "CI","RequireAdminOnWindows" {
BeforeAll {
$IsSkipped = (-not $IsCoreCLR) -or ($PSVersionTable.PSVersion -lt [version]'7.4.0')
}

It "Promotes Int64 overflow to Double" -Skip:$IsSkipped {
$result = [Int64]::MaxValue + [Int64]::MaxValue
$result.GetType().Name | Should -Be 'Double'
}

It "Promotes Int128 overflow to Double" -Skip:$IsSkipped {
$result = [Int128]::MaxValue + [Int128]::MaxValue
$result.GetType().Name | Should -Be 'Double'
}

It "Keeps non-overflow Int128 addition in Int128" -Skip:$IsSkipped {
$result = [Int128]1 + [Int128]2
$result.GetType().Name | Should -Be 'Int128'
$result | Should -Be ([Int128]3)
}

It "Promotes UInt128 overflow to Double" -Skip:$IsSkipped {
$result = [UInt128]::MaxValue + [UInt128]::MaxValue
$result.GetType().Name | Should -Be 'Double'
}
}