Skip to content

Commit

Permalink
runtime binder to collection params (params ReadOnlySpan<T>)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubmisek committed Feb 23, 2025
1 parent 6840062 commit ad88b1b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 13 deletions.
36 changes: 30 additions & 6 deletions src/Peachpie.Runtime/Dynamic/BinderHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,34 @@ namespace Pchp.Core.Dynamic
[DebuggerNonUserCode]
internal static class BinderHelpers
{
public static bool IsParamsParameter(this ParameterInfo p)
public static bool IsParamsParameter(this ParameterInfo p, out Type elementType)
{
//TODO: [ParamCollectionAttribute] Span<T>
return p.ParameterType.IsArray && p.CustomAttributes.Any(attr => attr.AttributeType == typeof(ParamArrayAttribute));
if (p.ParameterType.IsArray)
{
// [ParamArray] T[]
if (p.CustomAttributes.Any(attr => attr.AttributeType == typeof(ParamArrayAttribute)))
{
elementType = p.ParameterType.GetElementType();
return true;
}
}
else if (p.ParameterType.IsConstructedGenericType && p.CustomAttributes.Any(attr => attr.AttributeType.Name == "ParamCollectionAttribute")) // [ParamCollectionAttribute] Span<T>
{
var def_args = p.ParameterType.GenericTypeArguments;
if (def_args.Length == 1)
{
var def = p.ParameterType.GetGenericTypeDefinition();
if (def == typeof(Span<>) || def == typeof(ReadOnlySpan<>))
{
elementType = def_args[0]; // T
return true;
}
}
}

//
elementType = null;
return false;
}

/// <summary>
Expand Down Expand Up @@ -201,7 +225,7 @@ public static bool IsMandatoryParameter(this ParameterInfo p)
!p.HasDefaultValue && // CLR default value
!p.IsOptional && // has [Optional} attribute
p.GetCustomAttribute<DefaultValueAttribute>() == null && // has [DefaultValue] attribute
!p.IsParamsParameter(); // is params
!p.IsParamsParameter(out _); // is params
}

/// <summary>
Expand Down Expand Up @@ -1278,9 +1302,9 @@ public static Expression BindToCall(Expression instance, MethodBase method, Expr

// regular parameter:

if (i == ps.Length - 1 && p.IsParamsParameter())
if (i == ps.Length - 1 && p.IsParamsParameter(out var elementType))
{
boundargs[i] = args.BindParams(argi, p.ParameterType.GetElementType());
boundargs[i] = Expression.Convert(args.BindParamsArray(argi, elementType), p.ParameterType);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion src/Peachpie.Runtime/Dynamic/CallBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ protected static bool IsClrMagicCallWithParams(MethodInfo method)
if (!method.DeclaringType.GetPhpTypeInfo().IsPhpType) // only methods declared outside PHP code
{
if (count > 2) return true;
if (ps.Last().IsParamsParameter()) return true;
if (ps.Last().IsParamsParameter(out _)) return true;
}
}

Expand Down
10 changes: 4 additions & 6 deletions src/Peachpie.Runtime/Dynamic/OverloadBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ protected ArgumentsBinder(Expression ctx)
/// <summary>
/// Bind arguments to array of parameters.
/// </summary>
public abstract Expression BindParams(int fromarg, Type element_type);
public abstract Expression BindParamsArray(int fromarg, Type element_type);

/// <summary>
/// Gets expression representing cost of argument binding operation.
Expand Down Expand Up @@ -563,7 +563,7 @@ public override Expression BindWriteBack(int targetarg, Expression expression)
return Expression.Assign(element, ConvertExpression.Bind(expression, element.Type, _ctx));
}

public override Expression BindParams(int fromarg, Type element_type)
public override Expression BindParamsArray(int fromarg, Type element_type)
{
//if (element_type == _argsarray.Type.GetElementType())
//if (true)
Expand Down Expand Up @@ -778,7 +778,7 @@ public override Expression BindWriteBack(int targetarg, Expression expression)
return BinderHelpers.BindAssign(arg, expression, _ctx);
}

public override Expression BindParams(int fromarg, Type element_type)
public override Expression BindParamsArray(int fromarg, Type element_type)
{
var count = _args.Length - fromarg;

Expand Down Expand Up @@ -862,12 +862,10 @@ static Expression BindCostOf(MethodBase method, ArgumentsBinder args, BitArray c
for (int im = 0; im < nmandatory + noptional; im++)
{
var p = ps[nimplicit + im];
if (noptional != 0 && p.Position == ps.Length - 1 && p.IsParamsParameter())
if (noptional != 0 && p.Position == ps.Length - 1 && p.IsParamsParameter(out var element_type))
{
hasparams = true;

var element_type = p.ParameterType.GetElementType();

// for (int o = io + nmandatory; o < argc; o++) result |= CostOf(argv[o], p.ElementType)
if (argc_opt.HasValue)
{
Expand Down

0 comments on commit ad88b1b

Please sign in to comment.