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