diff options
author | Marek Safar <marek.safar@gmail.com> | 2006-12-16 14:53:34 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2006-12-16 14:53:34 +0300 |
commit | 86cf45a556cfe278df79acbbba8a8a2a60739a8b (patch) | |
tree | 84992913715a76badef5ab8681adc6e71a8ce49a | |
parent | 3041719d86ed3bcba84fa13cc23b5c3c2eec4444 (diff) |
2006-12-16 Marek Safar <marek.safar@gmail.com>
A fix for bug #77014
* expression.cs (Invocation.BetterFunction): Fixed to cope with dynamic
paramters correctly and not rely on hacks in Parameters class.
(Invocation.IsParamsMethodApplicable): Changed to accept params parameter
at any possition.
(Invocation.VerifyArgumentsCompat): Ditto.
(Invocation.EmitArguments): Changed to correctly emit params arguments at
any possition.
* parameter.cs (HasParams): Don't assume that params is the last one.
* support.cs (ReflectionParameters.ctor): Look for params attribute
correctly.
(ReflectionParameters.ParameterType): Removed hack when we returned last
parameter for out of range parameters.
(ParameterName, ParameterModifier): Ditto.
svn path=/trunk/mcs/; revision=69571
-rw-r--r-- | mcs/mcs/ChangeLog | 19 | ||||
-rw-r--r-- | mcs/mcs/expression.cs | 161 | ||||
-rw-r--r-- | mcs/mcs/parameter.cs | 6 | ||||
-rw-r--r-- | mcs/mcs/support.cs | 83 |
4 files changed, 161 insertions, 108 deletions
diff --git a/mcs/mcs/ChangeLog b/mcs/mcs/ChangeLog index 818849b6043..fd7f1aa244f 100644 --- a/mcs/mcs/ChangeLog +++ b/mcs/mcs/ChangeLog @@ -1,3 +1,22 @@ +2006-12-16 Marek Safar <marek.safar@gmail.com> + + A fix for bug #77014 + * expression.cs (Invocation.BetterFunction): Fixed to cope with dynamic + paramters correctly and not rely on hacks in Parameters class. + (Invocation.IsParamsMethodApplicable): Changed to accept params parameter + at any possition. + (Invocation.VerifyArgumentsCompat): Ditto. + (Invocation.EmitArguments): Changed to correctly emit params arguments at + any possition. + + * parameter.cs (HasParams): Don't assume that params is the last one. + + * support.cs (ReflectionParameters.ctor): Look for params attribute + correctly. + (ReflectionParameters.ParameterType): Removed hack when we returned last + parameter for out of range parameters. + (ParameterName, ParameterModifier): Ditto. + 2006-12-14 Marek Safar <marek.safar@gmail.com> A fix for bug #79987 diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 5db4b296f8b..d7cdd548ffa 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -4075,19 +4075,21 @@ namespace Mono.CSharp { bool better_at_least_one = false; bool same = true; - for (int j = 0; j < argument_count; ++j) { + for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx) { Argument a = (Argument) args [j]; - Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j)); - Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j)); + Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx)); + Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx)); - if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) - if (candidate_params) - ct = TypeManager.GetElementType (ct); + if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS) { + ct = TypeManager.GetElementType (ct); + --c_idx; + } - if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) - if (best_params) - bt = TypeManager.GetElementType (bt); + if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS) { + bt = TypeManager.GetElementType (bt); + --b_idx; + } if (ct.Equals (bt)) continue; @@ -4317,6 +4319,10 @@ namespace Mono.CSharp { return false; if (pd_count != arg_count) return false; + + if (!(((Argument) arguments [count]).Expr is Arglist)) + return false; + --pd_count; } else { if (!pd.HasParams) return false; @@ -4333,9 +4339,26 @@ namespace Mono.CSharp { // remains is when the number of parameters is // less than or equal to the argument count. // - for (int i = 0; i < count; ++i) { + int argument_index = 0; + Argument a; + for (int i = 0; i < pd_count; ++i) { - Argument a = (Argument) arguments [i]; + if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) { + Type element_type = TypeManager.GetElementType (pd.ParameterType (i)); + int params_args_count = arg_count - pd_count; + if (params_args_count < 0) + continue; + + do { + a = (Argument) arguments [argument_index++]; + + if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type)) + return false; + } while (params_args_count-- > 0); + continue; + } + + a = (Argument) arguments [argument_index++]; Parameter.Modifier a_mod = a.Modifier & (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK))); @@ -4346,9 +4369,9 @@ namespace Mono.CSharp { if (a_mod == Parameter.Modifier.NONE) if (!Convert.ImplicitConversionExists (ec, - a.Expr, - pd.ParameterType (i))) - return false; + a.Expr, + pd.ParameterType (i))) + return false; if ((a_mod & Parameter.Modifier.ISBYREF) != 0) { Type pt = pd.ParameterType (i); @@ -4364,23 +4387,6 @@ namespace Mono.CSharp { } - if (do_varargs) { - Argument a = (Argument) arguments [count]; - if (!(a.Expr is Arglist)) - return false; - - return true; - } - - Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1)); - - for (int i = pd_count - 1; i < arg_count; i++) { - Argument a = (Argument) arguments [i]; - - if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type)) - return false; - } - return true; } @@ -4852,12 +4858,13 @@ namespace Mono.CSharp { { ParameterData pd = TypeManager.GetParameterData (method); int j; - for (j = 0; j < arg_count; j++) { - Argument a = (Argument) Arguments [j]; - Expression a_expr = a.Expr; + int a_idx = 0; + int params_arg_count = 0; + Argument a = null; + for (j = 0; j < pd.Count & a_idx < arg_count; j++, a_idx++) { + a = (Argument) Arguments [a_idx]; Type parameter_type = pd.ParameterType (j); Parameter.Modifier pm = pd.ParameterModifier (j); - Parameter.Modifier am = a.Modifier; if (pm == Parameter.Modifier.ARGLIST) { if (!(a.Expr is Arglist)) @@ -4867,37 +4874,45 @@ namespace Mono.CSharp { if (pm == Parameter.Modifier.PARAMS) { pm = Parameter.Modifier.NONE; + params_arg_count = arg_count - pd.Count; if (chose_params_expanded) parameter_type = TypeManager.GetElementType (parameter_type); } - if (pm != am) + conversion: + if (pm != a.Modifier) break; if (!TypeManager.IsEqual (a.Type, parameter_type)) { if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF) break; - Expression conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc); + Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc); if (conv == null) break; // Update the argument with the implicit conversion - if (a_expr != conv) + if (a.Expr != conv) a.Expr = conv; } + if (params_arg_count > 0) { + --params_arg_count; + a = (Argument) Arguments [++a_idx]; + goto conversion; + } + if (parameter_type.IsPointer && !ec.InUnsafe) { UnsafeError (loc); return false; } } - if (j == arg_count) + if (a_idx == arg_count) return true; if (!may_fail) - Error_InvalidArguments (loc, j, method, delegate_type, (Argument) Arguments [j], pd); + Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd); return false; } @@ -5037,22 +5052,20 @@ namespace Mono.CSharp { // <summary> // Emits the list of arguments as an array // </summary> - static void EmitParams (EmitContext ec, int idx, ArrayList arguments) + static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count) { ILGenerator ig = ec.ig; - int count = arguments.Count - idx; - Argument a = (Argument) arguments [idx]; - Type t = a.Expr.Type; - - IntConstant.EmitInt (ig, count); - ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t)); - - int top = arguments.Count; - for (int j = idx; j < top; j++){ - a = (Argument) arguments [j]; + Type t = null; + for (int j = 0; j < count; j++){ + Argument a = (Argument) arguments [j + idx]; + if (j == 0) { + t = a.Expr.Type; + IntConstant.EmitInt (ig, count); + ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t)); + } ig.Emit (OpCodes.Dup); - IntConstant.EmitInt (ig, j - idx); + IntConstant.EmitInt (ig, j); bool is_stobj, has_type_arg; OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg); @@ -5085,29 +5098,47 @@ namespace Mono.CSharp { public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg) { ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb); - int top = arguments == null ? 0 : arguments.Count; + int top = pd.Count; LocalTemporary [] temps = null; if (dup_args && top != 0) temps = new LocalTemporary [top]; + int argument_index = 0; + Argument a; for (int i = 0; i < top; i++){ - Argument a = (Argument) arguments [i]; - if (pd != null){ if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){ + //Type element_type = TypeManager.GetElementType (pd.ParameterType (i)); + int params_args_count = arguments == null ? + 0 : arguments.Count - top + 1; + + // Fill not provided argument + if (params_args_count <= 0) { + ILGenerator ig = ec.ig; + IntConstant.EmitInt (ig, 0); + ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i))); + continue; + } + // // Special case if we are passing the same data as the - // params argument, do not put it in an array. + // params argument, we do not need to recreate an array. // - if (pd.ParameterType (i) == a.Type) + a = (Argument) arguments [argument_index]; + if (params_args_count == 1 && pd.ParameterType (i) == a.Type) { + ++argument_index; a.Emit (ec); - else - EmitParams (ec, i, arguments); - return; + continue; + } + + EmitParams (ec, arguments, i, params_args_count); + argument_index += params_args_count; + continue; } } - + + a = (Argument) arguments [argument_index++]; a.Emit (ec); if (dup_args) { ec.ig.Emit (OpCodes.Dup); @@ -5124,14 +5155,6 @@ namespace Mono.CSharp { temps [i].Release (ec); } } - - if (pd != null && pd.Count > top && - pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){ - ILGenerator ig = ec.ig; - - IntConstant.EmitInt (ig, 0); - ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top))); - } } static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments) diff --git a/mcs/mcs/parameter.cs b/mcs/mcs/parameter.cs index 614bade23ce..80fc9753ca4 100644 --- a/mcs/mcs/parameter.cs +++ b/mcs/mcs/parameter.cs @@ -794,7 +794,11 @@ namespace Mono.CSharp { if (count == 0) return false; - return FixedParameters [count - 1] is ParamsParameter; + for (int i = count; i != 0; --i) { + if ((FixedParameters [i - 1].ModFlags & Parameter.Modifier.PARAMS) != 0) + return true; + } + return false; } } diff --git a/mcs/mcs/support.cs b/mcs/mcs/support.cs index 74b81a5f8db..2060f95e0f6 100644 --- a/mcs/mcs/support.cs +++ b/mcs/mcs/support.cs @@ -32,46 +32,60 @@ namespace Mono.CSharp { public class ReflectionParameters : ParameterData { ParameterInfo [] pi; Type [] types; - bool last_arg_is_params = false; - bool is_varargs = false; + int params_idx = -1; + bool is_varargs; ParameterData gpd; public ReflectionParameters (MethodBase mb) { - object [] attrs; - ParameterInfo [] pi = mb.GetParameters (); is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0; this.pi = pi; - int count = pi.Length-1; + int count = pi.Length; - if (pi.Length == 0) { + if (count == 0) { types = Type.EmptyTypes; - } else { - types = new Type [pi.Length]; - for (int i = 0; i < pi.Length; i++) - types [i] = pi [i].ParameterType; + return; } - if (count < 0) - return; + types = new Type [count]; + for (int i = 0; i < count; i++) + types [i] = pi [i].ParameterType; + // TODO: This (if) should be done one level higher to correctly use + // out caching facilities. MethodBase generic = TypeManager.DropGenericMethodArguments (mb); if (generic != mb) { - gpd = TypeManager.GetParameterData (generic); - last_arg_is_params = gpd.HasParams; - return; + gpd = TypeManager.GetParameterData (generic); + if (gpd.HasParams) { + for (int i = gpd.Count; i != 0; --i) { + if ((gpd.ParameterModifier (i)& Parameter.Modifier.PARAMS) != 0) { + this.params_idx = i; + break; + } + } + } + return; } - attrs = pi [count].GetCustomAttributes (TypeManager.param_array_type, true); - if (attrs == null) - return; - - if (attrs.Length == 0) - return; - - last_arg_is_params = true; + // + // So far, the params attribute can be used in C# for the last + // and next to last method parameters. + // If some other language can place it anywhere we will + // have to analyze all parameters and not just last 2. + // + --count; + for (int i = count; i >= 0 && i > count - 2; --i) { + if (!pi [i].ParameterType.IsArray) + continue; + + object [] attrs = pi [i].GetCustomAttributes (TypeManager.param_array_type, true); + if (attrs.Length == 1) { + params_idx = i; + return; + } + } } public string GetSignatureForError () @@ -93,15 +107,10 @@ namespace Mono.CSharp { public Type ParameterType (int pos) { - if (last_arg_is_params && pos >= pi.Length - 1) - return pi [pi.Length - 1].ParameterType; - else if (is_varargs && pos >= pi.Length) + if (is_varargs && pos >= pi.Length) return TypeManager.runtime_argument_handle_type; - else { - Type t = pi [pos].ParameterType; - return t; - } + return pi [pos].ParameterType; } public string ParameterName (int pos) @@ -109,12 +118,10 @@ namespace Mono.CSharp { if (gpd != null) return gpd.ParameterName (pos); - if (last_arg_is_params && pos >= pi.Length - 1) - return pi [pi.Length - 1].Name; - else if (is_varargs && pos >= pi.Length) + if (is_varargs && pos >= pi.Length) return "__arglist"; - else - return pi [pos].Name; + + return pi [pos].Name; } public string ParameterDesc (int pos) @@ -136,7 +143,7 @@ namespace Mono.CSharp { sb.Append ("ref "); } - if (pos >= pi.Length - 1 && last_arg_is_params) + if (params_idx == pos) sb.Append ("params "); sb.Append (TypeManager.CSharpName (partype).Replace ("&", "")); @@ -146,7 +153,7 @@ namespace Mono.CSharp { public Parameter.Modifier ParameterModifier (int pos) { - if (last_arg_is_params && pos >= pi.Length - 1) + if (pos == params_idx) return Parameter.Modifier.PARAMS; else if (is_varargs && pos >= pi.Length) return Parameter.Modifier.ARGLIST; @@ -170,7 +177,7 @@ namespace Mono.CSharp { } public bool HasParams { - get { return last_arg_is_params; } + get { return params_idx != -1; } } public Type[] Types { |