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