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