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