Facilitate the merge
[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 || (default_expr is New && ((New)default_expr).IsDefaultStruct))) {
468                                 rc.Compiler.Report.Error (1736, default_expr.Location,
469                                         "The expression being assigned to optional parameter `{0}' must be a constant or default value",
470                                         Name);
471
472                                 return null;
473                         }
474
475                         if (default_expr.Type == parameter_type)
476                                 return default_expr;
477
478                         if (TypeManager.IsNullableType (parameter_type)) {
479                                 if (default_expr.Type == InternalType.Null)
480                                         return default_expr;
481
482                                 var underlying = Nullable.NullableInfo.GetUnderlyingType (parameter_type);
483                                 var c = New.Constantify (underlying, Location.Null);
484                                 if (c == null) {
485                                         rc.Compiler.Report.Error (1770, default_expr.Location,
486                                                 "The expression being assigned to nullable optional parameter `{0}' must be default value",
487                                                 Name);
488                                         return null;
489                                 }
490
491                                 c = c.Resolve (rc);
492                                 if (c.Type == default_expr.Type)
493                                         return default_expr;
494                         } else {
495                                 var res = Convert.ImplicitConversionStandard (rc, default_expr, parameter_type, default_expr.Location);
496                                 if (res != null) {
497                                         if (!default_expr.IsNull && TypeManager.IsReferenceType (parameter_type) && parameter_type != TypeManager.string_type) {
498                                                 rc.Compiler.Report.Error (1763, default_expr.Location,
499                                                         "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
500                                                         Name, GetSignatureForError ());
501
502                                                 return null;
503                                         }
504
505                                         return res;
506                                 }
507                         }
508
509                         rc.Compiler.Report.Error (1750, Location,
510                                 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
511                                 TypeManager.CSharpName (default_expr.Type), GetSignatureForError ());
512
513                         return null;
514                 }
515
516                 public bool HasDefaultValue {
517                         get { return default_expr != null; }
518                 }
519
520                 public bool HasExtensionMethodModifier {
521                         get { return (modFlags & Modifier.This) != 0; }
522                 }
523
524                 //
525                 // Hoisted parameter variant
526                 //
527                 public HoistedVariable HoistedVariant {
528                         get {
529                                 return hoisted_variant;
530                         }
531                         set {
532                                 hoisted_variant = value;
533                         }
534                 }
535
536                 public Modifier ModFlags {
537                         get { return modFlags & ~Modifier.This; }
538                 }
539
540                 public string Name {
541                         get { return name; }
542                         set { name = value; }
543                 }
544
545                 ParameterAttributes Attributes {
546                         get { return ParametersCompiled.GetParameterAttribute (modFlags) |
547                                 (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); }
548                 }
549
550                 public override AttributeTargets AttributeTargets {
551                         get {
552                                 return AttributeTargets.Parameter;
553                         }
554                 }
555
556                 public virtual string GetSignatureForError ()
557                 {
558                         string type_name;
559                         if (parameter_type != null)
560                                 type_name = TypeManager.CSharpName (parameter_type);
561                         else
562                                 type_name = texpr.GetSignatureForError ();
563
564                         string mod = GetModifierSignature (modFlags);
565                         if (mod.Length > 0)
566                                 return String.Concat (mod, " ", type_name);
567
568                         return type_name;
569                 }
570
571                 public static string GetModifierSignature (Modifier mod)
572                 {
573                         switch (mod) {
574                         case Modifier.OUT:
575                                 return "out";
576                         case Modifier.PARAMS:
577                                 return "params";
578                         case Modifier.REF:
579                                 return "ref";
580                         case Modifier.This:
581                                 return "this";
582                         default:
583                                 return "";
584                         }
585                 }
586
587                 public void IsClsCompliant (IMemberContext ctx)
588                 {
589                         if (parameter_type.IsCLSCompliant ())
590                                 return;
591
592                         ctx.Compiler.Report.Warning (3001, 1, Location,
593                                 "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
594                 }
595
596                 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
597                 {
598                         if (mb == null)
599                                 builder = cb.DefineParameter (index, Attributes, Name);
600                         else
601                                 builder = mb.DefineParameter (index, Attributes, Name);
602
603                         if (OptAttributes != null)
604                                 OptAttributes.Emit ();
605
606                         if (HasDefaultValue) {
607                                 //
608                                 // Emit constant values for true constants only, the other
609                                 // constant-like expressions will rely on default value expression
610                                 //
611                                 Constant c = default_expr as Constant;
612                                 if (c != null) {
613                                         if (default_expr.Type == TypeManager.decimal_type) {
614                                                 builder.SetCustomAttribute (Const.CreateDecimalConstantAttribute (c, pa));
615                                         } else {
616                                                 builder.SetConstant (c.GetTypedValue ());
617                                         }
618                                 }
619                         }
620
621                         if (parameter_type == InternalType.Dynamic) {
622                                 pa.Dynamic.EmitAttribute (builder);
623                         } else {
624                                 var trans_flags = TypeManager.HasDynamicTypeUsed (parameter_type);
625                                 if (trans_flags != null) {
626                                         var dt = pa.DynamicTransform;
627                                         if (dt.Constructor != null || dt.ResolveConstructor (Location, ArrayContainer.MakeType (TypeManager.bool_type))) {
628                                                 builder.SetCustomAttribute (
629                                                         new CustomAttributeBuilder (dt.Constructor, new object [] { trans_flags }));
630                                         }
631                                 }
632                         }
633                 }
634
635                 public Parameter Clone ()
636                 {
637                         Parameter p = (Parameter) MemberwiseClone ();
638                         if (attributes != null)
639                                 p.attributes = attributes.Clone ();
640
641                         return p;
642                 }
643
644                 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
645                 {
646                         if ((modFlags & Modifier.ISBYREF) != 0)
647                                 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
648
649                         expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
650                         expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
651
652                         Arguments arguments = new Arguments (2);
653                         arguments.Add (new Argument (new TypeOf (
654                                 new TypeExpression (parameter_type, Location), Location)));
655                         arguments.Add (new Argument (new StringConstant (Name, Location)));
656                         return new SimpleAssign (ExpressionTreeVariableReference (),
657                                 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
658                 }
659
660                 public void Emit (EmitContext ec)
661                 {
662                         int arg_idx = idx;
663                         if (!ec.IsStatic)
664                                 arg_idx++;
665
666                         ParameterReference.EmitLdArg (ec, arg_idx);
667                 }
668
669                 public void EmitAssign (EmitContext ec)
670                 {
671                         int arg_idx = idx;
672                         if (!ec.IsStatic)
673                                 arg_idx++;
674
675                         if (arg_idx <= 255)
676                                 ec.Emit (OpCodes.Starg_S, (byte) arg_idx);
677                         else
678                                 ec.Emit (OpCodes.Starg, arg_idx);
679                 }
680
681                 public void EmitAddressOf (EmitContext ec)
682                 {
683                         int arg_idx = idx;
684
685                         if (!ec.IsStatic)
686                                 arg_idx++;
687
688                         bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
689                         if (is_ref) {
690                                 ParameterReference.EmitLdArg (ec, arg_idx);
691                         } else {
692                                 if (arg_idx <= 255)
693                                         ec.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
694                                 else
695                                         ec.Emit (OpCodes.Ldarga, arg_idx);
696                         }
697                 }
698
699                 public TemporaryVariableReference ExpressionTreeVariableReference ()
700                 {
701                         return expr_tree_variable;
702                 }
703
704                 //
705                 // System.Linq.Expressions.ParameterExpression type
706                 //
707                 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
708                 {
709                         if (parameter_expr_tree_type != null)
710                                 return parameter_expr_tree_type;
711
712                         TypeSpec p_type = TypeManager.parameter_expression_type;
713                         if (p_type == null) {
714                                 p_type = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "ParameterExpression", MemberKind.Class, true);
715                                 TypeManager.parameter_expression_type = p_type;
716                         }
717
718                         parameter_expr_tree_type = new TypeExpression (p_type, location).
719                                 ResolveAsTypeTerminal (ec, false);
720
721                         return parameter_expr_tree_type;
722                 }
723
724                 public void Warning_UselessOptionalParameter (Report Report)
725                 {
726                         Report.Warning (1066, 1, Location,
727                                 "The default value specified for optional parameter `{0}' will never be used",
728                                 Name);
729                 }
730         }
731
732         //
733         // Imported or resolved parameter information
734         //
735         public class ParameterData : IParameterData
736         {
737                 readonly string name;
738                 readonly Parameter.Modifier modifiers;
739                 readonly Expression default_value;
740
741                 public ParameterData (string name, Parameter.Modifier modifiers)
742                 {
743                         this.name = name;
744                         this.modifiers = modifiers;
745                 }
746
747                 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
748                         : this (name, modifiers)
749                 {
750                         this.default_value = defaultValue;
751                 }
752
753                 #region IParameterData Members
754
755                 public Expression DefaultValue {
756                         get { return default_value; }
757                 }
758
759                 public bool HasExtensionMethodModifier {
760                         get { return (modifiers & Parameter.Modifier.This) != 0; }
761                 }
762
763                 public bool HasDefaultValue {
764                         get { return default_value != null; }
765                 }
766
767                 public Parameter.Modifier ModFlags {
768                         get { return modifiers & ~Parameter.Modifier.This; }
769                 }
770
771                 public string Name {
772                         get { return name; }
773                 }
774
775                 #endregion
776         }
777
778         public abstract class AParametersCollection
779         {
780                 protected bool has_arglist;
781                 protected bool has_params;
782
783                 // Null object pattern
784                 protected IParameterData [] parameters;
785                 protected TypeSpec [] types;
786
787                 public CallingConventions CallingConvention {
788                         get {
789                                 return has_arglist ?
790                                         CallingConventions.VarArgs :
791                                         CallingConventions.Standard;
792                         }
793                 }
794
795                 public int Count {
796                         get { return parameters.Length; }
797                 }
798
799                 public TypeSpec ExtensionMethodType {
800                         get {
801                                 if (Count == 0)
802                                         return null;
803
804                                 return FixedParameters [0].HasExtensionMethodModifier ?
805                                         types [0] : null;
806                         }
807                 }
808
809                 public IParameterData [] FixedParameters {
810                         get {
811                                 return parameters;
812                         }
813                 }
814
815                 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
816                 {
817                         return (modFlags & Parameter.Modifier.OUT) == Parameter.Modifier.OUT ?
818                                 ParameterAttributes.Out : ParameterAttributes.None;
819                 }
820
821                 // Very expensive operation
822                 public Type[] GetMetaInfo ()
823                 {
824                         Type[] types;
825                         if (has_arglist) {
826                                 if (Count == 1)
827                                         return Type.EmptyTypes;
828
829                                 types = new Type [Count - 1];
830                         } else {
831                                 if (Count == 0)
832                                         return Type.EmptyTypes;
833
834                                 types = new Type [Count];
835                         }
836
837                         for (int i = 0; i < types.Length; ++i) {
838                                 types[i] = Types[i].GetMetaInfo ();
839
840                                 if ((FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) == 0)
841                                         continue;
842
843                                 // TODO MemberCache: Should go to MetaInfo getter
844                                 types [i] = types [i].MakeByRefType ();
845                         }
846
847                         return types;
848                 }
849
850                 //
851                 // Returns the parameter information based on the name
852                 //
853                 public int GetParameterIndexByName (string name)
854                 {
855                         for (int idx = 0; idx < Count; ++idx) {
856                                 if (parameters [idx].Name == name)
857                                         return idx;
858                         }
859
860                         return -1;
861                 }
862
863                 public string GetSignatureForError ()
864                 {
865                         return GetSignatureForError ("(", ")", Count);
866                 }
867
868                 public string GetSignatureForError (string start, string end, int count)
869                 {
870                         StringBuilder sb = new StringBuilder (start);
871                         for (int i = 0; i < count; ++i) {
872                                 if (i != 0)
873                                         sb.Append (", ");
874                                 sb.Append (ParameterDesc (i));
875                         }
876                         sb.Append (end);
877                         return sb.ToString ();
878                 }
879
880                 public bool HasArglist {
881                         get { return has_arglist; }
882                 }
883
884                 public bool HasExtensionMethodType {
885                         get {
886                                 if (Count == 0)
887                                         return false;
888
889                                 return FixedParameters [0].HasExtensionMethodModifier;
890                         }
891                 }
892
893                 public bool HasParams {
894                         get { return has_params; }
895                 }
896
897                 public bool IsEmpty {
898                         get { return parameters.Length == 0; }
899                 }
900
901                 public AParametersCollection Inflate (TypeParameterInflator inflator)
902                 {
903                         TypeSpec[] inflated_types = null;
904                         bool default_value = false;
905
906                         for (int i = 0; i < Count; ++i) {
907                                 var inflated_param = inflator.Inflate (types[i]);
908                                 if (inflated_types == null) {
909                                         if (inflated_param == types[i])
910                                                 continue;
911
912                                         default_value |= FixedParameters[i] is DefaultValueExpression;
913                                         inflated_types = new TypeSpec[types.Length];
914                                         Array.Copy (types, inflated_types, types.Length);       
915                                 }
916
917                                 inflated_types[i] = inflated_param;
918                         }
919
920                         if (inflated_types == null)
921                                 return this;
922
923                         var clone = (AParametersCollection) MemberwiseClone ();
924                         clone.types = inflated_types;
925                         if (default_value) {
926                                 for (int i = 0; i < Count; ++i) {
927                                         var dve = clone.FixedParameters[i] as DefaultValueExpression;
928                                         if (dve != null) {
929                                                 throw new NotImplementedException ("net");
930                                                 //      clone.FixedParameters [i].DefaultValue = new DefaultValueExpression ();
931                                         }
932                                 }
933                         }
934
935                         return clone;
936                 }
937
938                 public string ParameterDesc (int pos)
939                 {
940                         if (types == null || types [pos] == null)
941                                 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
942
943                         string type = TypeManager.CSharpName (types [pos]);
944                         if (FixedParameters [pos].HasExtensionMethodModifier)
945                                 return "this " + type;
946
947                         Parameter.Modifier mod = FixedParameters [pos].ModFlags;
948                         if (mod == 0)
949                                 return type;
950
951                         return Parameter.GetModifierSignature (mod) + " " + type;
952                 }
953
954                 public TypeSpec[] Types {
955                         get { return types; }
956                         set { types = value; }
957                 }
958         }
959
960         //
961         // A collection of imported or resolved parameters
962         //
963         public class ParametersImported : AParametersCollection
964         {
965                 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
966                 {
967                         this.parameters = parameters;
968                         this.types = types;
969                         this.has_arglist = hasArglist;
970                         this.has_params = hasParams;
971                 }
972
973                 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
974                 {
975                         this.parameters = param;
976                         this.types = types;
977                         this.has_params = hasParams;
978                 }
979         }
980
981         /// <summary>
982         ///   Represents the methods parameters
983         /// </summary>
984         public class ParametersCompiled : AParametersCollection
985         {
986                 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
987                 
988                 // Used by C# 2.0 delegates
989                 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
990
991                 private ParametersCompiled ()
992                 {
993                         parameters = new Parameter [0];
994                         types = TypeSpec.EmptyTypes;
995                 }
996
997                 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
998                 {
999                         this.parameters = parameters;
1000                     this.types = types;
1001                 }
1002                 
1003                 public ParametersCompiled (params Parameter[] parameters)
1004                 {
1005                         if (parameters == null || parameters.Length == 0)
1006                                 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1007
1008                         this.parameters = parameters;
1009                         int count = parameters.Length;
1010
1011                         for (int i = 0; i < count; i++){
1012                                 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1013                         }
1014                 }
1015
1016                 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1017                         this (parameters)
1018                 {
1019                         this.has_arglist = has_arglist;
1020                 }
1021                 
1022                 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1023                 {
1024                         return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1025                 }
1026                 
1027                 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1028                 {
1029                         return new ParametersCompiled (parameters, types);
1030                 }
1031
1032                 //
1033                 // TODO: This does not fit here, it should go to different version of AParametersCollection
1034                 // as the underlying type is not Parameter and some methods will fail to cast
1035                 //
1036                 public static AParametersCollection CreateFullyResolved (TypeSpec[] types)
1037                 {
1038                         var pd = new ParameterData [types.Length];
1039                         for (int i = 0; i < pd.Length; ++i)
1040                                 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1041
1042                         return new ParametersCompiled (pd, types);
1043                 }
1044
1045                 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1046                 {
1047                         return new ParametersCompiled (
1048                                 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1049                                 null);
1050                 }
1051
1052                 //
1053                 // Returns non-zero value for equal CLS parameter signatures
1054                 //
1055                 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1056                 {
1057                         int res = 0;
1058
1059                         for (int i = 0; i < a.Count; ++i) {
1060                                 var a_type = a.Types[i];
1061                                 var b_type = b.Types[i];
1062                                 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1063                                         const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
1064                                         if ((a.FixedParameters[i].ModFlags & ref_out) != (b.FixedParameters[i].ModFlags & ref_out))
1065                                                 res |= 1;
1066
1067                                         continue;
1068                                 }
1069
1070                                 var ac_a = a_type as ArrayContainer;
1071                                 if (ac_a == null)
1072                                         return 0;
1073
1074                                 var ac_b = b_type as ArrayContainer;
1075                                 if (ac_b == null)
1076                                         return 0;
1077
1078                                 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1079                                         res |= 2;
1080                                         continue;
1081                                 }
1082
1083                                 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1084                                         res |= 1;
1085                                         continue;
1086                                 }
1087
1088                                 return 0;
1089                         }
1090
1091                         return res;
1092                 }
1093
1094                 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1095                 {
1096                         return MergeGenerated (ctx, userParams, checkConflicts,
1097                                 new Parameter [] { compilerParams },
1098                                 new TypeSpec [] { compilerTypes });
1099                 }
1100
1101                 //
1102                 // Use this method when you merge compiler generated parameters with user parameters
1103                 //
1104                 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1105                 {
1106                         Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1107                         userParams.FixedParameters.CopyTo(all_params, 0);
1108
1109                         TypeSpec [] all_types;
1110                         if (userParams.types != null) {
1111                                 all_types = new TypeSpec [all_params.Length];
1112                                 userParams.Types.CopyTo (all_types, 0);
1113                         } else {
1114                                 all_types = null;
1115                         }
1116
1117                         int last_filled = userParams.Count;
1118                         int index = 0;
1119                         foreach (Parameter p in compilerParams) {
1120                                 for (int i = 0; i < last_filled; ++i) {
1121                                         while (p.Name == all_params [i].Name) {
1122                                                 if (checkConflicts && i < userParams.Count) {
1123                                                         ctx.Report.Error (316, userParams[i].Location,
1124                                                                 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1125                                                 }
1126                                                 p.Name = '_' + p.Name;
1127                                         }
1128                                 }
1129                                 all_params [last_filled] = p;
1130                                 if (all_types != null)
1131                                         all_types [last_filled] = compilerTypes [index++];
1132                                 ++last_filled;
1133                         }
1134                         
1135                         ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1136                         parameters.has_params = userParams.has_params;
1137                         return parameters;
1138                 }
1139
1140                 public bool Resolve (IMemberContext ec)
1141                 {
1142                         if (types != null)
1143                                 return true;
1144                         
1145                         types = new TypeSpec [Count];
1146                         
1147                         bool ok = true;
1148                         Parameter p;
1149                         for (int i = 0; i < FixedParameters.Length; ++i) {
1150                                 p = this [i];
1151                                 TypeSpec t = p.Resolve (ec, i);
1152                                 if (t == null) {
1153                                         ok = false;
1154                                         continue;
1155                                 }
1156
1157                                 types [i] = t;
1158                         }
1159
1160                         return ok;
1161                 }
1162
1163                 public void ResolveDefaultValues (MemberCore m)
1164                 {
1165                         var count = parameters.Length;
1166
1167                         //
1168                         // Try not to enter default values resolution if there are not any
1169                         //
1170                         if (parameters[count - 1].HasDefaultValue || (HasParams && count > 1 && parameters[count - 2].HasDefaultValue) ||
1171                                 ((Parameter) parameters[count - 1]).OptAttributes != null) {
1172                                 var rc = new ResolveContext (m);
1173                                 for (int i = 0; i < count; ++i) {
1174                                         this [i].ResolveDefaultValue (rc);
1175                                 }
1176                         }
1177                 }
1178
1179                 // Define each type attribute (in/out/ref) and
1180                 // the argument names.
1181                 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1182                 {
1183                         if (Count == 0)
1184                                 return;
1185
1186                         MethodBuilder mb = builder as MethodBuilder;
1187                         ConstructorBuilder cb = builder as ConstructorBuilder;
1188                         var pa = mc.Compiler.PredefinedAttributes;
1189
1190                         for (int i = 0; i < Count; i++) {
1191                                 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1192                         }
1193                 }
1194
1195                 public void VerifyClsCompliance (IMemberContext ctx)
1196                 {
1197                         foreach (Parameter p in FixedParameters)
1198                                 p.IsClsCompliant (ctx);
1199                 }
1200
1201                 public Parameter this [int pos] {
1202                         get { return (Parameter) parameters [pos]; }
1203                 }
1204
1205                 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1206                 {
1207                         var initializers = new ArrayInitializer (Count, loc);
1208                         foreach (Parameter p in FixedParameters) {
1209                                 //
1210                                 // Each parameter expression is stored to local variable
1211                                 // to save some memory when referenced later.
1212                                 //
1213                                 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec));
1214                                 if (se.Resolve (ec)) {
1215                                         ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1216                                         ec.CurrentBlock.AddScopeStatement (se);
1217                                 }
1218                                 
1219                                 initializers.Add (p.ExpressionTreeVariableReference ());
1220                         }
1221
1222                         return new ArrayCreation (
1223                                 Parameter.ResolveParameterExpressionType (ec, loc),
1224                                 initializers, loc);
1225                 }
1226
1227                 public ParametersCompiled Clone ()
1228                 {
1229                         ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1230
1231                         p.parameters = new IParameterData [parameters.Length];
1232                         for (int i = 0; i < Count; ++i)
1233                                 p.parameters [i] = this [i].Clone ();
1234
1235                         return p;
1236                 }
1237         }
1238 }