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