Skip to content
Merged
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
78 changes: 64 additions & 14 deletions src/System.Management.Automation/engine/CoreAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -708,28 +708,46 @@ internal string BaseParameterizedPropertyToString(PSParameterizedProperty proper

#region Internal Helper Methods

private static Type GetArgumentType(object argument)
private static Type GetArgumentType(object argument, bool isByRefParameter)
{
if (argument == null)
{
return typeof(LanguagePrimitives.Null);
}
PSReference psref = argument as PSReference;
if (psref != null)

if (isByRefParameter && argument is PSReference psref)
{
return GetArgumentType(PSObject.Base(psref.Value));
return GetArgumentType(PSObject.Base(psref.Value), isByRefParameter: false);
}

return argument.GetType();
}

internal static ConversionRank GetArgumentConversionRank(object argument, Type parameterType)
internal static ConversionRank GetArgumentConversionRank(object argument, Type parameterType, bool isByRef, bool allowCastingToByRefLikeType)
{
Type fromType = GetArgumentType(argument);
ConversionRank rank = LanguagePrimitives.GetConversionRank(fromType, parameterType);
Type fromType = null;
ConversionRank rank = ConversionRank.None;

if (allowCastingToByRefLikeType && parameterType.IsByRefLike)
{
// When resolving best method for use in binders, we can accept implicit/explicit casting conversions to
// a ByRef-like target type, because when generating IL from a call site with the binder, the IL includes
// the casting operation. However, we don't accept such conversions when it's for invoking the method via
// reflection, because reflection just doesn't support ByRef-like type.
fromType = GetArgumentType(PSObject.Base(argument), isByRefParameter: false);
if (fromType != typeof(LanguagePrimitives.Null))
{
LanguagePrimitives.FigureCastConversion(fromType, parameterType, ref rank);
}
return rank;
}

fromType = GetArgumentType(argument, isByRef);
rank = LanguagePrimitives.GetConversionRank(fromType, parameterType);

if (rank == ConversionRank.None)
{
fromType = GetArgumentType(PSObject.Base(argument));
fromType = GetArgumentType(PSObject.Base(argument), isByRef);
rank = LanguagePrimitives.GetConversionRank(fromType, parameterType);
}

Expand Down Expand Up @@ -1186,6 +1204,7 @@ private static bool IsInvocationConstraintSatisfied(OverloadCandidate overloadCa
/// </summary>
/// <param name="methods">different overloads for a method</param>
/// <param name="invocationConstraints">invocation constraints</param>
/// <param name="allowCastingToByRefLikeType">true if we accept implicit/explicit casting conversion to a ByRef-like parameter type for method resolution</param>
/// <param name="arguments">arguments to check against the overloads</param>
/// <param name="errorId">if no best method, the error id to use in the error message</param>
/// <param name="errorMsg">if no best method, the error message (format string) to use in the error message</param>
Expand All @@ -1194,14 +1213,15 @@ private static bool IsInvocationConstraintSatisfied(OverloadCandidate overloadCa
internal static MethodInformation FindBestMethod(
MethodInformation[] methods,
PSMethodInvocationConstraints invocationConstraints,
bool allowCastingToByRefLikeType,
object[] arguments,
ref string errorId,
ref string errorMsg,
out bool expandParamsOnBest,
out bool callNonVirtually)
{
callNonVirtually = false;
var methodInfo = FindBestMethodImpl(methods, invocationConstraints, arguments, ref errorId, ref errorMsg, out expandParamsOnBest);
var methodInfo = FindBestMethodImpl(methods, invocationConstraints, allowCastingToByRefLikeType, arguments, ref errorId, ref errorMsg, out expandParamsOnBest);
if (methodInfo == null)
{
return null;
Expand Down Expand Up @@ -1243,6 +1263,7 @@ internal static MethodInformation FindBestMethod(
private static MethodInformation FindBestMethodImpl(
MethodInformation[] methods,
PSMethodInvocationConstraints invocationConstraints,
bool allowCastingToByRefLikeType,
object[] arguments,
ref string errorId,
ref string errorMsg,
Expand Down Expand Up @@ -1364,8 +1385,18 @@ private static MethodInformation FindBestMethodImpl(
Type elementType = parameter.parameterType.GetElementType();
if (parameters.Length == arguments.Length)
{
ConversionRank arrayConv = GetArgumentConversionRank(arguments[j], parameter.parameterType);
ConversionRank elemConv = GetArgumentConversionRank(arguments[j], elementType);
ConversionRank arrayConv = GetArgumentConversionRank(
arguments[j],
parameter.parameterType,
isByRef: false,
allowCastingToByRefLikeType: false);

ConversionRank elemConv = GetArgumentConversionRank(
arguments[j],
elementType,
isByRef: false,
allowCastingToByRefLikeType: false);

if (elemConv > arrayConv)
{
candidate.expandedParameters = ExpandParameters(arguments.Length, parameters, elementType);
Expand All @@ -1387,7 +1418,12 @@ private static MethodInformation FindBestMethodImpl(
// Note that we go through here when the param array parameter has no argument.
for (int k = j; k < arguments.Length; k++)
{
candidate.conversionRanks[k] = GetArgumentConversionRank(arguments[k], elementType);
candidate.conversionRanks[k] = GetArgumentConversionRank(
arguments[k],
elementType,
isByRef: false,
allowCastingToByRefLikeType: false);

if (candidate.conversionRanks[k] == ConversionRank.None)
{
// No longer a candidate
Expand All @@ -1404,7 +1440,11 @@ private static MethodInformation FindBestMethodImpl(
}
else
{
candidate.conversionRanks[j] = GetArgumentConversionRank(arguments[j], parameter.parameterType);
candidate.conversionRanks[j] = GetArgumentConversionRank(
arguments[j],
parameter.parameterType,
parameter.isByRef,
allowCastingToByRefLikeType);

if (candidate.conversionRanks[j] == ConversionRank.None)
{
Expand Down Expand Up @@ -1540,7 +1580,17 @@ internal static MethodInformation GetBestMethodAndArguments(
bool callNonVirtually;
string errorId = null;
string errorMsg = null;
MethodInformation bestMethod = FindBestMethod(methods, invocationConstraints, arguments, ref errorId, ref errorMsg, out expandParamsOnBest, out callNonVirtually);

MethodInformation bestMethod = FindBestMethod(
methods,
invocationConstraints,
allowCastingToByRefLikeType: false,
arguments,
ref errorId,
ref errorMsg,
out expandParamsOnBest,
out callNonVirtually);

if (bestMethod == null)
{
throw new MethodException(errorId, null, errorMsg, methodName, arguments.Length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,7 @@ internal static void DoConversionsForSetInGenericDictionary(IDictionary dictiona
#region type converter

internal static PSTraceSource typeConversion = PSTraceSource.GetTracer("TypeConversion", "Traces the type conversion algorithm", false);
internal static ConversionData<object> NoConversion = new ConversionData<object>(ConvertNoConversion, ConversionRank.None);

private static TypeConverter GetIntegerSystemConverter(Type type)
{
Expand Down
12 changes: 11 additions & 1 deletion src/System.Management.Automation/engine/parser/PSType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,17 @@ private static CustomAttributeBuilder GetAttributeBuilder(Parser parser, Attribu
bool expandParamsOnBest;
bool callNonVirtually;
var positionalArgCount = positionalArgs.Length;
var bestMethod = Adapter.FindBestMethod(newConstructors, null, positionalArgs, ref errorId, ref errorMsg, out expandParamsOnBest, out callNonVirtually);

var bestMethod = Adapter.FindBestMethod(
newConstructors,
invocationConstraints: null,
allowCastingToByRefLikeType: false,
positionalArgs,
ref errorId,
ref errorMsg,
out expandParamsOnBest,
out callNonVirtually);

if (bestMethod == null)
{
parser.ReportError(new ParseError(attributeAst.Extent, errorId,
Expand Down
Loading