diff --git a/Jurassic/Compiler/Binders/BinderMethod.cs b/Jurassic/Compiler/Binders/BinderMethod.cs
index 8ce0e8f3..c6f52479 100644
--- a/Jurassic/Compiler/Binders/BinderMethod.cs
+++ b/Jurassic/Compiler/Binders/BinderMethod.cs
@@ -187,7 +187,7 @@ private Type ParamArrayElementType
/// Gets an array of method parameters.
///
/// An array of ParameterInfo instances describing the method parameters.
- protected virtual ParameterInfo[] GetParameters()
+ internal virtual ParameterInfo[] GetParameters()
{
return this.Method.GetParameters();
}
diff --git a/Jurassic/Compiler/Binders/BinderUtilities.cs b/Jurassic/Compiler/Binders/BinderUtilities.cs
index f2eac035..59697abe 100644
--- a/Jurassic/Compiler/Binders/BinderUtilities.cs
+++ b/Jurassic/Compiler/Binders/BinderUtilities.cs
@@ -33,7 +33,8 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn
const int disqualification = 65536;
for (int i = 0; i < methods.Length; i++)
{
- foreach (var argument in methods[i].GetArguments(arguments.Length))
+ IEnumerable binderArguments = methods[i].GetArguments(arguments.Length);
+ foreach (var argument in binderArguments)
{
// Get the input parameter.
object input;
@@ -55,8 +56,10 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn
// Get the type of the output parameter.
Type outputType = argument.Type;
+ TypeCode typeCode = Type.GetTypeCode(outputType);
- switch (Type.GetTypeCode(outputType))
+
+ switch (typeCode)
{
case TypeCode.Boolean:
if ((input is bool) == false)
@@ -64,26 +67,37 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn
break;
case TypeCode.SByte:
- case TypeCode.Int16:
- case TypeCode.Int32:
- case TypeCode.Int64:
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Int64:
case TypeCode.Single:
case TypeCode.Decimal:
+ case TypeCode.Double:
+ Dictionary offsetDict = new Dictionary() { { TypeCode.SByte, 10 },
+ { TypeCode.Byte, 9 },
+ { TypeCode.UInt16, 8 },
+ { TypeCode.UInt32, 7 },
+ { TypeCode.UInt64, 6 },
+ { TypeCode.Int16, 5 },
+ { TypeCode.Int32, 4 },
+ { TypeCode.Int64, 3 },
+ { TypeCode.Single, 2 },
+ { TypeCode.Decimal, 1 },
+ { TypeCode.Double, 0 }
+ };
+
+ // To fix ambiguous methods error when there are method with numeric parameters
+ // double has maximal priority
if (TypeUtilities.IsNumeric(input) == true)
- demeritPoints[i] ++;
+ demeritPoints[i] += offsetDict[typeCode];
else
demeritPoints[i] += disqualification;
break;
- case TypeCode.Double:
- if (TypeUtilities.IsNumeric(input) == false)
- demeritPoints[i] += disqualification;
- break;
-
case TypeCode.Char:
if (TypeUtilities.IsString(input) == true)
demeritPoints[i]++;
@@ -111,6 +125,12 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn
{
demeritPoints[i] += disqualification;
}
+ else if (outputType != input.GetType())
+ {
+ // To fix ambiguous when the parameter is of type object and there is another method
+ // with parameter which inherits object.
+ demeritPoints[i]++;
+ }
break;
@@ -118,22 +138,47 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn
case TypeCode.DBNull:
throw new NotSupportedException(string.Format("{0} is not a supported parameter type.", outputType));
}
+ // To fix ambiguous methods error when there are method with smilar parameters, for example int32[] and int32
+ if (argument.IsParamArrayArgument)
+ {
+ demeritPoints[i] += 100;
+ }
}
}
// Find the method(s) with the fewest number of demerit points.
- int lowestScore = int.MaxValue;
- var lowestIndices = new List();
- for (int i = 0; i < methods.Length; i++)
+ int lowestScore;
+ var lowestIndices = _LowestIndices(methods, demeritPoints, out lowestScore);
+
+ // Try to get the method from the most close base type
+ if (lowestIndices.Count > 1)
{
- if (demeritPoints[i] < lowestScore)
+ for (int i = 0; i < demeritPoints.Length; i++)
{
- lowestScore = demeritPoints[i];
- lowestIndices.Clear();
+ demeritPoints[i] = disqualification;
}
- if (demeritPoints[i] <= lowestScore)
- lowestIndices.Add(i);
+ for (int i = 0; i < lowestIndices.Count; i++)
+ {
+ int index = lowestIndices[i];
+ demeritPoints[index] = _CalcMethodDistance(_GetThisType(thisValue), methods[index].DeclaringType);
+ }
+ lowestIndices = _LowestIndices(methods, demeritPoints, out lowestScore);
+ }
+
+ // Try to get the method with most close arguments count
+ if (lowestIndices.Count > 1)
+ {
+ for (int i = 0; i < demeritPoints.Length; i++)
+ {
+ demeritPoints[i] = disqualification;
+ }
+ for (int i = 0; i < lowestIndices.Count; i++)
+ {
+ int index = lowestIndices[i];
+ demeritPoints[index] = _CalcArgumentsPoint(methods[index], arguments.Length);
+ }
+ lowestIndices = _LowestIndices(methods, demeritPoints, out lowestScore);
}
// Throw an error if the match is ambiguous.
@@ -151,6 +196,66 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn
return lowestIndices[0];
}
+
+
+ private static List _LowestIndices(BinderMethod[] methods, int[] demeritPoints, out int lowestScore)
+ {
+ lowestScore = int.MaxValue;
+ List lowestIndices = new List();
+ for (int i = 0; i < methods.Length; i++)
+ {
+ if (demeritPoints[i] < lowestScore)
+ {
+ lowestScore = demeritPoints[i];
+ lowestIndices.Clear();
+ }
+ if (demeritPoints[i] <= lowestScore)
+ lowestIndices.Add(i);
+ }
+
+ return lowestIndices;
+ }
+
+
+ private static Type _GetThisType(object thisValue)
+ {
+ object thisUnwrapped = thisValue;
+ if (thisUnwrapped is Jurassic.Library.ClrInstanceWrapper)
+ {
+ thisUnwrapped = ((Jurassic.Library.ClrInstanceWrapper)thisUnwrapped).WrappedInstance;
+ }
+ else if (thisUnwrapped is Jurassic.Library.ClrInstanceTypeWrapper)
+ {
+ thisUnwrapped = ((Jurassic.Library.ClrInstanceTypeWrapper)thisUnwrapped).WrappedType;
+ }
+ else if (thisUnwrapped is Jurassic.Library.ClrStaticTypeWrapper)
+ {
+ thisUnwrapped = ((Jurassic.Library.ClrStaticTypeWrapper)thisUnwrapped).WrappedType;
+ }
+ return thisUnwrapped.GetType();
+ }
+
+
+ private static int _CalcMethodDistance(Type thisType, Type declaringType)
+ {
+ Type currentType = thisType;
+
+ int result = 0;
+ while (currentType != null && currentType != declaringType)
+ {
+ result++;
+ currentType = currentType.BaseType;
+ }
+
+ return result;
+ }
+
+
+ private static int _CalcArgumentsPoint(BinderMethod method, int argumentsCount)
+ {
+ int points = Math.Max(method.GetParameters().Length - argumentsCount, 0);
+ return points;
+ }
}
}
diff --git a/Jurassic/Compiler/Binders/JSBinderMethod.cs b/Jurassic/Compiler/Binders/JSBinderMethod.cs
index c196dc3e..bbfd2045 100644
--- a/Jurassic/Compiler/Binders/JSBinderMethod.cs
+++ b/Jurassic/Compiler/Binders/JSBinderMethod.cs
@@ -163,7 +163,7 @@ public int MaxParameterCount
/// Gets an array of method parameters.
///
/// An array of ParameterInfo instances describing the method parameters.
- protected override ParameterInfo[] GetParameters()
+ internal override ParameterInfo[] GetParameters()
{
// Pull out the first and/or second parameters.
var result = base.GetParameters();
diff --git a/Jurassic/Compiler/Binders/MethodBinder.cs b/Jurassic/Compiler/Binders/MethodBinder.cs
index 5221a26e..378662ed 100644
--- a/Jurassic/Compiler/Binders/MethodBinder.cs
+++ b/Jurassic/Compiler/Binders/MethodBinder.cs
@@ -39,14 +39,14 @@ protected MethodBinder(BinderMethod targetMethod)
/// Creates a new Binder instance.
///
/// An enumerable list of methods to bind to. At least one
- /// method must be provided. Every method must have the same name and declaring type.
+ /// method must be provided. Every method must have the same name.
protected MethodBinder(IEnumerable targetMethods)
{
if (targetMethods == null)
throw new ArgumentNullException(nameof(targetMethods));
// At least one method must be provided.
- // Every method must have the same name and declaring type.
+ // Every method must have the same name
foreach (var method in targetMethods)
{
if (this.Name == null)
@@ -58,8 +58,13 @@ protected MethodBinder(IEnumerable targetMethods)
{
if (this.Name != method.Name)
throw new ArgumentException(nameof(targetMethods));
- if (this.declaringType != method.DeclaringType)
- throw new ArgumentException(nameof(targetMethods));
+
+ // This code is removed, because now methods with same name from
+ // the whole inheritance hierarchy are grouped together.
+ // Otherwise method from the base class is not accessible when there
+ // is a method with the same name in inherited class.
+ //if (this.declaringType != method.DeclaringType)
+ // throw new ArgumentException(nameof(targetMethods));
}
this.functionLength = Math.Max(this.FunctionLength, method.RequiredParameterCount +
method.OptionalParameterCount + (method.HasParamArray ? 1 : 0));
diff --git a/Jurassic/Library/ClrWrapper/ClrStaticTypeWrapper.cs b/Jurassic/Library/ClrWrapper/ClrStaticTypeWrapper.cs
index 01e19dcf..bc6fd944 100644
--- a/Jurassic/Library/ClrWrapper/ClrStaticTypeWrapper.cs
+++ b/Jurassic/Library/ClrWrapper/ClrStaticTypeWrapper.cs
@@ -197,13 +197,24 @@ public override ObjectInstance ConstructLateBound(params object[] argumentValues
/// BindingFlags.Instance to populate instance methods.
internal static void PopulateMembers(ObjectInstance target, Type type, BindingFlags flags)
{
+ List ownMethods = new List();
+ foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | flags))
+ {
+ if (member.MemberType == MemberTypes.Method)
+ ownMethods.Add(member.Name);
+ }
+
// Register static methods as functions.
var methodGroups = new Dictionary>();
- foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | flags))
+ foreach (var member in type.GetMembers(BindingFlags.Public | flags))
{
switch (member.MemberType)
{
case MemberTypes.Method:
+ // Use base class method only when overriden
+ if (member.DeclaringType != type && !ownMethods.Contains(member.Name))
+ continue;
+
MethodInfo method = (MethodInfo)member;
List methodGroup;
if (methodGroups.TryGetValue(method.Name, out methodGroup) == true)
@@ -213,6 +224,9 @@ internal static void PopulateMembers(ObjectInstance target, Type type, BindingFl
break;
case MemberTypes.Property:
+ if (member.DeclaringType != type) // Skip base class properties
+ continue;
+
PropertyInfo property = (PropertyInfo)member;
var getMethod = property.GetGetMethod();
ClrFunction getter = getMethod == null ? null : new ClrFunction(target.Engine.Function.InstancePrototype, new ClrBinder(getMethod));
@@ -229,6 +243,9 @@ internal static void PopulateMembers(ObjectInstance target, Type type, BindingFl
break;
case MemberTypes.Field:
+ if (member.DeclaringType != type) // Skip base class fields
+ continue;
+
FieldInfo field = (FieldInfo)member;
ClrFunction fieldGetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldGetterBinder(field));
ClrFunction fieldSetter = new ClrFunction(target.Engine.Function.InstancePrototype, new FieldSetterBinder(field));