Forráskód Böngészése

Improve null handling in generic parameter resolution logic (#1209)

Marko Lahma 3 éve
szülő
commit
a800bd32e7

+ 18 - 2
Jint.Tests/Runtime/InteropTests.cs

@@ -2981,12 +2981,12 @@ namespace Jint.Tests.Runtime
 					var result = param0 + param1;
 					return result;
 				}");
-            //Checking working cusom type
+            // checking working custom type
             Assert.Equal(new Dimensional("kg", 90), (new Dimensional("kg", 30) + new Dimensional("kg", 60)));
             Assert.Equal(new Dimensional("kg", 90), engine.Invoke("Eval", new object[] { new Dimensional("kg", 30), new Dimensional("kg", 60) }).ToObject());
             Assert.Throws<InvalidOperationException>(() => new Dimensional("kg", 30) + new Dimensional("piece", 70));
 
-            //Checking throwing exception in ovveride operator
+            // checking throwing exception in override operator
             string errorMsg = string.Empty;
             errorMsg = Assert.Throws<JavaScriptException>(() => engine.Invoke("Eval", new object[] {new Dimensional("kg", 30), new Dimensional("piece", 70)})).Message;
             Assert.Equal("Dimensionals with different measure types are non-summable", errorMsg);
@@ -2996,5 +2996,21 @@ namespace Jint.Tests.Runtime
         {
             public int AnyProperty => throw new NotSupportedException("NOT SUPPORTED");
         }
+
+        [Fact]
+        public void GenericParameterResolutionShouldWorkWithNulls()
+        {
+            var result =new Engine()
+                .SetValue("JintCommon", new JintCommon())
+                .Evaluate("JintCommon.sum(1, null)")
+                .AsNumber();
+
+            Assert.Equal(2, result);
+        }
+
+        public class JintCommon
+        {
+            public int Sum(int a, int? b) => a + b.GetValueOrDefault(1);
+        }
     }
 }

+ 14 - 4
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -27,9 +27,14 @@ namespace Jint.Runtime.Interop
             _fallbackClrFunctionInstance = fallbackClrFunctionInstance;
         }
 
-        private static bool IsGenericParameter(object argObj, Type parameterType, int parameterIndex)
+        private static bool IsGenericParameter(object argObj, Type parameterType)
         {
-            var result = TypeConverter.IsAssignableToGenericType(argObj?.GetType(), parameterType);
+            if (argObj is null)
+            {
+                return false;
+            }
+
+            var result = TypeConverter.IsAssignableToGenericType(argObj.GetType(), parameterType);
             if (result.Score < 0)
             {
                 return false;
@@ -44,7 +49,12 @@ namespace Jint.Runtime.Interop
 
         private static void HandleGenericParameter(object argObj, Type parameterType, Type[] genericArgTypes)
         {
-            var result = TypeConverter.IsAssignableToGenericType(argObj?.GetType(), parameterType);
+            if (argObj is null)
+            {
+                return;
+            }
+
+            var result = TypeConverter.IsAssignableToGenericType(argObj.GetType(), parameterType);
             if (result.Score < 0)
             {
                 return;
@@ -173,7 +183,7 @@ namespace Jint.Runtime.Interop
                         // optional
                         parameters[i] = System.Type.Missing;
                     }
-                    else if (IsGenericParameter(argument.ToObject(), parameterType, i)) // don't think we need the condition preface of (argument == null) because of earlier condition
+                    else if (IsGenericParameter(argument.ToObject(), parameterType)) // don't think we need the condition preface of (argument == null) because of earlier condition
                     {
                         parameters[i] = argument.ToObject();
                     }

+ 8 - 15
Jint/Runtime/TypeConverter.cs

@@ -1124,17 +1124,9 @@ namespace Jint.Runtime
             return score;
         }
 
-        internal class AssignableResult
+        internal readonly record struct AssignableResult(int Score, Type MatchingGivenType)
         {
-            public int Score = -1;
-            public bool IsAssignable { get { return Score >= 0; } }
-            public Type MatchingGivenType;
-
-            public AssignableResult(int score, Type matchingGivenType)
-            {
-                Score = score;
-                MatchingGivenType = matchingGivenType;
-            }
+            public bool IsAssignable => Score >= 0;
         }
 
         /// <summary>
@@ -1147,11 +1139,13 @@ namespace Jint.Runtime
         /// and array handling - i.e.
         /// GetElementType()
         /// </summary>
-        /// <param name="givenType"></param>
-        /// <param name="genericType"></param>
-        /// <returns></returns>
         internal static AssignableResult IsAssignableToGenericType(Type givenType, Type genericType)
         {
+            if (givenType is null)
+            {
+                return new AssignableResult(-1, null);
+            }
+
             if (!genericType.IsConstructedGenericType)
             {
                 // as mentioned here:
@@ -1190,8 +1184,7 @@ namespace Jint.Runtime
                 return new AssignableResult(-1, givenType);
             }
 
-            var result = IsAssignableToGenericType(baseType, genericType);
-            return result;
+            return IsAssignableToGenericType(baseType, genericType);
         }
 
         /// <summary>