Merge pull request #1162 from DavidKarlas/endInvokeWithResult
[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                         PARAMS  = 1 << 0,
213                         REF = 1 << 1,
214                         OUT = 1 << 2,
215                         This = 1 << 3,
216                         CallerMemberName = 1 << 4,
217                         CallerLineNumber = 1 << 5,
218                         CallerFilePath = 1 << 6,
219
220                         RefOutMask = REF | OUT,
221                         ModifierMask = PARAMS | REF | OUT | This,
222                         CallerMask = CallerMemberName | CallerLineNumber | CallerFilePath
223                 }
224
225                 static readonly string[] attribute_targets = new string[] { "param" };
226                 static readonly string[] attribute_targets_primary = new string[] { "param", "field" };
227
228                 FullNamedExpression texpr;
229                 Modifier modFlags;
230                 string name;
231                 Expression default_expr;
232                 protected TypeSpec parameter_type;
233                 readonly Location loc;
234                 protected int idx;
235                 public bool HasAddressTaken;
236
237                 Constructor primary_constructor;
238                 TemporaryVariableReference expr_tree_variable;
239
240                 HoistedParameter hoisted_variant;
241
242                 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
243                 {
244                         this.name = name;
245                         modFlags = mod;
246                         this.loc = loc;
247                         texpr = type;
248
249                         // Only assign, attributes will be attached during resolve
250                         base.attributes = attrs;
251                 }
252
253                 #region Properties
254
255                 public Expression DefaultExpression {
256                         get {
257                                 return default_expr;
258                         }
259                 }
260
261                 public DefaultParameterValueExpression DefaultValue {
262                         get {
263                                 return default_expr as DefaultParameterValueExpression;
264                         }
265                         set {
266                                 default_expr = value;
267                         }
268                 }
269
270                 Expression IParameterData.DefaultValue {
271                         get {
272                                 var expr = default_expr as DefaultParameterValueExpression;
273                                 return expr == null ? default_expr : expr.Child;
274                         }
275                 }
276
277                 bool HasOptionalExpression {
278                         get {
279                                 return default_expr is DefaultParameterValueExpression;
280                         }
281                 }
282
283                 public Location Location {
284                         get {
285                                 return loc;
286                         }
287                 }
288
289                 public Modifier ParameterModifier {
290                         get {
291                                 return modFlags;
292                         }
293                 }
294
295                 public TypeSpec Type {
296                         get {
297                                 return parameter_type;
298                         }
299                         set {
300                                 parameter_type = value;
301                         }
302                 }
303
304                 public FullNamedExpression TypeExpression  {
305                         get {
306                                 return texpr;
307                         }
308                 }
309
310                 public override string[] ValidAttributeTargets {
311                         get {
312                                 return primary_constructor != null ? attribute_targets_primary : attribute_targets;
313                         }
314                 }
315
316                 #endregion
317
318                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
319                 {
320                         if (a.Target == AttributeTargets.Field) {
321                                 var field = MemberCache.FindMember (primary_constructor.Spec.DeclaringType, MemberFilter.Field (name, parameter_type), BindingRestriction.DeclaredOnly);
322                                 ((Field)field.MemberDefinition).ApplyAttributeBuilder (a, ctor, cdata, pa);
323                                 return;
324                         }
325
326                         if (a.Type == pa.In && ModFlags == Modifier.OUT) {
327                                 a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
328                                 return;
329                         }
330
331                         if (a.Type == pa.ParamArray) {
332                                 a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
333                                 return;
334                         }
335
336                         if (a.Type == pa.Out && (ModFlags & Modifier.REF) != 0 &&
337                             !OptAttributes.Contains (pa.In)) {
338                                 a.Report.Error (662, a.Location,
339                                         "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
340                                 return;
341                         }
342
343                         if (a.Type == pa.CLSCompliant) {
344                                 a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
345                         } else if (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter) {
346                                 if (HasOptionalExpression) {
347                                         a.Report.Error (1745, a.Location,
348                                                 "Cannot specify `{0}' attribute on optional parameter `{1}'",
349                                                 a.Type.GetSignatureForError ().Replace ("Attribute", ""), Name);
350                                 }
351
352                                 if (a.Type == pa.DefaultParameterValue)
353                                         return;
354                         } else if (a.Type == pa.CallerMemberNameAttribute) {
355                                 if ((modFlags & Modifier.CallerMemberName) == 0) {
356                                         a.Report.Error (4022, a.Location,
357                                                 "The CallerMemberName attribute can only be applied to parameters with default value");
358                                 }
359                         } else if (a.Type == pa.CallerLineNumberAttribute) {
360                                 if ((modFlags & Modifier.CallerLineNumber) == 0) {
361                                         a.Report.Error (4020, a.Location,
362                                                 "The CallerLineNumber attribute can only be applied to parameters with default value");
363                                 }
364                         } else if (a.Type == pa.CallerFilePathAttribute) {
365                                 if ((modFlags & Modifier.CallerFilePath) == 0) {
366                                         a.Report.Error (4021, a.Location,
367                                                 "The CallerFilePath attribute can only be applied to parameters with default value");
368                                 }
369                         }
370
371                         base.ApplyAttributeBuilder (a, ctor, cdata, pa);
372                 }
373                 
374                 public virtual bool CheckAccessibility (InterfaceMemberBase member)
375                 {
376                         if (parameter_type == null)
377                                 return true;
378
379                         return member.IsAccessibleAs (parameter_type);
380                 }
381
382                 bool IsValidCallerContext (MemberCore memberContext)
383                 {
384                         var m = memberContext as Method;
385                         if (m != null)
386                                 return !m.IsPartialImplementation;
387
388                         return true;
389                 }
390
391                 // <summary>
392                 //   Resolve is used in method definitions
393                 // </summary>
394                 public virtual TypeSpec Resolve (IMemberContext rc, int index)
395                 {
396                         if (parameter_type != null)
397                                 return parameter_type;
398
399                         if (attributes != null)
400                                 attributes.AttachTo (this, rc);
401
402                         var ctor = rc.CurrentMemberDefinition as Constructor;
403                         if (ctor != null && ctor.IsPrimaryConstructor)
404                                 primary_constructor = ctor;
405
406                         parameter_type = texpr.ResolveAsType (rc);
407                         if (parameter_type == null)
408                                 return null;
409
410                         this.idx = index;
411
412                         if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
413                                 rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
414                                         GetSignatureForError ());
415                                 return null;
416                         }
417
418                         VarianceDecl.CheckTypeVariance (parameter_type,
419                                 (modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
420                                 rc);
421
422                         if (parameter_type.IsStatic) {
423                                 rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
424                                         texpr.GetSignatureForError ());
425                                 return parameter_type;
426                         }
427
428                         if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
429                                 rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
430                                         parameter_type.GetSignatureForError ());
431                         }
432
433                         return parameter_type;
434                 }
435
436                 void ResolveCallerAttributes (ResolveContext rc)
437                 {
438                         var pa = rc.Module.PredefinedAttributes;
439                         TypeSpec caller_type;
440                         Attribute callerMemberName = null, callerFilePath = null;
441
442                         foreach (var attr in attributes.Attrs) {
443                                 var atype = attr.ResolveTypeForComparison ();
444                                 if (atype == null)
445                                         continue;
446
447                                 if (atype == pa.CallerMemberNameAttribute) {
448                                         caller_type = rc.BuiltinTypes.String;
449                                         if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
450                                                 rc.Report.Error (4019, attr.Location,
451                                                         "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
452                                                         caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
453                                         }
454
455                                         if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
456                                                 rc.Report.Warning (4026, 1, attr.Location,
457                                                         "The CallerMemberName applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
458                                                         name);
459                                         }
460
461                                         modFlags |= Modifier.CallerMemberName;
462                                         callerMemberName = attr;
463                                         continue;
464                                 }
465
466                                 if (atype == pa.CallerLineNumberAttribute) {
467                                         caller_type = rc.BuiltinTypes.Int;
468                                         if (caller_type != parameter_type && !Convert.ImplicitStandardConversionExists (new IntConstant (caller_type, int.MaxValue, Location.Null), parameter_type)) {
469                                                 rc.Report.Error (4017, attr.Location,
470                                                         "The CallerLineNumberAttribute attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
471                                                         caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
472                                         }
473
474                                         if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
475                                                 rc.Report.Warning (4024, 1, attr.Location,
476                                                         "The CallerLineNumberAttribute applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
477                                                         name);
478                                         }
479
480                                         modFlags |= Modifier.CallerLineNumber;
481                                         continue;
482                                 }
483
484                                 if (atype == pa.CallerFilePathAttribute) {
485                                         caller_type = rc.BuiltinTypes.String;
486                                         if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
487                                                 rc.Report.Error (4018, attr.Location,
488                                                         "The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
489                                                         caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
490                                         }
491
492                                         if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
493                                                 rc.Report.Warning (4025, 1, attr.Location,
494                                                         "The CallerFilePath applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
495                                                         name);
496                                         }
497
498                                         modFlags |= Modifier.CallerFilePath;
499                                         callerFilePath = attr;
500                                         continue;
501                                 }
502                         }
503
504                         if ((modFlags & Modifier.CallerLineNumber) != 0) {
505                                 if (callerMemberName != null) {
506                                         rc.Report.Warning (7081, 1, callerMemberName.Location,
507                                                 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
508                                                 Name);
509                                 }
510
511                                 if (callerFilePath != null) {
512                                         rc.Report.Warning (7082, 1, callerFilePath.Location,
513                                                 "The CallerFilePathAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
514                                                 name);
515                                 }
516                         }
517
518                         if ((modFlags & Modifier.CallerMemberName) != 0) {
519                                 if (callerFilePath != null) {
520                                         rc.Report.Warning (7080, 1, callerFilePath.Location,
521                                                 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerFilePathAttribute",
522                                                 name);
523                                 }
524
525                         }
526                 }
527
528                 public void ResolveDefaultValue (ResolveContext rc)
529                 {
530                         //
531                         // Default value was specified using an expression
532                         //
533                         if (default_expr != null) {
534                                 ((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
535                                 if (attributes != null)
536                                         ResolveCallerAttributes (rc);
537
538                                 return;
539                         }
540
541                         if (attributes == null)
542                                 return;
543
544                         var pa = rc.Module.PredefinedAttributes;
545                         var def_attr = attributes.Search (pa.DefaultParameterValue);
546                         if (def_attr != null) {
547                                 if (def_attr.Resolve () == null)
548                                         return;
549
550                                 var default_expr_attr = def_attr.GetParameterDefaultValue ();
551                                 if (default_expr_attr == null)
552                                         return;
553
554                                 var dpa_rc = def_attr.CreateResolveContext ();
555                                 default_expr = default_expr_attr.Resolve (dpa_rc);
556
557                                 if (default_expr is BoxedCast)
558                                         default_expr = ((BoxedCast) default_expr).Child;
559
560                                 Constant c = default_expr as Constant;
561                                 if (c == null) {
562                                         if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
563                                                 rc.Report.Error (1910, default_expr.Location,
564                                                         "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
565                                                         default_expr.Type.GetSignatureForError ());
566                                         } else {
567                                                 rc.Report.Error (1909, default_expr.Location,
568                                                         "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
569                                                         default_expr.Type.GetSignatureForError ());
570                                         }
571
572                                         default_expr = null;
573                                         return;
574                                 }
575
576                                 if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
577                                         (default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
578                                         parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
579                                         return;
580                                 }
581
582                                 //
583                                 // LAMESPEC: Some really weird csc behaviour which we have to mimic
584                                 // User operators returning same type as parameter type are considered
585                                 // valid for this attribute only
586                                 //
587                                 // struct S { public static implicit operator S (int i) {} }
588                                 //
589                                 // void M ([DefaultParameterValue (3)]S s)
590                                 //
591                                 var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
592                                 if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
593                                         return;
594                                 }
595                                 
596                                 rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
597                                 return;
598                         }
599
600                         var opt_attr = attributes.Search (pa.OptionalParameter);
601                         if (opt_attr != null) {
602                                 default_expr = EmptyExpression.MissingValue;
603                         }
604                 }
605
606                 public bool HasDefaultValue {
607                         get { return default_expr != null; }
608                 }
609
610                 public bool HasExtensionMethodModifier {
611                         get { return (modFlags & Modifier.This) != 0; }
612                 }
613
614                 //
615                 // Hoisted parameter variant
616                 //
617                 public HoistedParameter HoistedVariant {
618                         get {
619                                 return hoisted_variant;
620                         }
621                         set {
622                                 hoisted_variant = value;
623                         }
624                 }
625
626                 public Modifier ModFlags {
627                         get { return modFlags & ~Modifier.This; }
628                 }
629
630                 public string Name {
631                         get { return name; }
632                         set { name = value; }
633                 }
634
635                 public override AttributeTargets AttributeTargets {
636                         get {
637                                 return AttributeTargets.Parameter;
638                         }
639                 }
640
641                 public void Error_DuplicateName (Report r)
642                 {
643                         r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
644                 }
645
646                 public virtual string GetSignatureForError ()
647                 {
648                         string type_name;
649                         if (parameter_type != null)
650                                 type_name = parameter_type.GetSignatureForError ();
651                         else
652                                 type_name = texpr.GetSignatureForError ();
653
654                         string mod = GetModifierSignature (modFlags);
655                         if (mod.Length > 0)
656                                 return String.Concat (mod, " ", type_name);
657
658                         return type_name;
659                 }
660
661                 public static string GetModifierSignature (Modifier mod)
662                 {
663                         switch (mod) {
664                         case Modifier.OUT:
665                                 return "out";
666                         case Modifier.PARAMS:
667                                 return "params";
668                         case Modifier.REF:
669                                 return "ref";
670                         case Modifier.This:
671                                 return "this";
672                         default:
673                                 return "";
674                         }
675                 }
676
677                 public void IsClsCompliant (IMemberContext ctx)
678                 {
679                         if (parameter_type.IsCLSCompliant ())
680                                 return;
681
682                         ctx.Module.Compiler.Report.Warning (3001, 1, Location,
683                                 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
684                 }
685
686                 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
687                 {
688                         if (builder != null)
689                                 throw new InternalErrorException ("builder already exists");
690
691                         var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
692                         if (HasOptionalExpression)
693                                 pattrs |= ParameterAttributes.Optional;
694
695                         if (mb == null)
696                                 builder = cb.DefineParameter (index, pattrs, Name);
697                         else
698                                 builder = mb.DefineParameter (index, pattrs, Name);
699
700                         if (OptAttributes != null)
701                                 OptAttributes.Emit ();
702
703                         if (HasDefaultValue && default_expr.Type != null) {
704                                 //
705                                 // Emit constant values for true constants only, the other
706                                 // constant-like expressions will rely on default value expression
707                                 //
708                                 var def_value = DefaultValue;
709                                 Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
710                                 if (c != null) {
711                                         if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
712                                                 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
713                                         } else {
714                                                 builder.SetConstant (c.GetValue ());
715                                         }
716                                 } else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
717                                         //
718                                         // Handles special case where default expression is used with value-type or type parameter
719                                         //
720                                         // void Foo (S s = default (S)) {}
721                                         //
722                                         builder.SetConstant (null);
723                                 }
724                         }
725
726                         if (parameter_type != null) {
727                                 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
728                                         pa.Dynamic.EmitAttribute (builder);
729                                 } else if (parameter_type.HasDynamicElement) {
730                                         pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
731                                 }
732                         }
733                 }
734
735                 public Parameter Clone ()
736                 {
737                         Parameter p = (Parameter) MemberwiseClone ();
738                         if (attributes != null)
739                                 p.attributes = attributes.Clone ();
740
741                         return p;
742                 }
743
744                 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
745                 {
746                         if ((modFlags & Modifier.RefOutMask) != 0)
747                                 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
748
749                         expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
750                         expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
751
752                         Arguments arguments = new Arguments (2);
753                         arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
754                         arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
755                         return new SimpleAssign (ExpressionTreeVariableReference (),
756                                 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
757                 }
758
759                 public void Emit (EmitContext ec)
760                 {
761                         ec.EmitArgumentLoad (idx);
762                 }
763
764                 public void EmitAssign (EmitContext ec)
765                 {
766                         ec.EmitArgumentStore (idx);
767                 }
768
769                 public void EmitAddressOf (EmitContext ec)
770                 {
771                         if ((ModFlags & Modifier.RefOutMask) != 0) {
772                                 ec.EmitArgumentLoad (idx);
773                         } else {
774                                 ec.EmitArgumentAddress (idx);
775                         }
776                 }
777
778                 public TemporaryVariableReference ExpressionTreeVariableReference ()
779                 {
780                         return expr_tree_variable;
781                 }
782
783                 //
784                 // System.Linq.Expressions.ParameterExpression type
785                 //
786                 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
787                 {
788                         TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
789                         return new TypeExpression (p_type, location);
790                 }
791
792                 public void SetIndex (int index)
793                 {
794                         idx = index;
795                 }
796
797                 public void Warning_UselessOptionalParameter (Report Report)
798                 {
799                         Report.Warning (1066, 1, Location,
800                                 "The default value specified for optional parameter `{0}' will never be used",
801                                 Name);
802                 }
803         }
804
805         //
806         // Imported or resolved parameter information
807         //
808         public class ParameterData : IParameterData
809         {
810                 readonly string name;
811                 readonly Parameter.Modifier modifiers;
812                 readonly Expression default_value;
813
814                 public ParameterData (string name, Parameter.Modifier modifiers)
815                 {
816                         this.name = name;
817                         this.modifiers = modifiers;
818                 }
819
820                 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
821                         : this (name, modifiers)
822                 {
823                         this.default_value = defaultValue;
824                 }
825
826                 #region IParameterData Members
827
828                 public Expression DefaultValue {
829                         get { return default_value; }
830                 }
831
832                 public bool HasExtensionMethodModifier {
833                         get { return (modifiers & Parameter.Modifier.This) != 0; }
834                 }
835
836                 public bool HasDefaultValue {
837                         get { return default_value != null; }
838                 }
839
840                 public Parameter.Modifier ModFlags {
841                         get { return modifiers; }
842                 }
843
844                 public string Name {
845                         get { return name; }
846                 }
847
848                 #endregion
849         }
850
851         public abstract class AParametersCollection
852         {
853                 protected bool has_arglist;
854                 protected bool has_params;
855
856                 // Null object pattern
857                 protected IParameterData [] parameters;
858                 protected TypeSpec [] types;
859
860                 public CallingConventions CallingConvention {
861                         get {
862                                 return has_arglist ?
863                                         CallingConventions.VarArgs :
864                                         CallingConventions.Standard;
865                         }
866                 }
867
868                 public int Count {
869                         get { return parameters.Length; }
870                 }
871
872                 public TypeSpec ExtensionMethodType {
873                         get {
874                                 if (Count == 0)
875                                         return null;
876
877                                 return FixedParameters [0].HasExtensionMethodModifier ?
878                                         types [0] : null;
879                         }
880                 }
881
882                 public IParameterData [] FixedParameters {
883                         get {
884                                 return parameters;
885                         }
886                 }
887
888                 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
889                 {
890                         return (modFlags & Parameter.Modifier.OUT) != 0 ?
891                                 ParameterAttributes.Out : ParameterAttributes.None;
892                 }
893
894                 // Very expensive operation
895                 public MetaType[] GetMetaInfo ()
896                 {
897                         MetaType[] types;
898                         if (has_arglist) {
899                                 if (Count == 1)
900                                         return MetaType.EmptyTypes;
901
902                                 types = new MetaType[Count - 1];
903                         } else {
904                                 if (Count == 0)
905                                         return MetaType.EmptyTypes;
906
907                                 types = new MetaType[Count];
908                         }
909
910                         for (int i = 0; i < types.Length; ++i) {
911                                 types[i] = Types[i].GetMetaInfo ();
912
913                                 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
914                                         continue;
915
916                                 // TODO MemberCache: Should go to MetaInfo getter
917                                 types [i] = types [i].MakeByRefType ();
918                         }
919
920                         return types;
921                 }
922
923                 //
924                 // Returns the parameter information based on the name
925                 //
926                 public int GetParameterIndexByName (string name)
927                 {
928                         for (int idx = 0; idx < Count; ++idx) {
929                                 if (parameters [idx].Name == name)
930                                         return idx;
931                         }
932
933                         return -1;
934                 }
935
936                 public string GetSignatureForDocumentation ()
937                 {
938                         if (IsEmpty)
939                                 return string.Empty;
940
941                         StringBuilder sb = new StringBuilder ("(");
942                         for (int i = 0; i < Count; ++i) {
943                                 if (i != 0)
944                                         sb.Append (",");
945
946                                 sb.Append (types [i].GetSignatureForDocumentation ());
947
948                                 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
949                                         sb.Append ("@");
950                         }
951                         sb.Append (")");
952
953                         return sb.ToString ();
954                 }
955
956                 public string GetSignatureForError ()
957                 {
958                         return GetSignatureForError ("(", ")", Count);
959                 }
960
961                 public string GetSignatureForError (string start, string end, int count)
962                 {
963                         StringBuilder sb = new StringBuilder (start);
964                         for (int i = 0; i < count; ++i) {
965                                 if (i != 0)
966                                         sb.Append (", ");
967                                 sb.Append (ParameterDesc (i));
968                         }
969                         sb.Append (end);
970                         return sb.ToString ();
971                 }
972
973                 public bool HasArglist {
974                         get { return has_arglist; }
975                 }
976
977                 public bool HasExtensionMethodType {
978                         get {
979                                 if (Count == 0)
980                                         return false;
981
982                                 return FixedParameters [0].HasExtensionMethodModifier;
983                         }
984                 }
985
986                 public bool HasParams {
987                         get { return has_params; }
988                 }
989
990                 public bool IsEmpty {
991                         get { return parameters.Length == 0; }
992                 }
993
994                 public AParametersCollection Inflate (TypeParameterInflator inflator)
995                 {
996                         TypeSpec[] inflated_types = null;
997                         bool default_value = false;
998
999                         for (int i = 0; i < Count; ++i) {
1000                                 var inflated_param = inflator.Inflate (types[i]);
1001                                 if (inflated_types == null) {
1002                                         if (inflated_param == types[i])
1003                                                 continue;
1004
1005                                         default_value |= FixedParameters[i].HasDefaultValue;
1006                                         inflated_types = new TypeSpec[types.Length];
1007                                         Array.Copy (types, inflated_types, types.Length);
1008                                 } else {
1009                                         if (inflated_param == types[i])
1010                                                 continue;
1011
1012                                         default_value |= FixedParameters[i].HasDefaultValue;
1013                                 }
1014
1015                                 inflated_types[i] = inflated_param;
1016                         }
1017
1018                         if (inflated_types == null)
1019                                 return this;
1020
1021                         var clone = (AParametersCollection) MemberwiseClone ();
1022                         clone.types = inflated_types;
1023
1024                         //
1025                         // Default expression is original expression from the parameter
1026                         // declaration context which can be of nested enum in generic class type.
1027                         // In such case we end up with expression type of G<T>.E and e.g. parameter
1028                         // type of G<int>.E and conversion would fail without inflate in this
1029                         // context.
1030                         //
1031                         if (default_value) {
1032                                 clone.parameters = new IParameterData[Count];
1033                                 for (int i = 0; i < Count; ++i) {
1034                                         var fp = FixedParameters[i];
1035                                         clone.FixedParameters[i] = fp;
1036
1037                                         if (!fp.HasDefaultValue)
1038                                                 continue;
1039
1040                                         var expr = fp.DefaultValue;
1041
1042                                         if (inflated_types[i] == expr.Type)
1043                                                 continue;
1044
1045                                         var c = expr as Constant;
1046                                         if (c != null) {
1047                                                 //
1048                                                 // It may fail we are inflating before type validation is done
1049                                                 //
1050                                                 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1051                                                 if (c == null)
1052                                                         expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1053                                                 else
1054                                                         expr = c;
1055                                         } else if (expr is DefaultValueExpression)
1056                                                 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1057
1058                                         clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1059                                 }
1060                         }
1061
1062                         return clone;
1063                 }
1064
1065                 public string ParameterDesc (int pos)
1066                 {
1067                         if (types == null || types [pos] == null)
1068                                 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1069
1070                         string type = types [pos].GetSignatureForError ();
1071                         if (FixedParameters [pos].HasExtensionMethodModifier)
1072                                 return "this " + type;
1073
1074                         var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1075                         if (mod == 0)
1076                                 return type;
1077
1078                         return Parameter.GetModifierSignature (mod) + " " + type;
1079                 }
1080
1081                 public TypeSpec[] Types {
1082                         get { return types; }
1083                         set { types = value; }
1084                 }
1085         }
1086
1087         //
1088         // A collection of imported or resolved parameters
1089         //
1090         public class ParametersImported : AParametersCollection
1091         {
1092                 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1093                 {
1094                         this.parameters = parameters;
1095                         this.types = types;
1096                         this.has_arglist = hasArglist;
1097                         this.has_params = hasParams;
1098                 }
1099
1100                 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1101                 {
1102                         this.parameters = param;
1103                         this.types = types;
1104                         this.has_params = hasParams;
1105                 }
1106         }
1107
1108         /// <summary>
1109         ///   Represents the methods parameters
1110         /// </summary>
1111         public class ParametersCompiled : AParametersCollection
1112         {
1113                 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1114                 
1115                 // Used by C# 2.0 delegates
1116                 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1117
1118                 private ParametersCompiled ()
1119                 {
1120                         parameters = new Parameter [0];
1121                         types = TypeSpec.EmptyTypes;
1122                 }
1123
1124                 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1125                 {
1126                         this.parameters = parameters;
1127                     this.types = types;
1128                 }
1129                 
1130                 public ParametersCompiled (params Parameter[] parameters)
1131                 {
1132                         if (parameters == null || parameters.Length == 0)
1133                                 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1134
1135                         this.parameters = parameters;
1136                         int count = parameters.Length;
1137
1138                         for (int i = 0; i < count; i++){
1139                                 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1140                         }
1141                 }
1142
1143                 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1144                         this (parameters)
1145                 {
1146                         this.has_arglist = has_arglist;
1147                 }
1148                 
1149                 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1150                 {
1151                         return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1152                 }
1153                 
1154                 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1155                 {
1156                         return new ParametersCompiled (parameters, types);
1157                 }
1158
1159                 public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1160                 {
1161                         var ptypes = new TypeSpec [parameters.Count + 1];
1162                         ptypes [0] = type;
1163                         Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1164
1165                         var param = new Parameter [ptypes.Length];
1166                         param [0] = p;
1167                         for (int i = 0; i < parameters.Count; ++i) {
1168                                 var pi = parameters [i];
1169                                 param [i + 1] = pi;
1170                                 pi.SetIndex (i + 1);
1171                         }
1172
1173                         return ParametersCompiled.CreateFullyResolved (param, ptypes);
1174                 }
1175
1176                 //
1177                 // TODO: This does not fit here, it should go to different version of AParametersCollection
1178                 // as the underlying type is not Parameter and some methods will fail to cast
1179                 //
1180                 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1181                 {
1182                         var pd = new ParameterData [types.Length];
1183                         for (int i = 0; i < pd.Length; ++i)
1184                                 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1185
1186                         return new ParametersCompiled (pd, types);
1187                 }
1188
1189                 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1190                 {
1191                         return new ParametersCompiled (
1192                                 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1193                                 null);
1194                 }
1195
1196                 public void CheckConstraints (IMemberContext mc)
1197                 {
1198                         foreach (Parameter p in parameters) {
1199                                 //
1200                                 // It's null for compiler generated types or special types like __arglist
1201                                 //
1202                                 if (p.TypeExpression != null)
1203                                         ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1204                         }
1205                 }
1206
1207                 //
1208                 // Returns non-zero value for equal CLS parameter signatures
1209                 //
1210                 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1211                 {
1212                         int res = 0;
1213
1214                         for (int i = 0; i < a.Count; ++i) {
1215                                 var a_type = a.Types[i];
1216                                 var b_type = b.Types[i];
1217                                 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1218                                         if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1219                                                 res |= 1;
1220
1221                                         continue;
1222                                 }
1223
1224                                 var ac_a = a_type as ArrayContainer;
1225                                 if (ac_a == null)
1226                                         return 0;
1227
1228                                 var ac_b = b_type as ArrayContainer;
1229                                 if (ac_b == null)
1230                                         return 0;
1231
1232                                 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1233                                         res |= 2;
1234                                         continue;
1235                                 }
1236
1237                                 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1238                                         res |= 1;
1239                                         continue;
1240                                 }
1241
1242                                 return 0;
1243                         }
1244
1245                         return res;
1246                 }
1247
1248                 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1249                 {
1250                         return MergeGenerated (ctx, userParams, checkConflicts,
1251                                 new Parameter [] { compilerParams },
1252                                 new TypeSpec [] { compilerTypes });
1253                 }
1254
1255                 //
1256                 // Use this method when you merge compiler generated parameters with user parameters
1257                 //
1258                 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1259                 {
1260                         Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1261                         userParams.FixedParameters.CopyTo(all_params, 0);
1262
1263                         TypeSpec [] all_types;
1264                         if (userParams.types != null) {
1265                                 all_types = new TypeSpec [all_params.Length];
1266                                 userParams.Types.CopyTo (all_types, 0);
1267                         } else {
1268                                 all_types = null;
1269                         }
1270
1271                         int last_filled = userParams.Count;
1272                         int index = 0;
1273                         foreach (Parameter p in compilerParams) {
1274                                 for (int i = 0; i < last_filled; ++i) {
1275                                         while (p.Name == all_params [i].Name) {
1276                                                 if (checkConflicts && i < userParams.Count) {
1277                                                         ctx.Report.Error (316, userParams[i].Location,
1278                                                                 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1279                                                 }
1280                                                 p.Name = '_' + p.Name;
1281                                         }
1282                                 }
1283                                 all_params [last_filled] = p;
1284                                 if (all_types != null)
1285                                         all_types [last_filled] = compilerTypes [index++];
1286                                 ++last_filled;
1287                         }
1288                         
1289                         ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1290                         parameters.has_params = userParams.has_params;
1291                         return parameters;
1292                 }
1293
1294                 //
1295                 // Parameters checks for members which don't have a block
1296                 //
1297                 public void CheckParameters (MemberCore member)
1298                 {
1299                         for (int i = 0; i < parameters.Length; ++i) {
1300                                 var name = parameters[i].Name;
1301                                 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1302                                         if (parameters[ii].Name == name)
1303                                                 this[ii].Error_DuplicateName (member.Compiler.Report);
1304                                 }
1305                         }
1306                 }
1307
1308                 public bool Resolve (IMemberContext ec)
1309                 {
1310                         if (types != null)
1311                                 return true;
1312                         
1313                         types = new TypeSpec [Count];
1314                         
1315                         bool ok = true;
1316                         Parameter p;
1317                         for (int i = 0; i < FixedParameters.Length; ++i) {
1318                                 p = this [i];
1319                                 TypeSpec t = p.Resolve (ec, i);
1320                                 if (t == null) {
1321                                         ok = false;
1322                                         continue;
1323                                 }
1324
1325                                 types [i] = t;
1326                         }
1327
1328                         return ok;
1329                 }
1330
1331                 public void ResolveDefaultValues (MemberCore m)
1332                 {
1333                         ResolveContext rc = null;
1334                         for (int i = 0; i < parameters.Length; ++i) {
1335                                 Parameter p = (Parameter) parameters [i];
1336
1337                                 //
1338                                 // Try not to enter default values resolution if there are is not any default value possible
1339                                 //
1340                                 if (p.HasDefaultValue || p.OptAttributes != null) {
1341                                         if (rc == null)
1342                                                 rc = new ResolveContext (m);
1343
1344                                         p.ResolveDefaultValue (rc);
1345                                 }
1346                         }
1347                 }
1348
1349                 // Define each type attribute (in/out/ref) and
1350                 // the argument names.
1351                 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1352                 {
1353                         if (Count == 0)
1354                                 return;
1355
1356                         MethodBuilder mb = builder as MethodBuilder;
1357                         ConstructorBuilder cb = builder as ConstructorBuilder;
1358                         var pa = mc.Module.PredefinedAttributes;
1359
1360                         for (int i = 0; i < Count; i++) {
1361                                 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1362                         }
1363                 }
1364
1365                 public void VerifyClsCompliance (IMemberContext ctx)
1366                 {
1367                         foreach (Parameter p in FixedParameters)
1368                                 p.IsClsCompliant (ctx);
1369                 }
1370
1371                 public Parameter this [int pos] {
1372                         get { return (Parameter) parameters [pos]; }
1373                 }
1374
1375                 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1376                 {
1377                         var initializers = new ArrayInitializer (Count, loc);
1378                         foreach (Parameter p in FixedParameters) {
1379                                 //
1380                                 // Each parameter expression is stored to local variable
1381                                 // to save some memory when referenced later.
1382                                 //
1383                                 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1384                                 if (se.Resolve (ec)) {
1385                                         ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1386                                         ec.CurrentBlock.AddScopeStatement (se);
1387                                 }
1388                                 
1389                                 initializers.Add (p.ExpressionTreeVariableReference ());
1390                         }
1391
1392                         return new ArrayCreation (
1393                                 Parameter.ResolveParameterExpressionType (ec, loc),
1394                                 initializers, loc);
1395                 }
1396
1397                 public ParametersCompiled Clone ()
1398                 {
1399                         ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1400
1401                         p.parameters = new IParameterData [parameters.Length];
1402                         for (int i = 0; i < Count; ++i)
1403                                 p.parameters [i] = this [i].Clone ();
1404
1405                         return p;
1406                 }
1407         }
1408
1409         //
1410         // Default parameter value expression. We need this wrapper to handle
1411         // default parameter values of folded constants (e.g. indexer parameters).
1412         // The expression is resolved only once but applied to two methods which
1413         // both share reference to this expression and we ensure that resolving
1414         // this expression always returns same instance
1415         //
1416         public class DefaultParameterValueExpression : CompositeExpression
1417         {
1418                 public DefaultParameterValueExpression (Expression expr)
1419                         : base (expr)
1420                 {
1421                 }
1422
1423                 public void Resolve (ResolveContext rc, Parameter p)
1424                 {
1425                         var expr = Resolve (rc);
1426                         if (expr == null) {
1427                                 this.expr = ErrorExpression.Instance;
1428                                 return;
1429                         }
1430
1431                         expr = Child;
1432
1433                         if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) {
1434                                 if (!(expr is ErrorExpression)) {
1435                                         rc.Report.Error (1736, Location,
1436                                                 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1437                                                 p.Name);
1438                                 }
1439
1440                                 return;
1441                         }
1442
1443                         var parameter_type = p.Type;
1444                         if (type == parameter_type)
1445                                 return;
1446
1447                         var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1448                         if (res != null) {
1449                                 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1450                                         Nullable.Wrap wrap = (Nullable.Wrap) res;
1451                                         res = wrap.Child;
1452                                         if (!(res is Constant)) {
1453                                                 rc.Report.Error (1770, Location,
1454                                                         "The expression being assigned to nullable optional parameter `{0}' must be default value",
1455                                                         p.Name);
1456                                                 return;
1457                                         }
1458                                 }
1459
1460                                 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1461                                         rc.Report.Error (1763, Location,
1462                                                 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1463                                                 p.Name, parameter_type.GetSignatureForError ());
1464
1465                                         return;
1466                                 }
1467
1468                                 this.expr = res;
1469                                 return;
1470                         }
1471
1472                         rc.Report.Error (1750, Location,
1473                                 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1474                                 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1475
1476                         this.expr = ErrorExpression.Instance;
1477                 }
1478                 
1479                 public override object Accept (StructuralVisitor visitor)
1480                 {
1481                         return visitor.Visit (this);
1482                 }
1483         }
1484 }