Skip to content

Commit

Permalink
Improve interop conversion logic between numeric types (#1995)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Nov 2, 2024
1 parent d30fe18 commit 44a0ce0
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 6 deletions.
20 changes: 20 additions & 0 deletions Jint.Tests/Runtime/InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3698,4 +3698,24 @@ private class MyClass
{
public static JsNumber MAX_SAFE_INTEGER = new JsNumber(NumberConstructor.MaxSafeInteger);
}

[Fact]
public void ShouldFindShortOverload()
{
_engine.SetValue("target", new ShortOverloadWithBoolean());
_engine.Evaluate("target.method(42)").AsString().Should().Be("short");
}

private class ShortOverloadWithBoolean
{
public string Method(short s, bool b = true)
{
return "short";
}

public string Method(bool b)
{
return "boolean";
}
}
}
58 changes: 52 additions & 6 deletions Jint/Runtime/Interop/InteropHelper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using Jint.Extensions;
using Jint.Native;

Expand Down Expand Up @@ -120,14 +121,59 @@ private static int CalculateMethodParameterScore(Engine engine, ParameterInfo pa
return 5;
}

if (paramType == typeof(int) && parameterValue.IsInteger())
const int ScoreForDifferentTypeButFittingNumberRange = 2;
if (parameterValue.IsNumber())
{
return 0;
}
var num = (JsNumber) parameterValue;
var numValue = num._value;

if (paramType == typeof(float) && objectValueType == typeof(double))
{
return parameterValue.IsInteger() ? 1 : 2;
if (paramType == typeof(double))
{
return 0;
}

if (paramType == typeof(float) && numValue is <= float.MaxValue and >= float.MinValue)
{
return ScoreForDifferentTypeButFittingNumberRange;
}

var isInteger = num.IsInteger() || TypeConverter.IsIntegralNumber(num._value);

// if value is integral number and within allowed range for the parameter type, we consider this perfect match
if (isInteger)
{
if (paramType == typeof(int))
{
return 0;
}

if (paramType == typeof(long))
{
return ScoreForDifferentTypeButFittingNumberRange;
}

// check if we can narrow without exception throwing versions (CanChangeType)
var integerValue = (int) num._value;
if (paramType == typeof(short) && integerValue is <= short.MaxValue and >= short.MinValue)
{
return ScoreForDifferentTypeButFittingNumberRange;
}

if (paramType == typeof(ushort) && integerValue is <= ushort.MaxValue and >= ushort.MinValue)
{
return ScoreForDifferentTypeButFittingNumberRange;
}

if (paramType == typeof(byte) && integerValue is <= byte.MaxValue and >= byte.MinValue)
{
return ScoreForDifferentTypeButFittingNumberRange;
}

if (paramType == typeof(sbyte) && integerValue is <= sbyte.MaxValue and >= sbyte.MinValue)
{
return ScoreForDifferentTypeButFittingNumberRange;
}
}
}

if (paramType.IsEnum &&
Expand Down

0 comments on commit 44a0ce0

Please sign in to comment.