[asp.net] ValidationUtility implementation
[mono.git] / mcs / mcs / parameter.cs
1 //
2 // parameter.cs: Parameter definition.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Marek Safar (marek.safar@seznam.cz)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc. 
11 //
12 //
13 using System;
14 using System.Text;
15
16 #if STATIC
17 using MetaType = IKVM.Reflection.Type;
18 using IKVM.Reflection;
19 using IKVM.Reflection.Emit;
20 #else
21 using MetaType = System.Type;
22 using System.Reflection;
23 using System.Reflection.Emit;
24 #endif
25
26 namespace Mono.CSharp {
27
28         /// <summary>
29         ///   Abstract Base class for parameters of a method.
30         /// </summary>
31         public abstract class ParameterBase : Attributable
32         {
33                 protected ParameterBuilder builder;
34
35                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
36                 {
37 #if false
38                         if (a.Type == pa.MarshalAs) {
39                                 UnmanagedMarshal marshal = a.GetMarshal (this);
40                                 if (marshal != null) {
41                                         builder.SetMarshal (marshal);
42                                 }
43                                 return;
44                         }
45 #endif
46                         if (a.HasSecurityAttribute) {
47                                 a.Error_InvalidSecurityParent ();
48                                 return;
49                         }
50
51                         if (a.Type == pa.Dynamic) {
52                                 a.Error_MisusedDynamicAttribute ();
53                                 return;
54                         }
55
56                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
57                 }
58
59                 public ParameterBuilder Builder {
60                         get {
61                                 return builder;
62                         }
63                 }
64
65                 public override bool IsClsComplianceRequired()
66                 {
67                         return false;
68                 }
69         }
70
71         /// <summary>
72         /// Class for applying custom attributes on the return type
73         /// </summary>
74         public class ReturnParameter : ParameterBase
75         {
76                 MemberCore method;
77
78                 // TODO: merge method and mb
79                 public ReturnParameter (MemberCore method, MethodBuilder mb, Location location)
80                 {
81                         this.method = method;
82                         try {
83                                 builder = mb.DefineParameter (0, ParameterAttributes.None, "");                 
84                         }
85                         catch (ArgumentOutOfRangeException) {
86                                 method.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type");
87                         }
88                 }
89
90                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
91                 {
92                         if (a.Type == pa.CLSCompliant) {
93                                 method.Compiler.Report.Warning (3023, 1, a.Location,
94                                         "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
95                         }
96
97                         // This occurs after Warning -28
98                         if (builder == null)
99                                 return;
100
101                         base.ApplyAttributeBuilder (a, ctor, cdata, pa);
102                 }
103
104                 public override AttributeTargets AttributeTargets {
105                         get {
106                                 return AttributeTargets.ReturnValue;
107                         }
108                 }
109
110                 /// <summary>
111                 /// Is never called
112                 /// </summary>
113                 public override string[] ValidAttributeTargets {
114                         get {
115                                 return null;
116                         }
117                 }
118         }
119
120         public class ImplicitLambdaParameter : Parameter
121         {
122                 public ImplicitLambdaParameter (string name, Location loc)
123                         : base (null, name, Modifier.NONE, null, loc)
124                 {
125                 }
126
127                 public override TypeSpec Resolve (IMemberContext ec, int index)
128                 {
129                         if (parameter_type == null)
130                                 throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
131                                         Name);
132
133                         base.idx = index;
134                         return parameter_type;
135                 }
136
137                 public void SetParameterType (TypeSpec type)
138                 {
139                         parameter_type = type;
140                 }
141         }
142
143         public class ParamsParameter : Parameter {
144                 public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
145                         base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
146                 {
147                 }
148
149                 public override TypeSpec Resolve (IMemberContext ec, int index)
150                 {
151                         if (base.Resolve (ec, index) == null)
152                                 return null;
153
154                         var ac = parameter_type as ArrayContainer;
155                         if (ac == null || ac.Rank != 1) {
156                                 ec.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
157                                 return null;
158                         }
159
160                         return parameter_type;
161                 }
162
163                 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
164                 {
165                         base.ApplyAttributes (mb, cb, index, pa);
166                         pa.ParamArray.EmitAttribute (builder);
167                 }
168         }
169
170         public class ArglistParameter : Parameter {
171                 // Doesn't have proper type because it's never chosen for better conversion
172                 public ArglistParameter (Location loc) :
173                         base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
174                 {
175                         parameter_type = InternalType.Arglist;
176                 }
177
178                 public override void  ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
179                 {
180                         // Nothing to do
181                 }
182
183                 public override bool CheckAccessibility (InterfaceMemberBase member)
184                 {
185                         return true;
186                 }
187
188                 public override TypeSpec Resolve (IMemberContext ec, int index)
189                 {
190                         return parameter_type;
191                 }
192         }
193
194         public interface IParameterData
195         {
196                 Expression DefaultValue { get; }
197                 bool HasExtensionMethodModifier { get; }
198                 bool HasDefaultValue { get; }
199                 Parameter.Modifier ModFlags { get; }
200                 string Name { get; }
201         }
202
203         //
204         // Parameter information created by parser
205         //
206         public class Parameter : ParameterBase, IParameterData, ILocalVariable // TODO: INamedBlockVariable
207         {
208                 [Flags]
209                 public enum Modifier : byte {
210                         NONE    = 0,
211                         REF     = REFMASK | ISBYREF,
212                         OUT     = OUTMASK | ISBYREF,
213                         PARAMS  = 4,
214                         // This is a flag which says that it's either REF or OUT.
215                         ISBYREF = 8,
216                         REFMASK = 32,
217                         OUTMASK = 64,
218                         This    = 128
219                 }
220
221                 static string[] attribute_targets = new string [] { "param" };
222
223                 FullNamedExpression texpr;
224                 readonly Modifier modFlags;
225                 string name;
226                 Expression default_expr;
227                 protected TypeSpec parameter_type;
228                 readonly Location loc;
229                 protected int idx;
230                 public bool HasAddressTaken;
231
232                 TemporaryVariableReference expr_tree_variable;
233                 static TypeExpr parameter_expr_tree_type;
234
235                 HoistedVariable hoisted_variant;
236
237                 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
238                 {
239                         this.name = name;
240                         modFlags = mod;
241                         this.loc = loc;
242                         texpr = type;
243
244                         // Only assign, attributes will be attached during resolve
245                         base.attributes = attrs;
246                 }
247
248                 #region Properties
249
250                 public Expression DefaultValue {
251                         get {
252                                 return default_expr;
253                         }
254                         set {
255                                 default_expr = value;
256                         }
257                 }
258
259                 public Location Location {
260                         get {
261                                 return loc;
262                         }
263                 }
264
265                 public TypeSpec Type {
266                         get {
267                                 return parameter_type;
268                         }
269                 }
270
271                 public FullNamedExpression TypeExpression  {
272                         get {
273                                 return texpr;
274                         }
275                 }
276
277                 public override string[] ValidAttributeTargets {
278                         get {
279                                 return attribute_targets;
280                         }
281                 }
282
283                 #endregion
284
285                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
286                 {
287                         if (a.Type == pa.In && ModFlags == Modifier.OUT) {
288                                 a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
289                                 return;
290                         }
291
292                         if (a.Type == pa.ParamArray) {
293                                 a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
294                                 return;
295                         }
296
297                         if (a.Type == pa.Out && (ModFlags & Modifier.REF) == Modifier.REF &&
298                             !OptAttributes.Contains (pa.In)) {
299                                 a.Report.Error (662, a.Location,
300                                         "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
301                                 return;
302                         }
303
304                         if (a.Type == pa.CLSCompliant) {
305                                 a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
306                         }
307
308                         if (HasDefaultValue && (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter)) {
309                                 a.Report.Error (1745, a.Location,
310                                         "Cannot specify `{0}' attribute on optional parameter `{1}'",
311                                         TypeManager.CSharpName (a.Type).Replace ("Attribute", ""), Name);
312                                 return;
313                         }
314
315                         if (a.Type == pa.DefaultParameterValue) {
316                                 TypeSpec arg_type;
317                                 var c = a.GetParameterDefaultValue (out arg_type);
318                                 if (c == null) {
319                                         if (parameter_type == TypeManager.object_type) {
320                                                 a.Report.Error (1910, a.Location, "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
321                                                         arg_type.GetSignatureForError ());
322                                         } else {
323                                                 a.Report.Error (1909, a.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
324                                                         parameter_type.GetSignatureForError ()); ;
325                                         }
326
327                                         return;
328                                 }
329
330                                 if (arg_type == parameter_type || parameter_type == TypeManager.object_type || 
331                                         (c.IsNull && TypeManager.IsReferenceType (parameter_type) && !TypeManager.IsGenericParameter (parameter_type)))
332                                         builder.SetConstant (c.GetValue ());
333                                 else
334                                         a.Report.Error (1908, a.Location, "The type of the default value should match the type of the parameter");
335
336                                 return;
337                         }
338
339                         base.ApplyAttributeBuilder (a, ctor, cdata, pa);
340                 }
341                 
342                 public virtual bool CheckAccessibility (InterfaceMemberBase member)
343                 {
344                         if (parameter_type == null)
345                                 return true;
346
347                         return member.IsAccessibleAs (parameter_type);
348                 }
349
350                 public static void Reset ()
351                 {
352                         parameter_expr_tree_type = null;
353                 }
354
355                 // <summary>
356                 //   Resolve is used in method definitions
357                 // </summary>
358                 public virtual TypeSpec Resolve (IMemberContext rc, int index)
359                 {
360                         if (parameter_type != null)
361                                 return parameter_type;
362
363                         if (attributes != null)
364                                 attributes.AttachTo (this, rc);
365
366                         var expr = texpr.ResolveAsTypeTerminal (rc, false);
367                         if (expr == null)
368                                 return null;
369
370                         this.idx = index;
371                         texpr = expr;
372                         parameter_type = texpr.Type;
373         
374                         if ((modFlags & Parameter.Modifier.ISBYREF) != 0 &&
375                                 TypeManager.IsSpecialType (parameter_type)) {
376                                 rc.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
377                                         GetSignatureForError ());
378                                 return null;
379                         }
380
381                         TypeManager.CheckTypeVariance (parameter_type,
382                                 (modFlags & Parameter.Modifier.ISBYREF) != 0 ? Variance.None : Variance.Contravariant,
383                                 rc);
384
385                         if (parameter_type.IsStatic) {
386                                 rc.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
387                                         texpr.GetSignatureForError ());
388                                 return parameter_type;
389                         }
390
391                         if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type == InternalType.Dynamic)) {
392                                 rc.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
393                                         TypeManager.CSharpName (parameter_type));
394                         }
395
396                         return parameter_type;
397                 }
398
399                 public void ResolveDefaultValue (ResolveContext rc)
400                 {
401                         //
402                         // Default value was specified using an expression
403                         //
404                         if (default_expr != null) {
405                                 default_expr = ResolveDefaultExpression (rc);
406                                 return;
407                         }
408
409                         if (attributes == null)
410                                 return;
411                         
412                         var pa = attributes.Search (rc.Module.PredefinedAttributes.OptionalParameter);
413                         if (pa == null)
414                                 return;
415
416                         //
417                         // Default value was specified using an attribute
418                         //
419                         attributes.Attrs.Remove (pa);
420
421                         TypeSpec expr_type = null;
422                         pa = attributes.Search (rc.Module.PredefinedAttributes.DefaultParameterValue);
423                         if (pa != null) {
424                                 attributes.Attrs.Remove (pa);
425                                 default_expr = pa.GetParameterDefaultValue (out expr_type);
426                         } else {
427                                 default_expr = EmptyExpression.MissingValue;
428                         }
429
430                         if (default_expr == null) {
431                                 if (expr_type == null)
432                                         expr_type = parameter_type;
433
434                                 default_expr = new DefaultValueExpression (new TypeExpression (expr_type, Location), Location);
435                         }
436
437                         default_expr = default_expr.Resolve (rc);
438                 }
439
440                 Expression ResolveDefaultExpression (ResolveContext rc)
441                 {
442                         default_expr = default_expr.Resolve (rc);
443                         if (default_expr == null)
444                                 return null;
445
446                         if (!(default_expr is Constant || default_expr is DefaultValueExpression || (default_expr is New && ((New)default_expr).IsDefaultStruct))) {
447                                 rc.Compiler.Report.Error (1736, default_expr.Location,
448                                         "The expression being assigned to optional parameter `{0}' must be a constant or default value",
449                                         Name);
450
451                                 return null;
452                         }
453
454                         if (default_expr.Type == parameter_type)
455                                 return default_expr;
456
457                         var res = Convert.ImplicitConversionStandard (rc, default_expr, parameter_type, default_expr.Location);
458                         if (res != null) {
459                                 if (TypeManager.IsNullableType (parameter_type) && res is Nullable.Wrap) {
460                                         Nullable.Wrap wrap = (Nullable.Wrap) res;
461                                         res = wrap.Child;
462                                         if (!(res is Constant)) {
463                                                 rc.Compiler.Report.Error (1770, default_expr.Location,
464                                                         "The expression being assigned to nullable optional parameter `{0}' must be default value",
465                                                         Name);
466                                                 return null;
467                                         }
468                                 }
469
470                                 if (!default_expr.IsNull && TypeManager.IsReferenceType (parameter_type) && parameter_type != TypeManager.string_type) {
471                                         rc.Compiler.Report.Error (1763, default_expr.Location,
472                                                 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
473                                                 Name, GetSignatureForError ());
474
475                                         return null;
476                                 }
477
478                                 return res;
479                         }
480
481                         rc.Compiler.Report.Error (1750, Location,
482                                 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
483                                 TypeManager.CSharpName (default_expr.Type), GetSignatureForError ());
484
485                         return null;
486                 }
487
488                 public bool HasDefaultValue {
489                         get { return default_expr != null; }
490                 }
491
492                 public bool HasExtensionMethodModifier {
493                         get { return (modFlags & Modifier.This) != 0; }
494                 }
495
496                 //
497                 // Hoisted parameter variant
498                 //
499                 public HoistedVariable HoistedVariant {
500                         get {
501                                 return hoisted_variant;
502                         }
503                         set {
504                                 hoisted_variant = value;
505                         }
506                 }
507
508                 public Modifier ModFlags {
509                         get { return modFlags & ~Modifier.This; }
510                 }
511
512                 public string Name {
513                         get { return name; }
514                         set { name = value; }
515                 }
516
517                 ParameterAttributes Attributes {
518                         get { return ParametersCompiled.GetParameterAttribute (modFlags) |
519                                 (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); }
520                 }
521
522                 public override AttributeTargets AttributeTargets {
523                         get {
524                                 return AttributeTargets.Parameter;
525                         }
526                 }
527
528                 public virtual string GetSignatureForError ()
529                 {
530                         string type_name;
531                         if (parameter_type != null)
532                                 type_name = TypeManager.CSharpName (parameter_type);
533                         else
534                                 type_name = texpr.GetSignatureForError ();
535
536                         string mod = GetModifierSignature (modFlags);
537                         if (mod.Length > 0)
538                                 return String.Concat (mod, " ", type_name);
539
540                         return type_name;
541                 }
542
543                 public static string GetModifierSignature (Modifier mod)
544                 {
545                         switch (mod) {
546                         case Modifier.OUT:
547                                 return "out";
548                         case Modifier.PARAMS:
549                                 return "params";
550                         case Modifier.REF:
551                                 return "ref";
552                         case Modifier.This:
553                                 return "this";
554                         default:
555                                 return "";
556                         }
557                 }
558
559                 public void IsClsCompliant (IMemberContext ctx)
560                 {
561                         if (parameter_type.IsCLSCompliant ())
562                                 return;
563
564                         ctx.Compiler.Report.Warning (3001, 1, Location,
565                                 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
566                 }
567
568                 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
569                 {
570                         if (builder != null)
571                                 throw new InternalErrorException ("builder already exists");
572
573                         if (mb == null)
574                                 builder = cb.DefineParameter (index, Attributes, Name);
575                         else
576                                 builder = mb.DefineParameter (index, Attributes, Name);
577
578                         if (OptAttributes != null)
579                                 OptAttributes.Emit ();
580
581                         if (HasDefaultValue) {
582                                 //
583                                 // Emit constant values for true constants only, the other
584                                 // constant-like expressions will rely on default value expression
585                                 //
586                                 Constant c = default_expr as Constant;
587                                 if (c != null) {
588                                         if (default_expr.Type == TypeManager.decimal_type) {
589                                                 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
590                                         } else {
591                                                 builder.SetConstant (c.GetValue ());
592                                         }
593                                 } else if (default_expr.Type.IsStruct) {
594                                         //
595                                         // Handles special case where default expression is used with value-type
596                                         //
597                                         // void Foo (S s = default (S)) {}
598                                         //
599                                         builder.SetConstant (null);
600                                 }
601                         }
602
603                         if (parameter_type != null) {
604                                 if (parameter_type == InternalType.Dynamic) {
605                                         pa.Dynamic.EmitAttribute (builder);
606                                 } else if (parameter_type.HasDynamicElement) {
607                                         pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
608                                 }
609                         }
610                 }
611
612                 public Parameter Clone ()
613                 {
614                         Parameter p = (Parameter) MemberwiseClone ();
615                         if (attributes != null)
616                                 p.attributes = attributes.Clone ();
617
618                         return p;
619                 }
620
621                 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
622                 {
623                         if ((modFlags & Modifier.ISBYREF) != 0)
624                                 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
625
626                         expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
627                         expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
628
629                         Arguments arguments = new Arguments (2);
630                         arguments.Add (new Argument (new TypeOf (
631                                 new TypeExpression (parameter_type, Location), Location)));
632                         arguments.Add (new Argument (new StringConstant (Name, Location)));
633                         return new SimpleAssign (ExpressionTreeVariableReference (),
634                                 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
635                 }
636
637                 public void Emit (EmitContext ec)
638                 {
639                         int arg_idx = idx;
640                         if (!ec.IsStatic)
641                                 arg_idx++;
642
643                         ParameterReference.EmitLdArg (ec, arg_idx);
644                 }
645
646                 public void EmitAssign (EmitContext ec)
647                 {
648                         int arg_idx = idx;
649                         if (!ec.IsStatic)
650                                 arg_idx++;
651
652                         if (arg_idx <= 255)
653                                 ec.Emit (OpCodes.Starg_S, (byte) arg_idx);
654                         else
655                                 ec.Emit (OpCodes.Starg, arg_idx);
656                 }
657
658                 public void EmitAddressOf (EmitContext ec)
659                 {
660                         int arg_idx = idx;
661
662                         if (!ec.IsStatic)
663                                 arg_idx++;
664
665                         bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
666                         if (is_ref) {
667                                 ParameterReference.EmitLdArg (ec, arg_idx);
668                         } else {
669                                 if (arg_idx <= 255)
670                                         ec.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
671                                 else
672                                         ec.Emit (OpCodes.Ldarga, arg_idx);
673                         }
674                 }
675
676                 public TemporaryVariableReference ExpressionTreeVariableReference ()
677                 {
678                         return expr_tree_variable;
679                 }
680
681                 //
682                 // System.Linq.Expressions.ParameterExpression type
683                 //
684                 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
685                 {
686                         if (parameter_expr_tree_type != null)
687                                 return parameter_expr_tree_type;
688
689                         TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve (location);
690                         parameter_expr_tree_type = new TypeExpression (p_type, location).
691                                 ResolveAsTypeTerminal (ec, false);
692
693                         return parameter_expr_tree_type;
694                 }
695
696                 public void Warning_UselessOptionalParameter (Report Report)
697                 {
698                         Report.Warning (1066, 1, Location,
699                                 "The default value specified for optional parameter `{0}' will never be used",
700                                 Name);
701                 }
702         }
703
704         //
705         // Imported or resolved parameter information
706         //
707         public class ParameterData : IParameterData
708         {
709                 readonly string name;
710                 readonly Parameter.Modifier modifiers;
711                 readonly Expression default_value;
712
713                 public ParameterData (string name, Parameter.Modifier modifiers)
714                 {
715                         this.name = name;
716                         this.modifiers = modifiers;
717                 }
718
719                 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
720                         : this (name, modifiers)
721                 {
722                         this.default_value = defaultValue;
723                 }
724
725                 #region IParameterData Members
726
727                 public Expression DefaultValue {
728                         get { return default_value; }
729                 }
730
731                 public bool HasExtensionMethodModifier {
732                         get { return (modifiers & Parameter.Modifier.This) != 0; }
733                 }
734
735                 public bool HasDefaultValue {
736                         get { return default_value != null; }
737                 }
738
739                 public Parameter.Modifier ModFlags {
740                         get { return modifiers & ~Parameter.Modifier.This; }
741                 }
742
743                 public string Name {
744                         get { return name; }
745                 }
746
747                 #endregion
748         }
749
750         public abstract class AParametersCollection
751         {
752                 protected bool has_arglist;
753                 protected bool has_params;
754
755                 // Null object pattern
756                 protected IParameterData [] parameters;
757                 protected TypeSpec [] types;
758
759                 public CallingConventions CallingConvention {
760                         get {
761                                 return has_arglist ?
762                                         CallingConventions.VarArgs :
763                                         CallingConventions.Standard;
764                         }
765                 }
766
767                 public int Count {
768                         get { return parameters.Length; }
769                 }
770
771                 public TypeSpec ExtensionMethodType {
772                         get {
773                                 if (Count == 0)
774                                         return null;
775
776                                 return FixedParameters [0].HasExtensionMethodModifier ?
777                                         types [0] : null;
778                         }
779                 }
780
781                 public IParameterData [] FixedParameters {
782                         get {
783                                 return parameters;
784                         }
785                 }
786
787                 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
788                 {
789                         return (modFlags & Parameter.Modifier.OUT) == Parameter.Modifier.OUT ?
790                                 ParameterAttributes.Out : ParameterAttributes.None;
791                 }
792
793                 // Very expensive operation
794                 public MetaType[] GetMetaInfo ()
795                 {
796                         MetaType[] types;
797                         if (has_arglist) {
798                                 if (Count == 1)
799                                         return MetaType.EmptyTypes;
800
801                                 types = new MetaType[Count - 1];
802                         } else {
803                                 if (Count == 0)
804                                         return MetaType.EmptyTypes;
805
806                                 types = new MetaType[Count];
807                         }
808
809                         for (int i = 0; i < types.Length; ++i) {
810                                 types[i] = Types[i].GetMetaInfo ();
811
812                                 if ((FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) == 0)
813                                         continue;
814
815                                 // TODO MemberCache: Should go to MetaInfo getter
816                                 types [i] = types [i].MakeByRefType ();
817                         }
818
819                         return types;
820                 }
821
822                 //
823                 // Returns the parameter information based on the name
824                 //
825                 public int GetParameterIndexByName (string name)
826                 {
827                         for (int idx = 0; idx < Count; ++idx) {
828                                 if (parameters [idx].Name == name)
829                                         return idx;
830                         }
831
832                         return -1;
833                 }
834
835                 public string GetSignatureForError ()
836                 {
837                         return GetSignatureForError ("(", ")", Count);
838                 }
839
840                 public string GetSignatureForError (string start, string end, int count)
841                 {
842                         StringBuilder sb = new StringBuilder (start);
843                         for (int i = 0; i < count; ++i) {
844                                 if (i != 0)
845                                         sb.Append (", ");
846                                 sb.Append (ParameterDesc (i));
847                         }
848                         sb.Append (end);
849                         return sb.ToString ();
850                 }
851
852                 public bool HasArglist {
853                         get { return has_arglist; }
854                 }
855
856                 public bool HasExtensionMethodType {
857                         get {
858                                 if (Count == 0)
859                                         return false;
860
861                                 return FixedParameters [0].HasExtensionMethodModifier;
862                         }
863                 }
864
865                 public bool HasParams {
866                         get { return has_params; }
867                 }
868
869                 public bool IsEmpty {
870                         get { return parameters.Length == 0; }
871                 }
872
873                 public AParametersCollection Inflate (TypeParameterInflator inflator)
874                 {
875                         TypeSpec[] inflated_types = null;
876                         bool default_value = false;
877
878                         for (int i = 0; i < Count; ++i) {
879                                 var inflated_param = inflator.Inflate (types[i]);
880                                 if (inflated_types == null) {
881                                         if (inflated_param == types[i])
882                                                 continue;
883
884                                         default_value |= FixedParameters[i] is DefaultValueExpression;
885                                         inflated_types = new TypeSpec[types.Length];
886                                         Array.Copy (types, inflated_types, types.Length);       
887                                 }
888
889                                 inflated_types[i] = inflated_param;
890                         }
891
892                         if (inflated_types == null)
893                                 return this;
894
895                         var clone = (AParametersCollection) MemberwiseClone ();
896                         clone.types = inflated_types;
897                         if (default_value) {
898                                 for (int i = 0; i < Count; ++i) {
899                                         var dve = clone.FixedParameters[i] as DefaultValueExpression;
900                                         if (dve != null) {
901                                                 throw new NotImplementedException ("net");
902                                                 //      clone.FixedParameters [i].DefaultValue = new DefaultValueExpression ();
903                                         }
904                                 }
905                         }
906
907                         return clone;
908                 }
909
910                 public string ParameterDesc (int pos)
911                 {
912                         if (types == null || types [pos] == null)
913                                 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
914
915                         string type = TypeManager.CSharpName (types [pos]);
916                         if (FixedParameters [pos].HasExtensionMethodModifier)
917                                 return "this " + type;
918
919                         Parameter.Modifier mod = FixedParameters [pos].ModFlags;
920                         if (mod == 0)
921                                 return type;
922
923                         return Parameter.GetModifierSignature (mod) + " " + type;
924                 }
925
926                 public TypeSpec[] Types {
927                         get { return types; }
928                         set { types = value; }
929                 }
930         }
931
932         //
933         // A collection of imported or resolved parameters
934         //
935         public class ParametersImported : AParametersCollection
936         {
937                 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
938                 {
939                         this.parameters = parameters;
940                         this.types = types;
941                         this.has_arglist = hasArglist;
942                         this.has_params = hasParams;
943                 }
944
945                 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
946                 {
947                         this.parameters = param;
948                         this.types = types;
949                         this.has_params = hasParams;
950                 }
951         }
952
953         /// <summary>
954         ///   Represents the methods parameters
955         /// </summary>
956         public class ParametersCompiled : AParametersCollection
957         {
958                 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
959                 
960                 // Used by C# 2.0 delegates
961                 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
962
963                 private ParametersCompiled ()
964                 {
965                         parameters = new Parameter [0];
966                         types = TypeSpec.EmptyTypes;
967                 }
968
969                 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
970                 {
971                         this.parameters = parameters;
972                     this.types = types;
973                 }
974                 
975                 public ParametersCompiled (params Parameter[] parameters)
976                 {
977                         if (parameters == null || parameters.Length == 0)
978                                 throw new ArgumentException ("Use EmptyReadOnlyParameters");
979
980                         this.parameters = parameters;
981                         int count = parameters.Length;
982
983                         for (int i = 0; i < count; i++){
984                                 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
985                         }
986                 }
987
988                 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
989                         this (parameters)
990                 {
991                         this.has_arglist = has_arglist;
992                 }
993                 
994                 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
995                 {
996                         return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
997                 }
998                 
999                 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1000                 {
1001                         return new ParametersCompiled (parameters, types);
1002                 }
1003
1004                 //
1005                 // TODO: This does not fit here, it should go to different version of AParametersCollection
1006                 // as the underlying type is not Parameter and some methods will fail to cast
1007                 //
1008                 public static AParametersCollection CreateFullyResolved (TypeSpec[] types)
1009                 {
1010                         var pd = new ParameterData [types.Length];
1011                         for (int i = 0; i < pd.Length; ++i)
1012                                 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1013
1014                         return new ParametersCompiled (pd, types);
1015                 }
1016
1017                 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1018                 {
1019                         return new ParametersCompiled (
1020                                 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1021                                 null);
1022                 }
1023
1024                 //
1025                 // Returns non-zero value for equal CLS parameter signatures
1026                 //
1027                 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1028                 {
1029                         int res = 0;
1030
1031                         for (int i = 0; i < a.Count; ++i) {
1032                                 var a_type = a.Types[i];
1033                                 var b_type = b.Types[i];
1034                                 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1035                                         const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
1036                                         if ((a.FixedParameters[i].ModFlags & ref_out) != (b.FixedParameters[i].ModFlags & ref_out))
1037                                                 res |= 1;
1038
1039                                         continue;
1040                                 }
1041
1042                                 var ac_a = a_type as ArrayContainer;
1043                                 if (ac_a == null)
1044                                         return 0;
1045
1046                                 var ac_b = b_type as ArrayContainer;
1047                                 if (ac_b == null)
1048                                         return 0;
1049
1050                                 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1051                                         res |= 2;
1052                                         continue;
1053                                 }
1054
1055                                 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1056                                         res |= 1;
1057                                         continue;
1058                                 }
1059
1060                                 return 0;
1061                         }
1062
1063                         return res;
1064                 }
1065
1066                 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1067                 {
1068                         return MergeGenerated (ctx, userParams, checkConflicts,
1069                                 new Parameter [] { compilerParams },
1070                                 new TypeSpec [] { compilerTypes });
1071                 }
1072
1073                 //
1074                 // Use this method when you merge compiler generated parameters with user parameters
1075                 //
1076                 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1077                 {
1078                         Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1079                         userParams.FixedParameters.CopyTo(all_params, 0);
1080
1081                         TypeSpec [] all_types;
1082                         if (userParams.types != null) {
1083                                 all_types = new TypeSpec [all_params.Length];
1084                                 userParams.Types.CopyTo (all_types, 0);
1085                         } else {
1086                                 all_types = null;
1087                         }
1088
1089                         int last_filled = userParams.Count;
1090                         int index = 0;
1091                         foreach (Parameter p in compilerParams) {
1092                                 for (int i = 0; i < last_filled; ++i) {
1093                                         while (p.Name == all_params [i].Name) {
1094                                                 if (checkConflicts && i < userParams.Count) {
1095                                                         ctx.Report.Error (316, userParams[i].Location,
1096                                                                 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1097                                                 }
1098                                                 p.Name = '_' + p.Name;
1099                                         }
1100                                 }
1101                                 all_params [last_filled] = p;
1102                                 if (all_types != null)
1103                                         all_types [last_filled] = compilerTypes [index++];
1104                                 ++last_filled;
1105                         }
1106                         
1107                         ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1108                         parameters.has_params = userParams.has_params;
1109                         return parameters;
1110                 }
1111
1112                 public bool Resolve (IMemberContext ec)
1113                 {
1114                         if (types != null)
1115                                 return true;
1116                         
1117                         types = new TypeSpec [Count];
1118                         
1119                         bool ok = true;
1120                         Parameter p;
1121                         for (int i = 0; i < FixedParameters.Length; ++i) {
1122                                 p = this [i];
1123                                 TypeSpec t = p.Resolve (ec, i);
1124                                 if (t == null) {
1125                                         ok = false;
1126                                         continue;
1127                                 }
1128
1129                                 types [i] = t;
1130                         }
1131
1132                         return ok;
1133                 }
1134
1135                 public void ResolveDefaultValues (MemberCore m)
1136                 {
1137                         ResolveContext rc = null;
1138                         for (int i = 0; i < parameters.Length; ++i) {
1139                                 Parameter p = (Parameter) parameters [i];
1140
1141                                 //
1142                                 // Try not to enter default values resolution if there are is not any default value possible
1143                                 //
1144                                 if (p.HasDefaultValue || p.OptAttributes != null) {
1145                                         if (rc == null)
1146                                                 rc = new ResolveContext (m);
1147
1148                                         p.ResolveDefaultValue (rc);
1149                                 }
1150                         }
1151                 }
1152
1153                 // Define each type attribute (in/out/ref) and
1154                 // the argument names.
1155                 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1156                 {
1157                         if (Count == 0)
1158                                 return;
1159
1160                         MethodBuilder mb = builder as MethodBuilder;
1161                         ConstructorBuilder cb = builder as ConstructorBuilder;
1162                         var pa = mc.Module.PredefinedAttributes;
1163
1164                         for (int i = 0; i < Count; i++) {
1165                                 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1166                         }
1167                 }
1168
1169                 public void VerifyClsCompliance (IMemberContext ctx)
1170                 {
1171                         foreach (Parameter p in FixedParameters)
1172                                 p.IsClsCompliant (ctx);
1173                 }
1174
1175                 public Parameter this [int pos] {
1176                         get { return (Parameter) parameters [pos]; }
1177                 }
1178
1179                 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1180                 {
1181                         var initializers = new ArrayInitializer (Count, loc);
1182                         foreach (Parameter p in FixedParameters) {
1183                                 //
1184                                 // Each parameter expression is stored to local variable
1185                                 // to save some memory when referenced later.
1186                                 //
1187                                 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec));
1188                                 if (se.Resolve (ec)) {
1189                                         ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1190                                         ec.CurrentBlock.AddScopeStatement (se);
1191                                 }
1192                                 
1193                                 initializers.Add (p.ExpressionTreeVariableReference ());
1194                         }
1195
1196                         return new ArrayCreation (
1197                                 Parameter.ResolveParameterExpressionType (ec, loc),
1198                                 initializers, loc);
1199                 }
1200
1201                 public ParametersCompiled Clone ()
1202                 {
1203                         ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1204
1205                         p.parameters = new IParameterData [parameters.Length];
1206                         for (int i = 0; i < Count; ++i)
1207                                 p.parameters [i] = this [i].Clone ();
1208
1209                         return p;
1210                 }
1211         }
1212 }