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