From 44a0ce0d173d9817a05a388b157d839cb2c8ce9c Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Sat, 2 Nov 2024 20:45:21 +0200 Subject: [PATCH] Improve interop conversion logic between numeric types (#1995) --- Jint.Tests/Runtime/InteropTests.cs | 20 +++++++++ Jint/Runtime/Interop/InteropHelper.cs | 58 ++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/Jint.Tests/Runtime/InteropTests.cs b/Jint.Tests/Runtime/InteropTests.cs index 125303f599..c62b7f5f3a 100644 --- a/Jint.Tests/Runtime/InteropTests.cs +++ b/Jint.Tests/Runtime/InteropTests.cs @@ -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"; + } + } } diff --git a/Jint/Runtime/Interop/InteropHelper.cs b/Jint/Runtime/Interop/InteropHelper.cs index 59b9c997a4..8130e0d724 100644 --- a/Jint/Runtime/Interop/InteropHelper.cs +++ b/Jint/Runtime/Interop/InteropHelper.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; +using System.Runtime.CompilerServices; using Jint.Extensions; using Jint.Native; @@ -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 &&