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