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