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