2009-11-02 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / parameter.cs
blob0fb7a02da2b042949dcf4e4b821588ea16f289e3
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.
13 using System;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Collections;
17 using System.Text;
19 namespace Mono.CSharp {
21 /// <summary>
22 /// Abstract Base class for parameters of a method.
23 /// </summary>
24 public abstract class ParameterBase : Attributable
26 protected ParameterBuilder builder;
28 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
30 #if false
31 if (a.Type == pa.MarshalAs) {
32 UnmanagedMarshal marshal = a.GetMarshal (this);
33 if (marshal != null) {
34 builder.SetMarshal (marshal);
36 return;
38 #endif
39 if (a.HasSecurityAttribute) {
40 a.Error_InvalidSecurityParent ();
41 return;
44 builder.SetCustomAttribute (cb);
47 public override bool IsClsComplianceRequired()
49 return false;
53 /// <summary>
54 /// Class for applying custom attributes on the return type
55 /// </summary>
56 public class ReturnParameter : ParameterBase {
57 public ReturnParameter (MethodBuilder mb, Location location)
59 try {
60 builder = mb.DefineParameter (0, ParameterAttributes.None, "");
62 catch (ArgumentOutOfRangeException) {
63 RootContext.ToplevelTypes.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type");
67 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
69 if (a.Type == pa.CLSCompliant) {
70 RootContext.ToplevelTypes.Compiler.Report.Warning (3023, 1, a.Location,
71 "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
74 // This occurs after Warning -28
75 if (builder == null)
76 return;
78 base.ApplyAttributeBuilder (a, cb, pa);
81 public override AttributeTargets AttributeTargets {
82 get {
83 return AttributeTargets.ReturnValue;
87 public void EmitPredefined (PredefinedAttribute pa, Location loc)
89 if (builder != null)
90 pa.EmitAttribute (builder, loc);
93 /// <summary>
94 /// Is never called
95 /// </summary>
96 public override string[] ValidAttributeTargets {
97 get {
98 return null;
103 /// <summary>
104 /// Class for applying custom attributes on the implicit parameter type
105 /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
106 /// </summary>
107 ///
108 // TODO: should use more code from Parameter.ApplyAttributeBuilder
109 public class ImplicitParameter : ParameterBase {
110 public ImplicitParameter (MethodBuilder mb)
112 builder = mb.DefineParameter (1, ParameterAttributes.None, "value");
115 public override AttributeTargets AttributeTargets {
116 get {
117 return AttributeTargets.Parameter;
121 /// <summary>
122 /// Is never called
123 /// </summary>
124 public override string[] ValidAttributeTargets {
125 get {
126 return null;
131 public class ImplicitLambdaParameter : Parameter
133 public ImplicitLambdaParameter (string name, Location loc)
134 : base (null, name, Modifier.NONE, null, loc)
138 public override Type Resolve (IMemberContext ec)
140 if (parameter_type == null)
141 throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
142 Name);
144 return parameter_type;
147 public Type Type {
148 set { parameter_type = value; }
152 public class ParamsParameter : Parameter {
153 public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
154 base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
158 public override Type Resolve (IMemberContext ec)
160 if (base.Resolve (ec) == null)
161 return null;
163 if (!parameter_type.IsArray || parameter_type.GetArrayRank () != 1) {
164 ec.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
165 return null;
168 return parameter_type;
171 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
173 base.ApplyAttributes (mb, cb, index);
174 PredefinedAttributes.Get.ParamArray.EmitAttribute (builder, Location);
178 public class ArglistParameter : Parameter {
179 // Doesn't have proper type because it's never chosen for better conversion
180 public ArglistParameter (Location loc) :
181 base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
185 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
187 // Nothing to do
190 public override bool CheckAccessibility (InterfaceMemberBase member)
192 return true;
195 public override Type Resolve (IMemberContext ec)
197 return InternalType.Arglist;
200 public override string GetSignatureForError ()
202 return "__arglist";
206 public interface IParameterData
208 Expression DefaultValue { get; }
209 bool HasExtensionMethodModifier { get; }
210 bool HasDefaultValue { get; }
211 Parameter.Modifier ModFlags { get; }
212 string Name { get; }
216 // Parameter information created by parser
218 public class Parameter : ParameterBase, IParameterData, ILocalVariable {
219 [Flags]
220 public enum Modifier : byte {
221 NONE = 0,
222 REF = REFMASK | ISBYREF,
223 OUT = OUTMASK | ISBYREF,
224 PARAMS = 4,
225 // This is a flag which says that it's either REF or OUT.
226 ISBYREF = 8,
227 REFMASK = 32,
228 OUTMASK = 64,
229 This = 128
232 static string[] attribute_targets = new string [] { "param" };
234 protected FullNamedExpression TypeName;
235 readonly Modifier modFlags;
236 string name;
237 Expression default_expr;
238 protected Type parameter_type;
239 public readonly Location Location;
240 int idx;
241 public bool HasAddressTaken;
243 LocalVariableReference expr_tree_variable;
244 static TypeExpr parameter_expr_tree_type;
246 HoistedVariable hoisted_variant;
248 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
250 this.name = name;
251 modFlags = mod;
252 Location = loc;
253 TypeName = type;
255 // Only assign, attributes will be attached during resolve
256 base.attributes = attrs;
259 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
261 Report Report = RootContext.ToplevelTypes.Compiler.Report;
263 if (a.Type == pa.In && ModFlags == Modifier.OUT) {
264 Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
265 return;
268 if (a.Type == pa.ParamArray) {
269 Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
270 return;
273 if (a.Type == PredefinedAttributes.Get.Out && (ModFlags & Modifier.REF) == Modifier.REF &&
274 !OptAttributes.Contains (pa.In)) {
275 Report.Error (662, a.Location,
276 "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
277 return;
280 if (a.Type == pa.CLSCompliant) {
281 Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
284 if (HasDefaultValue && (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter)) {
285 Report.Error (1745, a.Location,
286 "Cannot specify `{0}' attribute on optional parameter `{1}'",
287 TypeManager.CSharpName (a.Type).Replace ("Attribute", ""), Name);
288 return;
291 if (a.Type == pa.DefaultParameterValue) {
292 object val = a.GetParameterDefaultValue ();
293 if (val != null) {
294 Type t = val.GetType ();
295 if (t.IsArray || TypeManager.IsSubclassOf (t, TypeManager.type_type)) {
296 if (parameter_type == TypeManager.object_type) {
297 if (!t.IsArray)
298 t = TypeManager.type_type;
300 Report.Error (1910, a.Location, "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
301 TypeManager.CSharpName (t));
302 } else {
303 Report.Error (1909, a.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
304 TypeManager.CSharpName (parameter_type)); ;
306 return;
310 if (parameter_type == TypeManager.object_type ||
311 (val == null && !TypeManager.IsGenericParameter (parameter_type) && TypeManager.IsReferenceType (parameter_type)) ||
312 (val != null && TypeManager.TypeToCoreType (val.GetType ()) == parameter_type))
313 builder.SetConstant (val);
314 else
315 Report.Error (1908, a.Location, "The type of the default value should match the type of the parameter");
316 return;
319 base.ApplyAttributeBuilder (a, cb, pa);
322 public virtual bool CheckAccessibility (InterfaceMemberBase member)
324 if (parameter_type == null || TypeManager.IsGenericParameter (parameter_type))
325 return true;
327 return member.IsAccessibleAs (parameter_type);
330 // <summary>
331 // Resolve is used in method definitions
332 // </summary>
333 public virtual Type Resolve (IMemberContext rc)
335 if (parameter_type != null)
336 return parameter_type;
338 if (attributes != null)
339 attributes.AttachTo (this, rc);
341 TypeExpr texpr = TypeName.ResolveAsTypeTerminal (rc, false);
342 if (texpr == null)
343 return null;
345 parameter_type = texpr.Type;
347 // Ignore all checks for dummy members
348 AbstractPropertyEventMethod pem = rc as AbstractPropertyEventMethod;
349 if (pem != null && pem.IsDummy)
350 return parameter_type;
352 if (default_expr != null) {
353 ResolveContext ec = new ResolveContext (rc);
354 default_expr = default_expr.Resolve (ec);
355 if (default_expr != null) {
356 Constant value = default_expr as Constant;
357 if (value == null) {
358 if (default_expr != null) {
359 bool is_valid = false;
360 if (default_expr is DefaultValueExpression) {
361 is_valid = true;
362 } else if (default_expr is New && ((New) default_expr).IsDefaultValueType) {
363 is_valid = TypeManager.IsEqual (parameter_type, default_expr.Type) ||
364 (TypeManager.IsNullableType (parameter_type) &&
365 Convert.ImplicitNulableConversion (ec, default_expr, parameter_type) != EmptyExpression.Null);
366 } else {
367 rc.Compiler.Report.Error (1736, default_expr.Location,
368 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
369 Name);
370 is_valid = true;
373 if (!is_valid) {
374 default_expr = null;
375 ec.Compiler.Report.Error (1763, Location,
376 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
377 Name, GetSignatureForError ());
380 } else {
381 Constant c = value.ConvertImplicitly (parameter_type);
382 if (c == null) {
383 if (parameter_type == TypeManager.object_type) {
384 rc.Compiler.Report.Error (1763, Location,
385 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
386 Name, GetSignatureForError ());
387 } else {
388 rc.Compiler.Report.Error (1750, Location,
389 "Optional parameter value `{0}' cannot be converted to parameter type `{1}'",
390 value.GetValue (), GetSignatureForError ());
392 default_expr = null;
398 if ((modFlags & Parameter.Modifier.ISBYREF) != 0 &&
399 TypeManager.IsSpecialType (parameter_type)) {
400 rc.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
401 GetSignatureForError ());
402 return null;
405 TypeManager.CheckTypeVariance (parameter_type,
406 (modFlags & Parameter.Modifier.ISBYREF) != 0 ? Variance.None : Variance.Contravariant,
407 rc);
409 if (TypeManager.IsGenericParameter (parameter_type))
410 return parameter_type;
412 if ((parameter_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
413 rc.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
414 texpr.GetSignatureForError ());
415 return parameter_type;
418 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || TypeManager.IsDynamicType (parameter_type))) {
419 rc.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
420 TypeManager.CSharpName (parameter_type));
423 return parameter_type;
426 public void ResolveVariable (int idx)
428 this.idx = idx;
431 public bool HasDefaultValue {
432 get { return default_expr != null; }
435 public bool HasExtensionMethodModifier {
436 get { return (modFlags & Modifier.This) != 0; }
440 // Hoisted parameter variant
442 public HoistedVariable HoistedVariant {
443 get {
444 return hoisted_variant;
446 set {
447 hoisted_variant = value;
451 public Modifier ModFlags {
452 get { return modFlags & ~Modifier.This; }
455 public string Name {
456 get { return name; }
457 set { name = value; }
460 ParameterAttributes Attributes {
461 get { return ParametersCompiled.GetParameterAttribute (modFlags) |
462 (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); }
465 public override AttributeTargets AttributeTargets {
466 get {
467 return AttributeTargets.Parameter;
471 public virtual string GetSignatureForError ()
473 string type_name;
474 if (parameter_type != null)
475 type_name = TypeManager.CSharpName (parameter_type);
476 else
477 type_name = TypeName.GetSignatureForError ();
479 string mod = GetModifierSignature (modFlags);
480 if (mod.Length > 0)
481 return String.Concat (mod, " ", type_name);
483 return type_name;
486 public static string GetModifierSignature (Modifier mod)
488 switch (mod) {
489 case Modifier.OUT:
490 return "out";
491 case Modifier.PARAMS:
492 return "params";
493 case Modifier.REF:
494 return "ref";
495 case Modifier.This:
496 return "this";
497 default:
498 return "";
502 public void IsClsCompliant ()
504 if (AttributeTester.IsClsCompliant (parameter_type))
505 return;
507 RootContext.ToplevelTypes.Compiler.Report.Warning (3001, 1, Location, "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
510 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
512 if (mb == null)
513 builder = cb.DefineParameter (index, Attributes, Name);
514 else
515 builder = mb.DefineParameter (index, Attributes, Name);
517 if (OptAttributes != null)
518 OptAttributes.Emit ();
520 if (HasDefaultValue) {
522 // Emit constant values for true constants only, the other
523 // constant-like expressions will rely on default value expression
525 Constant c = default_expr as Constant;
526 if (c != null) {
527 if (default_expr.Type == TypeManager.decimal_type) {
528 builder.SetCustomAttribute (Const.CreateDecimalConstantAttribute (c));
529 } else {
530 builder.SetConstant (c.GetValue ());
535 if (TypeManager.IsDynamicType (parameter_type))
536 PredefinedAttributes.Get.Dynamic.EmitAttribute (builder, Location);
539 public override string[] ValidAttributeTargets {
540 get {
541 return attribute_targets;
545 public Parameter Clone ()
547 Parameter p = (Parameter) MemberwiseClone ();
548 if (attributes != null)
549 p.attributes = attributes.Clone ();
551 return p;
554 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
556 if ((modFlags & Modifier.ISBYREF) != 0)
557 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
559 LocalInfo variable = ec.CurrentBlock.AddTemporaryVariable (
560 ResolveParameterExpressionType (ec, Location), Location);
561 variable.Resolve (ec);
563 expr_tree_variable = new LocalVariableReference (
564 ec.CurrentBlock, variable.Name, Location, variable, false);
566 Arguments arguments = new Arguments (2);
567 arguments.Add (new Argument (new TypeOf (
568 new TypeExpression (parameter_type, Location), Location)));
569 arguments.Add (new Argument (new StringConstant (Name, Location)));
570 return new SimpleAssign (ExpressionTreeVariableReference (),
571 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
574 public Expression DefaultValue {
575 get { return default_expr; }
576 set { default_expr = value; }
579 public void Emit (EmitContext ec)
581 int arg_idx = idx;
582 if (!ec.IsStatic)
583 arg_idx++;
585 ParameterReference.EmitLdArg (ec.ig, arg_idx);
588 public void EmitAssign (EmitContext ec)
590 int arg_idx = idx;
591 if (!ec.IsStatic)
592 arg_idx++;
594 if (arg_idx <= 255)
595 ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
596 else
597 ec.ig.Emit (OpCodes.Starg, arg_idx);
600 public void EmitAddressOf (EmitContext ec)
602 int arg_idx = idx;
604 if (!ec.IsStatic)
605 arg_idx++;
607 bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
608 if (is_ref) {
609 ParameterReference.EmitLdArg (ec.ig, arg_idx);
610 } else {
611 if (arg_idx <= 255)
612 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
613 else
614 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
618 public Expression ExpressionTreeVariableReference ()
620 return expr_tree_variable;
624 // System.Linq.Expressions.ParameterExpression type
626 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
628 if (parameter_expr_tree_type != null)
629 return parameter_expr_tree_type;
631 Type p_type = TypeManager.parameter_expression_type;
632 if (p_type == null) {
633 p_type = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "ParameterExpression", Kind.Class, true);
634 TypeManager.parameter_expression_type = p_type;
637 parameter_expr_tree_type = new TypeExpression (p_type, location).
638 ResolveAsTypeTerminal (ec, false);
640 return parameter_expr_tree_type;
643 public void Warning_UselessOptionalParameter (Report Report)
645 Report.Warning (1066, 1, Location,
646 "The default value specified for optional parameter `{0}' will never be used",
647 Name);
652 // Imported or resolved parameter information
654 public class ParameterData : IParameterData
656 readonly string name;
657 readonly Parameter.Modifier modifiers;
658 readonly Expression default_value;
660 public ParameterData (string name, Parameter.Modifier modifiers)
662 this.name = name;
663 this.modifiers = modifiers;
666 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
667 : this (name, modifiers)
669 this.default_value = defaultValue;
672 #region IParameterData Members
674 public Expression DefaultValue {
675 get { return default_value; }
678 public bool HasExtensionMethodModifier {
679 get { return (modifiers & Parameter.Modifier.This) != 0; }
682 public bool HasDefaultValue {
683 get { return default_value != null; }
686 public Parameter.Modifier ModFlags {
687 get { return modifiers & ~Parameter.Modifier.This; }
690 public string Name {
691 get { return name; }
694 #endregion
697 public abstract class AParametersCollection
699 protected bool has_arglist;
700 protected bool has_params;
702 // Null object pattern
703 protected IParameterData [] parameters;
704 protected Type [] types;
706 public int Count {
707 get { return parameters.Length; }
710 public Type ExtensionMethodType {
711 get {
712 if (Count == 0)
713 return null;
715 return FixedParameters [0].HasExtensionMethodModifier ?
716 types [0] : null;
720 public IParameterData [] FixedParameters {
721 get {
722 return parameters;
726 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
728 return (modFlags & Parameter.Modifier.OUT) == Parameter.Modifier.OUT ?
729 ParameterAttributes.Out : ParameterAttributes.None;
732 public Type [] GetEmitTypes ()
734 Type [] types = null;
735 if (has_arglist) {
736 if (Count == 1)
737 return Type.EmptyTypes;
739 types = new Type [Count - 1];
740 Array.Copy (Types, types, types.Length);
743 for (int i = 0; i < Count; ++i) {
744 if ((FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) == 0)
745 continue;
747 if (types == null)
748 types = (Type []) Types.Clone ();
750 types [i] = TypeManager.GetReferenceType (types [i]);
753 if (types == null)
754 types = Types;
756 return types;
760 // Returns the parameter information based on the name
762 public int GetParameterIndexByName (string name)
764 for (int idx = 0; idx < Count; ++idx) {
765 if (parameters [idx].Name == name)
766 return idx;
769 return -1;
772 public string GetSignatureForError ()
774 StringBuilder sb = new StringBuilder ("(");
775 for (int i = 0; i < Count; ++i) {
776 if (i != 0)
777 sb.Append (", ");
778 sb.Append (ParameterDesc (i));
780 sb.Append (')');
781 return sb.ToString ();
784 public bool HasArglist {
785 get { return has_arglist; }
788 public bool HasExtensionMethodType {
789 get {
790 if (Count == 0)
791 return false;
793 return FixedParameters [0].HasExtensionMethodModifier;
797 public bool HasParams {
798 get { return has_params; }
801 public bool IsEmpty {
802 get { return parameters.Length == 0; }
805 public string ParameterDesc (int pos)
807 if (types == null || types [pos] == null)
808 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
810 string type = TypeManager.CSharpName (types [pos]);
811 if (FixedParameters [pos].HasExtensionMethodModifier)
812 return "this " + type;
814 Parameter.Modifier mod = FixedParameters [pos].ModFlags;
815 if (mod == 0)
816 return type;
818 return Parameter.GetModifierSignature (mod) + " " + type;
821 public Type[] Types {
822 get { return types; }
823 set { types = value; }
826 #if MS_COMPATIBLE
827 public AParametersCollection InflateTypes (Type[] genArguments, Type[] argTypes)
829 AParametersCollection p = (AParametersCollection) MemberwiseClone (); // Clone ();
831 for (int i = 0; i < Count; ++i) {
832 if (types[i].IsGenericType) {
833 Type[] gen_arguments_open = new Type[types[i].GetGenericTypeDefinition ().GetGenericArguments ().Length];
834 Type[] gen_arguments = types[i].GetGenericArguments ();
835 for (int ii = 0; ii < gen_arguments_open.Length; ++ii) {
836 if (gen_arguments[ii].IsGenericParameter) {
837 Type t = argTypes[gen_arguments[ii].GenericParameterPosition];
838 gen_arguments_open[ii] = t;
839 } else
840 gen_arguments_open[ii] = gen_arguments[ii];
843 p.types[i] = types[i].GetGenericTypeDefinition ().MakeGenericType (gen_arguments_open);
844 continue;
847 if (types[i].IsGenericParameter) {
848 Type gen_argument = argTypes[types[i].GenericParameterPosition];
849 p.types[i] = gen_argument;
850 continue;
854 return p;
856 #endif
860 // A collection of imported or resolved parameters
862 public class ParametersImported : AParametersCollection
864 ParametersImported (AParametersCollection param, Type[] types)
866 this.parameters = param.FixedParameters;
867 this.types = types;
868 has_arglist = param.HasArglist;
869 has_params = param.HasParams;
872 ParametersImported (IParameterData [] parameters, Type [] types, bool hasArglist, bool hasParams)
874 this.parameters = parameters;
875 this.types = types;
876 this.has_arglist = hasArglist;
877 this.has_params = hasParams;
880 public ParametersImported (IParameterData [] param, Type[] types)
882 this.parameters = param;
883 this.types = types;
886 public static AParametersCollection Create (MethodBase method)
888 return Create (method.GetParameters (), method);
892 // Generic method parameters importer, param is shared between all instances
894 public static AParametersCollection Create (AParametersCollection param, MethodBase method)
896 if (param.IsEmpty)
897 return param;
899 ParameterInfo [] pi = method.GetParameters ();
900 Type [] types = new Type [pi.Length];
901 for (int i = 0; i < types.Length; i++) {
902 Type t = pi [i].ParameterType;
903 if (t.IsByRef)
904 t = TypeManager.GetElementType (t);
906 types [i] = TypeManager.TypeToCoreType (t);
909 return new ParametersImported (param, types);
913 // Imports SRE parameters
915 public static AParametersCollection Create (ParameterInfo [] pi, MethodBase method)
917 int varargs = method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0 ? 1 : 0;
919 if (pi.Length == 0 && varargs == 0)
920 return ParametersCompiled.EmptyReadOnlyParameters;
922 Type [] types = new Type [pi.Length + varargs];
923 IParameterData [] par = new IParameterData [pi.Length + varargs];
924 bool is_params = false;
925 PredefinedAttribute extension_attr = PredefinedAttributes.Get.Extension;
926 PredefinedAttribute param_attr = PredefinedAttributes.Get.ParamArray;
927 for (int i = 0; i < pi.Length; i++) {
928 types [i] = TypeManager.TypeToCoreType (pi [i].ParameterType);
930 ParameterInfo p = pi [i];
931 Parameter.Modifier mod = 0;
932 Expression default_value = null;
933 if (types [i].IsByRef) {
934 if ((p.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
935 mod = Parameter.Modifier.OUT;
936 else
937 mod = Parameter.Modifier.REF;
940 // Strip reference wrapping
942 types [i] = TypeManager.GetElementType (types [i]);
943 } else if (i == 0 && extension_attr.IsDefined && method != null && method.IsStatic &&
944 (method.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
945 method.IsDefined (extension_attr.Type, false)) {
946 mod = Parameter.Modifier.This;
947 } else {
948 if (i >= pi.Length - 2 && types[i].IsArray) {
949 if (p.IsDefined (param_attr.Type, false)) {
950 mod = Parameter.Modifier.PARAMS;
951 is_params = true;
955 if (!is_params && p.IsOptional) {
956 object value = p.DefaultValue;
957 if (value == Missing.Value) {
958 default_value = EmptyExpression.Null;
959 } else if (value == null) {
960 default_value = new NullLiteral (Location.Null);
961 } else {
962 default_value = Constant.CreateConstant (value.GetType (), value, Location.Null);
967 par [i] = new ParameterData (p.Name, mod, default_value);
970 if (varargs != 0) {
971 par [par.Length - 1] = new ArglistParameter (Location.Null);
972 types [types.Length - 1] = InternalType.Arglist;
975 return method != null ?
976 new ParametersImported (par, types, varargs != 0, is_params) :
977 new ParametersImported (par, types);
981 /// <summary>
982 /// Represents the methods parameters
983 /// </summary>
984 public class ParametersCompiled : AParametersCollection
986 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
988 // Used by C# 2.0 delegates
989 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
991 private ParametersCompiled ()
993 parameters = new Parameter [0];
994 types = Type.EmptyTypes;
997 private ParametersCompiled (Parameter [] parameters, Type [] types)
999 this.parameters = parameters;
1000 this.types = types;
1003 public ParametersCompiled (params Parameter[] parameters)
1005 if (parameters == null)
1006 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1008 this.parameters = parameters;
1009 int count = parameters.Length;
1011 if (count == 0)
1012 return;
1014 if (count == 1) {
1015 has_params = (parameters [0].ModFlags & Parameter.Modifier.PARAMS) != 0;
1016 return;
1019 for (int i = 0; i < count; i++){
1020 string base_name = parameters [i].Name;
1021 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1023 for (int j = i + 1; j < count; j++){
1024 if (base_name != parameters [j].Name)
1025 continue;
1027 ErrorDuplicateName (parameters[i], RootContext.ToplevelTypes.Compiler.Report);
1028 i = j;
1033 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1034 this (parameters)
1036 this.has_arglist = has_arglist;
1039 public static ParametersCompiled CreateFullyResolved (Parameter p, Type type)
1041 return new ParametersCompiled (new Parameter [] { p }, new Type [] { type });
1044 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, Type[] types)
1046 return new ParametersCompiled (parameters, types);
1049 public static ParametersCompiled MergeGenerated (ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, Type compilerTypes)
1051 return MergeGenerated (userParams, checkConflicts,
1052 new Parameter [] { compilerParams },
1053 new Type [] { compilerTypes });
1057 // Use this method when you merge compiler generated parameters with user parameters
1059 public static ParametersCompiled MergeGenerated (ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, Type[] compilerTypes)
1061 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1062 userParams.FixedParameters.CopyTo(all_params, 0);
1064 Type [] all_types;
1065 if (userParams.types != null) {
1066 all_types = new Type [all_params.Length];
1067 userParams.Types.CopyTo (all_types, 0);
1068 } else {
1069 all_types = null;
1072 int last_filled = userParams.Count;
1073 int index = 0;
1074 foreach (Parameter p in compilerParams) {
1075 for (int i = 0; i < last_filled; ++i) {
1076 while (p.Name == all_params [i].Name) {
1077 if (checkConflicts && i < userParams.Count) {
1078 RootContext.ToplevelTypes.Compiler.Report.Error (316, userParams[i].Location,
1079 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1081 p.Name = '_' + p.Name;
1084 all_params [last_filled] = p;
1085 if (all_types != null)
1086 all_types [last_filled] = compilerTypes [index++];
1087 ++last_filled;
1090 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1091 parameters.has_params = userParams.has_params;
1092 return parameters;
1095 protected virtual void ErrorDuplicateName (Parameter p, Report Report)
1097 Report.Error (100, p.Location, "The parameter name `{0}' is a duplicate", p.Name);
1100 public bool Resolve (IMemberContext ec)
1102 if (types != null)
1103 return true;
1105 types = new Type [Count];
1107 bool ok = true;
1108 Parameter p;
1109 for (int i = 0; i < FixedParameters.Length; ++i) {
1110 p = this [i];
1111 Type t = p.Resolve (ec);
1112 if (t == null) {
1113 ok = false;
1114 continue;
1117 types [i] = t;
1120 return ok;
1123 public void ResolveVariable ()
1125 for (int i = 0; i < FixedParameters.Length; ++i) {
1126 this [i].ResolveVariable (i);
1130 public CallingConventions CallingConvention
1132 get {
1133 if (HasArglist)
1134 return CallingConventions.VarArgs;
1135 else
1136 return CallingConventions.Standard;
1140 // Define each type attribute (in/out/ref) and
1141 // the argument names.
1142 public void ApplyAttributes (MethodBase builder)
1144 if (Count == 0)
1145 return;
1147 MethodBuilder mb = builder as MethodBuilder;
1148 ConstructorBuilder cb = builder as ConstructorBuilder;
1150 for (int i = 0; i < Count; i++) {
1151 this [i].ApplyAttributes (mb, cb, i + 1);
1155 public void VerifyClsCompliance ()
1157 foreach (Parameter p in FixedParameters)
1158 p.IsClsCompliant ();
1161 public Parameter this [int pos] {
1162 get { return (Parameter) parameters [pos]; }
1165 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1167 ArrayList initializers = new ArrayList (Count);
1168 foreach (Parameter p in FixedParameters) {
1170 // Each parameter expression is stored to local variable
1171 // to save some memory when referenced later.
1173 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec));
1174 if (se.Resolve (ec))
1175 ec.CurrentBlock.AddScopeStatement (se);
1177 initializers.Add (p.ExpressionTreeVariableReference ());
1180 return new ArrayCreation (
1181 Parameter.ResolveParameterExpressionType (ec, loc),
1182 "[]", initializers, loc);
1185 public ParametersCompiled Clone ()
1187 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1189 p.parameters = new IParameterData [parameters.Length];
1190 for (int i = 0; i < Count; ++i)
1191 p.parameters [i] = this [i].Clone ();
1193 return p;