2009-12-09 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / parameter.cs
blobe6761d38096d1254f2da733c077eabfbf62ac70e
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.Text;
18 namespace Mono.CSharp {
20 /// <summary>
21 /// Abstract Base class for parameters of a method.
22 /// </summary>
23 public abstract class ParameterBase : Attributable
25 protected ParameterBuilder builder;
27 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
29 #if false
30 if (a.Type == pa.MarshalAs) {
31 UnmanagedMarshal marshal = a.GetMarshal (this);
32 if (marshal != null) {
33 builder.SetMarshal (marshal);
35 return;
37 #endif
38 if (a.HasSecurityAttribute) {
39 a.Error_InvalidSecurityParent ();
40 return;
43 if (a.Type == pa.Dynamic) {
44 a.Error_MisusedDynamicAttribute ();
45 return;
48 builder.SetCustomAttribute (cb);
51 public ParameterBuilder Builder {
52 get {
53 return builder;
57 public override bool IsClsComplianceRequired()
59 return false;
63 /// <summary>
64 /// Class for applying custom attributes on the return type
65 /// </summary>
66 public class ReturnParameter : ParameterBase
68 MemberCore method;
70 // TODO: merge method and mb
71 public ReturnParameter (MemberCore method, MethodBuilder mb, Location location)
73 this.method = method;
74 try {
75 builder = mb.DefineParameter (0, ParameterAttributes.None, "");
77 catch (ArgumentOutOfRangeException) {
78 method.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type");
82 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
84 if (a.Type == pa.CLSCompliant) {
85 method.Compiler.Report.Warning (3023, 1, a.Location,
86 "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
89 // This occurs after Warning -28
90 if (builder == null)
91 return;
93 base.ApplyAttributeBuilder (a, cb, pa);
96 public override AttributeTargets AttributeTargets {
97 get {
98 return AttributeTargets.ReturnValue;
102 /// <summary>
103 /// Is never called
104 /// </summary>
105 public override string[] ValidAttributeTargets {
106 get {
107 return null;
112 /// <summary>
113 /// Class for applying custom attributes on the implicit parameter type
114 /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
115 /// </summary>
116 ///
117 // TODO: should use more code from Parameter.ApplyAttributeBuilder
118 public class ImplicitParameter : ParameterBase {
119 public ImplicitParameter (MethodBuilder mb)
121 builder = mb.DefineParameter (1, ParameterAttributes.None, "value");
124 public override AttributeTargets AttributeTargets {
125 get {
126 return AttributeTargets.Parameter;
130 /// <summary>
131 /// Is never called
132 /// </summary>
133 public override string[] ValidAttributeTargets {
134 get {
135 return null;
140 public class ImplicitLambdaParameter : Parameter
142 public ImplicitLambdaParameter (string name, Location loc)
143 : base (null, name, Modifier.NONE, null, loc)
147 public override Type Resolve (IMemberContext ec)
149 if (parameter_type == null)
150 throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
151 Name);
153 return parameter_type;
156 public Type Type {
157 set { parameter_type = value; }
161 public class ParamsParameter : Parameter {
162 public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
163 base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
167 public override Type Resolve (IMemberContext ec)
169 if (base.Resolve (ec) == null)
170 return null;
172 if (!parameter_type.IsArray || parameter_type.GetArrayRank () != 1) {
173 ec.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
174 return null;
177 return parameter_type;
180 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
182 base.ApplyAttributes (mb, cb, index);
183 PredefinedAttributes.Get.ParamArray.EmitAttribute (builder);
187 public class ArglistParameter : Parameter {
188 // Doesn't have proper type because it's never chosen for better conversion
189 public ArglistParameter (Location loc) :
190 base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
194 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
196 // Nothing to do
199 public override bool CheckAccessibility (InterfaceMemberBase member)
201 return true;
204 public override Type Resolve (IMemberContext ec)
206 return InternalType.Arglist;
209 public override string GetSignatureForError ()
211 return "__arglist";
215 public interface IParameterData
217 Expression DefaultValue { get; }
218 bool HasExtensionMethodModifier { get; }
219 bool HasDefaultValue { get; }
220 Parameter.Modifier ModFlags { get; }
221 string Name { get; }
225 // Parameter information created by parser
227 public class Parameter : ParameterBase, IParameterData, ILocalVariable {
228 [Flags]
229 public enum Modifier : byte {
230 NONE = 0,
231 REF = REFMASK | ISBYREF,
232 OUT = OUTMASK | ISBYREF,
233 PARAMS = 4,
234 // This is a flag which says that it's either REF or OUT.
235 ISBYREF = 8,
236 REFMASK = 32,
237 OUTMASK = 64,
238 This = 128
241 static string[] attribute_targets = new string [] { "param" };
243 protected FullNamedExpression TypeName;
244 readonly Modifier modFlags;
245 string name;
246 Expression default_expr;
247 protected Type parameter_type;
248 public readonly Location Location;
249 int idx;
250 public bool HasAddressTaken;
252 Expression expr_tree_variable;
253 static TypeExpr parameter_expr_tree_type;
255 HoistedVariable hoisted_variant;
257 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
259 this.name = name;
260 modFlags = mod;
261 Location = loc;
262 TypeName = type;
264 // Only assign, attributes will be attached during resolve
265 base.attributes = attrs;
268 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
270 if (a.Type == pa.In && ModFlags == Modifier.OUT) {
271 a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
272 return;
275 if (a.Type == pa.ParamArray) {
276 a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
277 return;
280 if (a.Type == PredefinedAttributes.Get.Out && (ModFlags & Modifier.REF) == Modifier.REF &&
281 !OptAttributes.Contains (pa.In)) {
282 a.Report.Error (662, a.Location,
283 "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
284 return;
287 if (a.Type == pa.CLSCompliant) {
288 a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
291 if (HasDefaultValue && (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter)) {
292 a.Report.Error (1745, a.Location,
293 "Cannot specify `{0}' attribute on optional parameter `{1}'",
294 TypeManager.CSharpName (a.Type).Replace ("Attribute", ""), Name);
295 return;
298 if (a.Type == pa.DefaultParameterValue) {
299 object val = a.GetParameterDefaultValue ();
300 if (val != null) {
301 Type t = val.GetType ();
302 if (t.IsArray || TypeManager.IsSubclassOf (t, TypeManager.type_type)) {
303 if (parameter_type == TypeManager.object_type) {
304 if (!t.IsArray)
305 t = TypeManager.type_type;
307 a.Report.Error (1910, a.Location, "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
308 TypeManager.CSharpName (t));
309 } else {
310 a.Report.Error (1909, a.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
311 TypeManager.CSharpName (parameter_type)); ;
313 return;
317 if (parameter_type == TypeManager.object_type ||
318 (val == null && !TypeManager.IsGenericParameter (parameter_type) && TypeManager.IsReferenceType (parameter_type)) ||
319 (val != null && TypeManager.TypeToCoreType (val.GetType ()) == parameter_type))
320 builder.SetConstant (val);
321 else
322 a.Report.Error (1908, a.Location, "The type of the default value should match the type of the parameter");
323 return;
326 base.ApplyAttributeBuilder (a, cb, pa);
329 public virtual bool CheckAccessibility (InterfaceMemberBase member)
331 if (parameter_type == null || TypeManager.IsGenericParameter (parameter_type))
332 return true;
334 return member.IsAccessibleAs (parameter_type);
337 // <summary>
338 // Resolve is used in method definitions
339 // </summary>
340 public virtual Type Resolve (IMemberContext rc)
342 if (parameter_type != null)
343 return parameter_type;
345 if (attributes != null)
346 attributes.AttachTo (this, rc);
348 TypeExpr texpr = TypeName.ResolveAsTypeTerminal (rc, false);
349 if (texpr == null)
350 return null;
352 parameter_type = texpr.Type;
354 // Ignore all checks for dummy members
355 AbstractPropertyEventMethod pem = rc as AbstractPropertyEventMethod;
356 if (pem != null && pem.IsDummy)
357 return parameter_type;
359 if (default_expr != null)
360 default_expr = ResolveDefaultValue (new ResolveContext (rc));
362 if ((modFlags & Parameter.Modifier.ISBYREF) != 0 &&
363 TypeManager.IsSpecialType (parameter_type)) {
364 rc.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
365 GetSignatureForError ());
366 return null;
369 TypeManager.CheckTypeVariance (parameter_type,
370 (modFlags & Parameter.Modifier.ISBYREF) != 0 ? Variance.None : Variance.Contravariant,
371 rc);
373 if (TypeManager.IsGenericParameter (parameter_type))
374 return parameter_type;
376 if ((parameter_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
377 rc.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
378 texpr.GetSignatureForError ());
379 return parameter_type;
382 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || TypeManager.IsDynamicType (parameter_type))) {
383 rc.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
384 TypeManager.CSharpName (parameter_type));
387 return parameter_type;
390 Expression ResolveDefaultValue (ResolveContext rc)
392 default_expr = default_expr.Resolve (rc);
393 if (default_expr == null)
394 return null;
396 if (!(default_expr is Constant || default_expr is DefaultValueExpression)) {
397 if (TypeManager.IsNullableType (parameter_type)) {
398 rc.Compiler.Report.Error (1770, default_expr.Location,
399 "The expression being assigned to nullable optional parameter `{0}' must be default value",
400 Name);
401 } else {
402 rc.Compiler.Report.Error (1736, default_expr.Location,
403 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
404 Name);
407 return null;
410 if (TypeManager.IsEqual (default_expr.Type, parameter_type))
411 return default_expr;
413 if (TypeManager.IsNullableType (parameter_type)) {
414 if (Convert.ImplicitNulableConversion (rc, default_expr, parameter_type) != null)
415 return default_expr;
416 } else {
417 var res = Convert.ImplicitConversionStandard (rc, default_expr, parameter_type, default_expr.Location);
418 if (res != null) {
419 if (!default_expr.IsNull && TypeManager.IsReferenceType (parameter_type) && parameter_type != TypeManager.string_type) {
420 rc.Compiler.Report.Error (1763, default_expr.Location,
421 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
422 Name, GetSignatureForError ());
424 return null;
427 return res;
431 rc.Compiler.Report.Error (1750, Location,
432 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
433 TypeManager.CSharpName (default_expr.Type), GetSignatureForError ());
435 return null;
438 public void ResolveVariable (int idx)
440 this.idx = idx;
443 public bool HasDefaultValue {
444 get { return default_expr != null; }
447 public bool HasExtensionMethodModifier {
448 get { return (modFlags & Modifier.This) != 0; }
452 // Hoisted parameter variant
454 public HoistedVariable HoistedVariant {
455 get {
456 return hoisted_variant;
458 set {
459 hoisted_variant = value;
463 public Modifier ModFlags {
464 get { return modFlags & ~Modifier.This; }
467 public string Name {
468 get { return name; }
469 set { name = value; }
472 ParameterAttributes Attributes {
473 get { return ParametersCompiled.GetParameterAttribute (modFlags) |
474 (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); }
477 public override AttributeTargets AttributeTargets {
478 get {
479 return AttributeTargets.Parameter;
483 public virtual string GetSignatureForError ()
485 string type_name;
486 if (parameter_type != null)
487 type_name = TypeManager.CSharpName (parameter_type);
488 else
489 type_name = TypeName.GetSignatureForError ();
491 string mod = GetModifierSignature (modFlags);
492 if (mod.Length > 0)
493 return String.Concat (mod, " ", type_name);
495 return type_name;
498 public static string GetModifierSignature (Modifier mod)
500 switch (mod) {
501 case Modifier.OUT:
502 return "out";
503 case Modifier.PARAMS:
504 return "params";
505 case Modifier.REF:
506 return "ref";
507 case Modifier.This:
508 return "this";
509 default:
510 return "";
514 public void IsClsCompliant (IMemberContext ctx)
516 if (AttributeTester.IsClsCompliant (parameter_type))
517 return;
519 ctx.Compiler.Report.Warning (3001, 1, Location,
520 "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
523 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
525 if (mb == null)
526 builder = cb.DefineParameter (index, Attributes, Name);
527 else
528 builder = mb.DefineParameter (index, Attributes, Name);
530 if (OptAttributes != null)
531 OptAttributes.Emit ();
533 if (HasDefaultValue) {
535 // Emit constant values for true constants only, the other
536 // constant-like expressions will rely on default value expression
538 Constant c = default_expr as Constant;
539 if (c != null) {
540 if (default_expr.Type == TypeManager.decimal_type) {
541 builder.SetCustomAttribute (Const.CreateDecimalConstantAttribute (c));
542 } else {
543 builder.SetConstant (c.GetTypedValue ());
548 if (TypeManager.IsDynamicType (parameter_type)) {
549 PredefinedAttributes.Get.Dynamic.EmitAttribute (builder);
550 } else {
551 var trans_flags = TypeManager.HasDynamicTypeUsed (parameter_type);
552 if (trans_flags != null) {
553 var pa = PredefinedAttributes.Get.DynamicTransform;
554 if (pa.Constructor != null || pa.ResolveConstructor (Location, TypeManager.bool_type.MakeArrayType ())) {
555 builder.SetCustomAttribute (
556 new CustomAttributeBuilder (pa.Constructor, new object [] { trans_flags }));
562 public override string[] ValidAttributeTargets {
563 get {
564 return attribute_targets;
568 public Parameter Clone ()
570 Parameter p = (Parameter) MemberwiseClone ();
571 if (attributes != null)
572 p.attributes = attributes.Clone ();
574 return p;
577 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
579 if ((modFlags & Modifier.ISBYREF) != 0)
580 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
582 expr_tree_variable = new TemporaryVariable (ResolveParameterExpressionType (ec, Location).Type, Location);
583 expr_tree_variable = expr_tree_variable.Resolve (ec);
585 Arguments arguments = new Arguments (2);
586 arguments.Add (new Argument (new TypeOf (
587 new TypeExpression (parameter_type, Location), Location)));
588 arguments.Add (new Argument (new StringConstant (Name, Location)));
589 return new SimpleAssign (ExpressionTreeVariableReference (),
590 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
593 public Expression DefaultValue {
594 get { return default_expr; }
595 set { default_expr = value; }
598 public void Emit (EmitContext ec)
600 int arg_idx = idx;
601 if (!ec.IsStatic)
602 arg_idx++;
604 ParameterReference.EmitLdArg (ec.ig, arg_idx);
607 public void EmitAssign (EmitContext ec)
609 int arg_idx = idx;
610 if (!ec.IsStatic)
611 arg_idx++;
613 if (arg_idx <= 255)
614 ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
615 else
616 ec.ig.Emit (OpCodes.Starg, arg_idx);
619 public void EmitAddressOf (EmitContext ec)
621 int arg_idx = idx;
623 if (!ec.IsStatic)
624 arg_idx++;
626 bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
627 if (is_ref) {
628 ParameterReference.EmitLdArg (ec.ig, arg_idx);
629 } else {
630 if (arg_idx <= 255)
631 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
632 else
633 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
637 public Expression ExpressionTreeVariableReference ()
639 return expr_tree_variable;
643 // System.Linq.Expressions.ParameterExpression type
645 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
647 if (parameter_expr_tree_type != null)
648 return parameter_expr_tree_type;
650 Type p_type = TypeManager.parameter_expression_type;
651 if (p_type == null) {
652 p_type = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "ParameterExpression", Kind.Class, true);
653 TypeManager.parameter_expression_type = p_type;
656 parameter_expr_tree_type = new TypeExpression (p_type, location).
657 ResolveAsTypeTerminal (ec, false);
659 return parameter_expr_tree_type;
662 public void Warning_UselessOptionalParameter (Report Report)
664 Report.Warning (1066, 1, Location,
665 "The default value specified for optional parameter `{0}' will never be used",
666 Name);
671 // Imported or resolved parameter information
673 public class ParameterData : IParameterData
675 readonly string name;
676 readonly Parameter.Modifier modifiers;
677 readonly Expression default_value;
679 public ParameterData (string name, Parameter.Modifier modifiers)
681 this.name = name;
682 this.modifiers = modifiers;
685 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
686 : this (name, modifiers)
688 this.default_value = defaultValue;
691 #region IParameterData Members
693 public Expression DefaultValue {
694 get { return default_value; }
697 public bool HasExtensionMethodModifier {
698 get { return (modifiers & Parameter.Modifier.This) != 0; }
701 public bool HasDefaultValue {
702 get { return default_value != null; }
705 public Parameter.Modifier ModFlags {
706 get { return modifiers & ~Parameter.Modifier.This; }
709 public string Name {
710 get { return name; }
713 #endregion
716 public abstract class AParametersCollection
718 protected bool has_arglist;
719 protected bool has_params;
721 // Null object pattern
722 protected IParameterData [] parameters;
723 protected Type [] types;
725 public int Count {
726 get { return parameters.Length; }
729 public Type ExtensionMethodType {
730 get {
731 if (Count == 0)
732 return null;
734 return FixedParameters [0].HasExtensionMethodModifier ?
735 types [0] : null;
739 public IParameterData [] FixedParameters {
740 get {
741 return parameters;
745 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
747 return (modFlags & Parameter.Modifier.OUT) == Parameter.Modifier.OUT ?
748 ParameterAttributes.Out : ParameterAttributes.None;
751 public Type [] GetEmitTypes ()
753 Type [] types = null;
754 if (has_arglist) {
755 if (Count == 1)
756 return Type.EmptyTypes;
758 types = new Type [Count - 1];
759 Array.Copy (Types, types, types.Length);
762 for (int i = 0; i < Count; ++i) {
763 if ((FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) == 0)
764 continue;
766 if (types == null)
767 types = (Type []) Types.Clone ();
769 types [i] = TypeManager.GetReferenceType (types [i]);
772 if (types == null)
773 types = Types;
775 return types;
779 // Returns the parameter information based on the name
781 public int GetParameterIndexByName (string name)
783 for (int idx = 0; idx < Count; ++idx) {
784 if (parameters [idx].Name == name)
785 return idx;
788 return -1;
791 public string GetSignatureForError ()
793 StringBuilder sb = new StringBuilder ("(");
794 for (int i = 0; i < Count; ++i) {
795 if (i != 0)
796 sb.Append (", ");
797 sb.Append (ParameterDesc (i));
799 sb.Append (')');
800 return sb.ToString ();
803 public bool HasArglist {
804 get { return has_arglist; }
807 public bool HasExtensionMethodType {
808 get {
809 if (Count == 0)
810 return false;
812 return FixedParameters [0].HasExtensionMethodModifier;
816 public bool HasParams {
817 get { return has_params; }
820 public bool IsEmpty {
821 get { return parameters.Length == 0; }
824 public string ParameterDesc (int pos)
826 if (types == null || types [pos] == null)
827 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
829 string type = TypeManager.CSharpName (types [pos]);
830 if (FixedParameters [pos].HasExtensionMethodModifier)
831 return "this " + type;
833 Parameter.Modifier mod = FixedParameters [pos].ModFlags;
834 if (mod == 0)
835 return type;
837 return Parameter.GetModifierSignature (mod) + " " + type;
840 public Type[] Types {
841 get { return types; }
842 set { types = value; }
845 #if MS_COMPATIBLE
846 public AParametersCollection InflateTypes (Type[] genArguments, Type[] argTypes)
848 AParametersCollection p = (AParametersCollection) MemberwiseClone (); // Clone ();
850 for (int i = 0; i < Count; ++i) {
851 if (types[i].IsGenericType) {
852 Type[] gen_arguments_open = new Type[types[i].GetGenericTypeDefinition ().GetGenericArguments ().Length];
853 Type[] gen_arguments = types[i].GetGenericArguments ();
854 for (int ii = 0; ii < gen_arguments_open.Length; ++ii) {
855 if (gen_arguments[ii].IsGenericParameter) {
856 Type t = argTypes[gen_arguments[ii].GenericParameterPosition];
857 gen_arguments_open[ii] = t;
858 } else
859 gen_arguments_open[ii] = gen_arguments[ii];
862 p.types[i] = types[i].GetGenericTypeDefinition ().MakeGenericType (gen_arguments_open);
863 continue;
866 if (types[i].IsGenericParameter) {
867 Type gen_argument = argTypes[types[i].GenericParameterPosition];
868 p.types[i] = gen_argument;
869 continue;
873 return p;
875 #endif
879 // A collection of imported or resolved parameters
881 public class ParametersImported : AParametersCollection
883 ParametersImported (AParametersCollection param, Type[] types)
885 this.parameters = param.FixedParameters;
886 this.types = types;
887 has_arglist = param.HasArglist;
888 has_params = param.HasParams;
891 ParametersImported (IParameterData [] parameters, Type [] types, bool hasArglist, bool hasParams)
893 this.parameters = parameters;
894 this.types = types;
895 this.has_arglist = hasArglist;
896 this.has_params = hasParams;
899 public ParametersImported (IParameterData [] param, Type[] types)
901 this.parameters = param;
902 this.types = types;
905 public static AParametersCollection Create (MethodBase method)
907 return Create (method.GetParameters (), method);
911 // Generic method parameters importer, param is shared between all instances
913 public static AParametersCollection Create (AParametersCollection param, MethodBase method)
915 if (param.IsEmpty)
916 return param;
918 ParameterInfo [] pi = method.GetParameters ();
919 Type [] types = new Type [pi.Length];
920 for (int i = 0; i < types.Length; i++) {
921 Type t = pi [i].ParameterType;
922 if (t.IsByRef)
923 t = TypeManager.GetElementType (t);
925 types [i] = TypeManager.TypeToCoreType (t);
928 return new ParametersImported (param, types);
932 // Imports SRE parameters
934 public static AParametersCollection Create (ParameterInfo [] pi, MethodBase method)
936 int varargs = method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0 ? 1 : 0;
938 if (pi.Length == 0 && varargs == 0)
939 return ParametersCompiled.EmptyReadOnlyParameters;
941 Type [] types = new Type [pi.Length + varargs];
942 IParameterData [] par = new IParameterData [pi.Length + varargs];
943 bool is_params = false;
944 PredefinedAttribute extension_attr = PredefinedAttributes.Get.Extension;
945 PredefinedAttribute param_attr = PredefinedAttributes.Get.ParamArray;
946 for (int i = 0; i < pi.Length; i++) {
947 types [i] = TypeManager.TypeToCoreType (pi [i].ParameterType);
949 ParameterInfo p = pi [i];
950 Parameter.Modifier mod = 0;
951 Expression default_value = null;
952 if (types [i].IsByRef) {
953 if ((p.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
954 mod = Parameter.Modifier.OUT;
955 else
956 mod = Parameter.Modifier.REF;
959 // Strip reference wrapping
961 types [i] = TypeManager.GetElementType (types [i]);
962 } else if (i == 0 && extension_attr.IsDefined && method != null && method.IsStatic &&
963 (method.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
964 method.IsDefined (extension_attr.Type, false)) {
965 mod = Parameter.Modifier.This;
966 } else {
967 if (i >= pi.Length - 2 && types[i].IsArray) {
968 if (p.IsDefined (param_attr.Type, false)) {
969 mod = Parameter.Modifier.PARAMS;
970 is_params = true;
974 if (!is_params && p.IsOptional) {
975 object value = p.DefaultValue;
976 if (value == Missing.Value) {
977 default_value = EmptyExpression.Null;
978 } else if (value == null) {
979 default_value = new NullLiteral (Location.Null);
980 } else {
981 default_value = Constant.CreateConstant (null, value.GetType (), value, Location.Null);
986 par [i] = new ParameterData (p.Name, mod, default_value);
989 if (varargs != 0) {
990 par [par.Length - 1] = new ArglistParameter (Location.Null);
991 types [types.Length - 1] = InternalType.Arglist;
994 return method != null ?
995 new ParametersImported (par, types, varargs != 0, is_params) :
996 new ParametersImported (par, types);
1000 /// <summary>
1001 /// Represents the methods parameters
1002 /// </summary>
1003 public class ParametersCompiled : AParametersCollection
1005 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1007 // Used by C# 2.0 delegates
1008 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1010 private ParametersCompiled ()
1012 parameters = new Parameter [0];
1013 types = Type.EmptyTypes;
1016 private ParametersCompiled (Parameter [] parameters, Type [] types)
1018 this.parameters = parameters;
1019 this.types = types;
1022 public ParametersCompiled (CompilerContext ctx, params Parameter[] parameters)
1024 if (parameters == null)
1025 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1027 this.parameters = parameters;
1028 int count = parameters.Length;
1030 if (count == 0)
1031 return;
1033 if (count == 1) {
1034 has_params = (parameters [0].ModFlags & Parameter.Modifier.PARAMS) != 0;
1035 return;
1038 for (int i = 0; i < count; i++){
1039 string base_name = parameters [i].Name;
1040 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1042 for (int j = i + 1; j < count; j++){
1043 if (base_name != parameters [j].Name)
1044 continue;
1046 ErrorDuplicateName (parameters[i], ctx.Report);
1047 i = j;
1052 public ParametersCompiled (CompilerContext ctx, Parameter [] parameters, bool has_arglist) :
1053 this (ctx, parameters)
1055 this.has_arglist = has_arglist;
1058 public static ParametersCompiled CreateFullyResolved (Parameter p, Type type)
1060 return new ParametersCompiled (new Parameter [] { p }, new Type [] { type });
1063 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, Type[] types)
1065 return new ParametersCompiled (parameters, types);
1068 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, Type compilerTypes)
1070 return MergeGenerated (ctx, userParams, checkConflicts,
1071 new Parameter [] { compilerParams },
1072 new Type [] { compilerTypes });
1076 // Use this method when you merge compiler generated parameters with user parameters
1078 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, Type[] compilerTypes)
1080 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1081 userParams.FixedParameters.CopyTo(all_params, 0);
1083 Type [] all_types;
1084 if (userParams.types != null) {
1085 all_types = new Type [all_params.Length];
1086 userParams.Types.CopyTo (all_types, 0);
1087 } else {
1088 all_types = null;
1091 int last_filled = userParams.Count;
1092 int index = 0;
1093 foreach (Parameter p in compilerParams) {
1094 for (int i = 0; i < last_filled; ++i) {
1095 while (p.Name == all_params [i].Name) {
1096 if (checkConflicts && i < userParams.Count) {
1097 ctx.Report.Error (316, userParams[i].Location,
1098 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1100 p.Name = '_' + p.Name;
1103 all_params [last_filled] = p;
1104 if (all_types != null)
1105 all_types [last_filled] = compilerTypes [index++];
1106 ++last_filled;
1109 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1110 parameters.has_params = userParams.has_params;
1111 return parameters;
1114 protected virtual void ErrorDuplicateName (Parameter p, Report Report)
1116 Report.Error (100, p.Location, "The parameter name `{0}' is a duplicate", p.Name);
1119 public bool Resolve (IMemberContext ec)
1121 if (types != null)
1122 return true;
1124 types = new Type [Count];
1126 bool ok = true;
1127 Parameter p;
1128 for (int i = 0; i < FixedParameters.Length; ++i) {
1129 p = this [i];
1130 Type t = p.Resolve (ec);
1131 if (t == null) {
1132 ok = false;
1133 continue;
1136 types [i] = t;
1139 return ok;
1142 public void ResolveVariable ()
1144 for (int i = 0; i < FixedParameters.Length; ++i) {
1145 this [i].ResolveVariable (i);
1149 public CallingConventions CallingConvention
1151 get {
1152 if (HasArglist)
1153 return CallingConventions.VarArgs;
1154 else
1155 return CallingConventions.Standard;
1159 // Define each type attribute (in/out/ref) and
1160 // the argument names.
1161 public void ApplyAttributes (MethodBase builder)
1163 if (Count == 0)
1164 return;
1166 MethodBuilder mb = builder as MethodBuilder;
1167 ConstructorBuilder cb = builder as ConstructorBuilder;
1169 for (int i = 0; i < Count; i++) {
1170 this [i].ApplyAttributes (mb, cb, i + 1);
1174 public void VerifyClsCompliance (IMemberContext ctx)
1176 foreach (Parameter p in FixedParameters)
1177 p.IsClsCompliant (ctx);
1180 public Parameter this [int pos] {
1181 get { return (Parameter) parameters [pos]; }
1184 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1186 var initializers = new ArrayInitializer (Count, loc);
1187 foreach (Parameter p in FixedParameters) {
1189 // Each parameter expression is stored to local variable
1190 // to save some memory when referenced later.
1192 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec));
1193 if (se.Resolve (ec))
1194 ec.CurrentBlock.AddScopeStatement (se);
1196 initializers.Add (p.ExpressionTreeVariableReference ());
1199 return new ArrayCreation (
1200 Parameter.ResolveParameterExpressionType (ec, loc),
1201 "[]", initializers, loc);
1204 public ParametersCompiled Clone ()
1206 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1208 p.parameters = new IParameterData [parameters.Length];
1209 for (int i = 0; i < Count; ++i)
1210 p.parameters [i] = this [i].Clone ();
1212 return p;