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