2010-05-27 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / parameter.cs
blob8cc781a5e530a0919b284c111a72348b2a49d24b
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;
17 using System.Linq;
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, MethodSpec ctor, byte[] cdata, 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 if (a.Type == pa.Dynamic) {
45 a.Error_MisusedDynamicAttribute ();
46 return;
49 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
52 public ParameterBuilder Builder {
53 get {
54 return builder;
58 public override bool IsClsComplianceRequired()
60 return false;
64 /// <summary>
65 /// Class for applying custom attributes on the return type
66 /// </summary>
67 public class ReturnParameter : ParameterBase
69 MemberCore method;
71 // TODO: merge method and mb
72 public ReturnParameter (MemberCore method, MethodBuilder mb, Location location)
74 this.method = method;
75 try {
76 builder = mb.DefineParameter (0, ParameterAttributes.None, "");
78 catch (ArgumentOutOfRangeException) {
79 method.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type");
83 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
85 if (a.Type == pa.CLSCompliant) {
86 method.Compiler.Report.Warning (3023, 1, a.Location,
87 "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
90 // This occurs after Warning -28
91 if (builder == null)
92 return;
94 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
97 public override AttributeTargets AttributeTargets {
98 get {
99 return AttributeTargets.ReturnValue;
103 /// <summary>
104 /// Is never called
105 /// </summary>
106 public override string[] ValidAttributeTargets {
107 get {
108 return null;
113 /// <summary>
114 /// Class for applying custom attributes on the implicit parameter type
115 /// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
116 /// </summary>
117 ///
118 // TODO: should use more code from Parameter.ApplyAttributeBuilder
119 public class ImplicitParameter : ParameterBase {
120 public ImplicitParameter (MethodBuilder mb)
122 builder = mb.DefineParameter (1, ParameterAttributes.None, "value");
125 public override AttributeTargets AttributeTargets {
126 get {
127 return AttributeTargets.Parameter;
131 /// <summary>
132 /// Is never called
133 /// </summary>
134 public override string[] ValidAttributeTargets {
135 get {
136 return null;
141 public class ImplicitLambdaParameter : Parameter
143 public ImplicitLambdaParameter (string name, Location loc)
144 : base (null, name, Modifier.NONE, null, loc)
148 public override TypeSpec Resolve (IMemberContext ec, int index)
150 if (parameter_type == null)
151 throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
152 Name);
154 base.idx = index;
155 return parameter_type;
158 public TypeSpec Type {
159 set { parameter_type = value; }
163 public class ParamsParameter : Parameter {
164 public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
165 base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
169 public override TypeSpec Resolve (IMemberContext ec, int index)
171 if (base.Resolve (ec, index) == null)
172 return null;
174 var ac = parameter_type as ArrayContainer;
175 if (ac == null || ac.Rank != 1) {
176 ec.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
177 return null;
180 return parameter_type;
183 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
185 base.ApplyAttributes (mb, cb, index);
186 PredefinedAttributes.Get.ParamArray.EmitAttribute (builder);
190 public class ArglistParameter : Parameter {
191 // Doesn't have proper type because it's never chosen for better conversion
192 public ArglistParameter (Location loc) :
193 base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
195 parameter_type = InternalType.Arglist;
198 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
200 // Nothing to do
203 public override bool CheckAccessibility (InterfaceMemberBase member)
205 return true;
208 public override TypeSpec Resolve (IMemberContext ec, int index)
210 return parameter_type;
214 public interface IParameterData
216 Expression DefaultValue { get; }
217 bool HasExtensionMethodModifier { get; }
218 bool HasDefaultValue { get; }
219 Parameter.Modifier ModFlags { get; }
220 string Name { get; }
224 // Parameter information created by parser
226 public class Parameter : ParameterBase, IParameterData, ILocalVariable {
227 [Flags]
228 public enum Modifier : byte {
229 NONE = 0,
230 REF = REFMASK | ISBYREF,
231 OUT = OUTMASK | ISBYREF,
232 PARAMS = 4,
233 // This is a flag which says that it's either REF or OUT.
234 ISBYREF = 8,
235 REFMASK = 32,
236 OUTMASK = 64,
237 This = 128
240 static string[] attribute_targets = new string [] { "param" };
242 FullNamedExpression texpr;
243 readonly Modifier modFlags;
244 string name;
245 Expression default_expr;
246 protected TypeSpec parameter_type;
247 public readonly Location Location;
248 protected int idx;
249 public bool HasAddressTaken;
251 Expression expr_tree_variable;
252 static TypeExpr parameter_expr_tree_type;
254 HoistedVariable hoisted_variant;
256 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
258 this.name = name;
259 modFlags = mod;
260 Location = loc;
261 texpr = type;
263 // Only assign, attributes will be attached during resolve
264 base.attributes = attrs;
267 #region Properties
268 public FullNamedExpression TypeExpression {
269 get {
270 return texpr;
273 #endregion
275 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
277 if (a.Type == pa.In && ModFlags == Modifier.OUT) {
278 a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
279 return;
282 if (a.Type == pa.ParamArray) {
283 a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
284 return;
287 if (a.Type == PredefinedAttributes.Get.Out && (ModFlags & Modifier.REF) == Modifier.REF &&
288 !OptAttributes.Contains (pa.In)) {
289 a.Report.Error (662, a.Location,
290 "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
291 return;
294 if (a.Type == pa.CLSCompliant) {
295 a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
298 if (HasDefaultValue && (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter)) {
299 a.Report.Error (1745, a.Location,
300 "Cannot specify `{0}' attribute on optional parameter `{1}'",
301 TypeManager.CSharpName (a.Type).Replace ("Attribute", ""), Name);
302 return;
305 if (a.Type == pa.DefaultParameterValue) {
306 TypeSpec arg_type;
307 var c = a.GetParameterDefaultValue (out arg_type);
308 if (c == null) {
309 if (parameter_type == TypeManager.object_type) {
310 a.Report.Error (1910, a.Location, "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
311 arg_type.GetSignatureForError ());
312 } else {
313 a.Report.Error (1909, a.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
314 parameter_type.GetSignatureForError ()); ;
317 return;
320 if (arg_type == parameter_type || parameter_type == TypeManager.object_type ||
321 (c.IsNull && TypeManager.IsReferenceType (parameter_type) && !TypeManager.IsGenericParameter (parameter_type)))
322 builder.SetConstant (c.GetValue ());
323 else
324 a.Report.Error (1908, a.Location, "The type of the default value should match the type of the parameter");
326 return;
329 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
332 public virtual bool CheckAccessibility (InterfaceMemberBase member)
334 if (parameter_type == null || TypeManager.IsGenericParameter (parameter_type))
335 return true;
337 return member.IsAccessibleAs (parameter_type);
340 public static void Reset ()
342 parameter_expr_tree_type = null;
345 // <summary>
346 // Resolve is used in method definitions
347 // </summary>
348 public virtual TypeSpec Resolve (IMemberContext rc, int index)
350 if (parameter_type != null)
351 return parameter_type;
353 if (attributes != null)
354 attributes.AttachTo (this, rc);
356 var expr = texpr.ResolveAsTypeTerminal (rc, false);
357 if (expr == null)
358 return null;
360 this.idx = index;
361 texpr = expr;
362 parameter_type = texpr.Type;
364 // Ignore all checks for dummy members
365 AbstractPropertyEventMethod pem = rc as AbstractPropertyEventMethod;
366 if (pem != null && pem.IsDummy)
367 return parameter_type;
369 if ((modFlags & Parameter.Modifier.ISBYREF) != 0 &&
370 TypeManager.IsSpecialType (parameter_type)) {
371 rc.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
372 GetSignatureForError ());
373 return null;
376 TypeManager.CheckTypeVariance (parameter_type,
377 (modFlags & Parameter.Modifier.ISBYREF) != 0 ? Variance.None : Variance.Contravariant,
378 rc);
380 if (parameter_type.IsStatic) {
381 rc.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
382 texpr.GetSignatureForError ());
383 return parameter_type;
386 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type == InternalType.Dynamic)) {
387 rc.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
388 TypeManager.CSharpName (parameter_type));
391 return parameter_type;
394 public void ResolveDefaultValue (ResolveContext rc)
396 if (default_expr != null)
397 default_expr = ResolveDefaultExpression (rc);
400 Expression ResolveDefaultExpression (ResolveContext rc)
402 default_expr = default_expr.Resolve (rc);
403 if (default_expr == null)
404 return null;
406 if (!(default_expr is Constant || default_expr is DefaultValueExpression)) {
407 if (TypeManager.IsNullableType (parameter_type)) {
408 rc.Compiler.Report.Error (1770, default_expr.Location,
409 "The expression being assigned to nullable optional parameter `{0}' must be default value",
410 Name);
411 } else {
412 rc.Compiler.Report.Error (1736, default_expr.Location,
413 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
414 Name);
417 return null;
420 if (TypeManager.IsEqual (default_expr.Type, parameter_type))
421 return default_expr;
423 if (TypeManager.IsNullableType (parameter_type)) {
424 if (Convert.ImplicitNulableConversion (rc, default_expr, parameter_type) != null)
425 return default_expr;
426 } else {
427 var res = Convert.ImplicitConversionStandard (rc, default_expr, parameter_type, default_expr.Location);
428 if (res != null) {
429 if (!default_expr.IsNull && TypeManager.IsReferenceType (parameter_type) && parameter_type != TypeManager.string_type) {
430 rc.Compiler.Report.Error (1763, default_expr.Location,
431 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
432 Name, GetSignatureForError ());
434 return null;
437 return res;
441 rc.Compiler.Report.Error (1750, Location,
442 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
443 TypeManager.CSharpName (default_expr.Type), GetSignatureForError ());
445 return null;
448 public bool HasDefaultValue {
449 get { return default_expr != null; }
452 public bool HasExtensionMethodModifier {
453 get { return (modFlags & Modifier.This) != 0; }
457 // Hoisted parameter variant
459 public HoistedVariable HoistedVariant {
460 get {
461 return hoisted_variant;
463 set {
464 hoisted_variant = value;
468 public Modifier ModFlags {
469 get { return modFlags & ~Modifier.This; }
472 public string Name {
473 get { return name; }
474 set { name = value; }
477 ParameterAttributes Attributes {
478 get { return ParametersCompiled.GetParameterAttribute (modFlags) |
479 (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); }
482 public override AttributeTargets AttributeTargets {
483 get {
484 return AttributeTargets.Parameter;
488 public virtual string GetSignatureForError ()
490 string type_name;
491 if (parameter_type != null)
492 type_name = TypeManager.CSharpName (parameter_type);
493 else
494 type_name = texpr.GetSignatureForError ();
496 string mod = GetModifierSignature (modFlags);
497 if (mod.Length > 0)
498 return String.Concat (mod, " ", type_name);
500 return type_name;
503 public static string GetModifierSignature (Modifier mod)
505 switch (mod) {
506 case Modifier.OUT:
507 return "out";
508 case Modifier.PARAMS:
509 return "params";
510 case Modifier.REF:
511 return "ref";
512 case Modifier.This:
513 return "this";
514 default:
515 return "";
519 public void IsClsCompliant (IMemberContext ctx)
521 if (parameter_type.IsCLSCompliant ())
522 return;
524 ctx.Compiler.Report.Warning (3001, 1, Location,
525 "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
528 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
530 if (mb == null)
531 builder = cb.DefineParameter (index, Attributes, Name);
532 else
533 builder = mb.DefineParameter (index, Attributes, Name);
535 if (OptAttributes != null)
536 OptAttributes.Emit ();
538 if (HasDefaultValue) {
540 // Emit constant values for true constants only, the other
541 // constant-like expressions will rely on default value expression
543 Constant c = default_expr as Constant;
544 if (c != null) {
545 if (default_expr.Type == TypeManager.decimal_type) {
546 builder.SetCustomAttribute (Const.CreateDecimalConstantAttribute (c));
547 } else {
548 builder.SetConstant (c.GetTypedValue ());
553 if (parameter_type == InternalType.Dynamic) {
554 PredefinedAttributes.Get.Dynamic.EmitAttribute (builder);
555 } else {
556 var trans_flags = TypeManager.HasDynamicTypeUsed (parameter_type);
557 if (trans_flags != null) {
558 var pa = PredefinedAttributes.Get.DynamicTransform;
559 if (pa.Constructor != null || pa.ResolveConstructor (Location, ArrayContainer.MakeType (TypeManager.bool_type))) {
560 builder.SetCustomAttribute (
561 new CustomAttributeBuilder (pa.Constructor, new object [] { trans_flags }));
567 public override string[] ValidAttributeTargets {
568 get {
569 return attribute_targets;
573 public Parameter Clone ()
575 Parameter p = (Parameter) MemberwiseClone ();
576 if (attributes != null)
577 p.attributes = attributes.Clone ();
579 return p;
582 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
584 if ((modFlags & Modifier.ISBYREF) != 0)
585 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
587 expr_tree_variable = new TemporaryVariable (ResolveParameterExpressionType (ec, Location).Type, Location);
588 expr_tree_variable = expr_tree_variable.Resolve (ec);
590 Arguments arguments = new Arguments (2);
591 arguments.Add (new Argument (new TypeOf (
592 new TypeExpression (parameter_type, Location), Location)));
593 arguments.Add (new Argument (new StringConstant (Name, Location)));
594 return new SimpleAssign (ExpressionTreeVariableReference (),
595 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
598 public Expression DefaultValue {
599 get { return default_expr; }
600 set { default_expr = value; }
603 public void Emit (EmitContext ec)
605 int arg_idx = idx;
606 if (!ec.IsStatic)
607 arg_idx++;
609 ParameterReference.EmitLdArg (ec, arg_idx);
612 public void EmitAssign (EmitContext ec)
614 int arg_idx = idx;
615 if (!ec.IsStatic)
616 arg_idx++;
618 if (arg_idx <= 255)
619 ec.Emit (OpCodes.Starg_S, (byte) arg_idx);
620 else
621 ec.Emit (OpCodes.Starg, arg_idx);
624 public void EmitAddressOf (EmitContext ec)
626 int arg_idx = idx;
628 if (!ec.IsStatic)
629 arg_idx++;
631 bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
632 if (is_ref) {
633 ParameterReference.EmitLdArg (ec, arg_idx);
634 } else {
635 if (arg_idx <= 255)
636 ec.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
637 else
638 ec.Emit (OpCodes.Ldarga, arg_idx);
642 public Expression ExpressionTreeVariableReference ()
644 return expr_tree_variable;
648 // System.Linq.Expressions.ParameterExpression type
650 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
652 if (parameter_expr_tree_type != null)
653 return parameter_expr_tree_type;
655 TypeSpec p_type = TypeManager.parameter_expression_type;
656 if (p_type == null) {
657 p_type = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "ParameterExpression", MemberKind.Class, true);
658 TypeManager.parameter_expression_type = p_type;
661 parameter_expr_tree_type = new TypeExpression (p_type, location).
662 ResolveAsTypeTerminal (ec, false);
664 return parameter_expr_tree_type;
667 public void Warning_UselessOptionalParameter (Report Report)
669 Report.Warning (1066, 1, Location,
670 "The default value specified for optional parameter `{0}' will never be used",
671 Name);
676 // Imported or resolved parameter information
678 public class ParameterData : IParameterData
680 readonly string name;
681 readonly Parameter.Modifier modifiers;
682 readonly Expression default_value;
684 public ParameterData (string name, Parameter.Modifier modifiers)
686 this.name = name;
687 this.modifiers = modifiers;
690 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
691 : this (name, modifiers)
693 this.default_value = defaultValue;
696 #region IParameterData Members
698 public Expression DefaultValue {
699 get { return default_value; }
702 public bool HasExtensionMethodModifier {
703 get { return (modifiers & Parameter.Modifier.This) != 0; }
706 public bool HasDefaultValue {
707 get { return default_value != null; }
710 public Parameter.Modifier ModFlags {
711 get { return modifiers & ~Parameter.Modifier.This; }
714 public string Name {
715 get { return name; }
718 #endregion
721 public abstract class AParametersCollection
723 protected bool has_arglist;
724 protected bool has_params;
726 // Null object pattern
727 protected IParameterData [] parameters;
728 protected TypeSpec [] types;
730 public CallingConventions CallingConvention {
731 get {
732 return has_arglist ?
733 CallingConventions.VarArgs :
734 CallingConventions.Standard;
738 public int Count {
739 get { return parameters.Length; }
742 public TypeSpec ExtensionMethodType {
743 get {
744 if (Count == 0)
745 return null;
747 return FixedParameters [0].HasExtensionMethodModifier ?
748 types [0] : null;
752 public IParameterData [] FixedParameters {
753 get {
754 return parameters;
758 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
760 return (modFlags & Parameter.Modifier.OUT) == Parameter.Modifier.OUT ?
761 ParameterAttributes.Out : ParameterAttributes.None;
764 // Very expensive operation
765 public Type[] GetMetaInfo ()
767 Type[] types;
768 if (has_arglist) {
769 if (Count == 1)
770 return Type.EmptyTypes;
772 types = new Type [Count - 1];
773 } else {
774 if (Count == 0)
775 return Type.EmptyTypes;
777 types = new Type [Count];
780 for (int i = 0; i < types.Length; ++i) {
781 types[i] = Types[i].GetMetaInfo ();
783 if ((FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) == 0)
784 continue;
786 // TODO MemberCache: Should go to MetaInfo getter
787 types [i] = types [i].MakeByRefType ();
790 return types;
794 // Returns the parameter information based on the name
796 public int GetParameterIndexByName (string name)
798 for (int idx = 0; idx < Count; ++idx) {
799 if (parameters [idx].Name == name)
800 return idx;
803 return -1;
806 public string GetSignatureForError ()
808 return GetSignatureForError ("(", ")", Count);
811 public string GetSignatureForError (string start, string end, int count)
813 StringBuilder sb = new StringBuilder (start);
814 for (int i = 0; i < count; ++i) {
815 if (i != 0)
816 sb.Append (", ");
817 sb.Append (ParameterDesc (i));
819 sb.Append (end);
820 return sb.ToString ();
823 public bool HasArglist {
824 get { return has_arglist; }
827 public bool HasExtensionMethodType {
828 get {
829 if (Count == 0)
830 return false;
832 return FixedParameters [0].HasExtensionMethodModifier;
836 public bool HasParams {
837 get { return has_params; }
840 public bool IsEmpty {
841 get { return parameters.Length == 0; }
844 public AParametersCollection Inflate (TypeParameterInflator inflator)
846 TypeSpec[] inflated_types = null;
847 bool default_value = false;
849 for (int i = 0; i < Count; ++i) {
850 var inflated_param = inflator.Inflate (types[i]);
851 if (inflated_types == null) {
852 if (inflated_param == types[i])
853 continue;
855 default_value |= FixedParameters[i] is DefaultValueExpression;
856 inflated_types = new TypeSpec[types.Length];
857 Array.Copy (types, inflated_types, types.Length);
860 inflated_types[i] = inflated_param;
863 if (inflated_types == null)
864 return this;
866 var clone = (AParametersCollection) MemberwiseClone ();
867 clone.types = inflated_types;
868 if (default_value) {
869 for (int i = 0; i < Count; ++i) {
870 var dve = clone.FixedParameters[i] as DefaultValueExpression;
871 if (dve != null) {
872 throw new NotImplementedException ("net");
873 // clone.FixedParameters [i].DefaultValue = new DefaultValueExpression ();
878 return clone;
881 public string ParameterDesc (int pos)
883 if (types == null || types [pos] == null)
884 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
886 string type = TypeManager.CSharpName (types [pos]);
887 if (FixedParameters [pos].HasExtensionMethodModifier)
888 return "this " + type;
890 Parameter.Modifier mod = FixedParameters [pos].ModFlags;
891 if (mod == 0)
892 return type;
894 return Parameter.GetModifierSignature (mod) + " " + type;
897 public TypeSpec[] Types {
898 get { return types; }
899 set { types = value; }
904 // A collection of imported or resolved parameters
906 public class ParametersImported : AParametersCollection
908 ParametersImported (AParametersCollection param, TypeSpec[] types)
910 this.parameters = param.FixedParameters;
911 this.types = types;
912 has_arglist = param.HasArglist;
913 has_params = param.HasParams;
916 ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
918 this.parameters = parameters;
919 this.types = types;
920 this.has_arglist = hasArglist;
921 this.has_params = hasParams;
924 public ParametersImported (IParameterData [] param, TypeSpec[] types)
926 this.parameters = param;
927 this.types = types;
930 public static AParametersCollection Create (TypeSpec parent, MethodBase method)
932 return Create (parent, method.GetParameters (), method);
936 // Imports System.Reflection parameters
938 public static AParametersCollection Create (TypeSpec parent, ParameterInfo [] pi, MethodBase method)
940 int varargs = method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0 ? 1 : 0;
942 if (pi.Length == 0 && varargs == 0)
943 return ParametersCompiled.EmptyReadOnlyParameters;
945 TypeSpec [] types = new TypeSpec [pi.Length + varargs];
946 IParameterData [] par = new IParameterData [pi.Length + varargs];
947 bool is_params = false;
948 for (int i = 0; i < pi.Length; i++) {
949 ParameterInfo p = pi [i];
950 Parameter.Modifier mod = 0;
951 Expression default_value = null;
952 if (p.ParameterType.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] = Import.ImportType (p.ParameterType.GetElementType ());
962 } else if (i == 0 && method.IsStatic && parent.IsStatic && // TODO: parent.Assembly.IsExtension &&
963 HasExtensionAttribute (method)) {
964 mod = Parameter.Modifier.This;
965 types[i] = Import.ImportType (p.ParameterType);
966 } else {
967 types[i] = Import.ImportType (p.ParameterType);
969 if (i >= pi.Length - 2 && types[i] is ArrayContainer) {
970 var cattrs = CustomAttributeData.GetCustomAttributes (p);
971 if (cattrs != null && cattrs.Any (l => l.Constructor.DeclaringType == typeof (ParamArrayAttribute))) {
972 mod = Parameter.Modifier.PARAMS;
973 is_params = true;
977 if (!is_params && p.IsOptional) {
978 object value = p.DefaultValue;
979 if (value == Missing.Value) {
980 default_value = EmptyExpression.Null;
981 } else if (value == null) {
982 default_value = new NullLiteral (Location.Null);
983 } else {
984 default_value = Constant.CreateConstant (null, Import.ImportType (value.GetType ()), value, Location.Null);
989 par [i] = new ParameterData (p.Name, mod, default_value);
992 if (varargs != 0) {
993 par [par.Length - 1] = new ArglistParameter (Location.Null);
994 types [types.Length - 1] = InternalType.Arglist;
997 return method != null ?
998 new ParametersImported (par, types, varargs != 0, is_params) :
999 new ParametersImported (par, types);
1002 static bool HasExtensionAttribute (MethodBase mb)
1004 var all_attributes = CustomAttributeData.GetCustomAttributes (mb);
1005 foreach (var attr in all_attributes) {
1006 var dt = attr.Constructor.DeclaringType;
1007 if (dt.Name == "ExtensionAttribute" && dt.Namespace == "System.Runtime.CompilerServices") {
1008 return true;
1012 return false;
1016 /// <summary>
1017 /// Represents the methods parameters
1018 /// </summary>
1019 public class ParametersCompiled : AParametersCollection
1021 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1023 // Used by C# 2.0 delegates
1024 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1026 private ParametersCompiled ()
1028 parameters = new Parameter [0];
1029 types = TypeSpec.EmptyTypes;
1032 private ParametersCompiled (IParameterData [] parameters, TypeSpec [] types)
1034 this.parameters = parameters;
1035 this.types = types;
1038 public ParametersCompiled (CompilerContext ctx, params Parameter[] parameters)
1040 if (parameters == null)
1041 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1043 this.parameters = parameters;
1044 int count = parameters.Length;
1046 if (count == 0)
1047 return;
1049 if (count == 1) {
1050 has_params = (parameters [0].ModFlags & Parameter.Modifier.PARAMS) != 0;
1051 return;
1054 for (int i = 0; i < count; i++){
1055 string base_name = parameters [i].Name;
1056 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1058 for (int j = i + 1; j < count; j++){
1059 if (base_name != parameters [j].Name)
1060 continue;
1062 ErrorDuplicateName (parameters[i], ctx.Report);
1063 i = j;
1068 public ParametersCompiled (CompilerContext ctx, Parameter [] parameters, bool has_arglist) :
1069 this (ctx, parameters)
1071 this.has_arglist = has_arglist;
1074 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1076 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1079 public static ParametersCompiled CreateFullyResolved (IParameterData[] parameters, TypeSpec[] types)
1081 return new ParametersCompiled (parameters, types);
1084 public static AParametersCollection CreateFullyResolved (TypeSpec[] types)
1086 var pd = new ParameterData [types.Length];
1087 for (int i = 0; i < pd.Length; ++i)
1088 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1090 return new ParametersCompiled (pd, types);
1094 // Returns non-zero value for equal CLS parameter signatures
1096 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1098 int res = 0;
1100 for (int i = 0; i < a.Count; ++i) {
1101 var a_type = a.Types[i];
1102 var b_type = b.Types[i];
1103 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1104 const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
1105 if ((a.FixedParameters[i].ModFlags & ref_out) != (b.FixedParameters[i].ModFlags & ref_out))
1106 res |= 1;
1108 continue;
1111 var ac_a = a_type as ArrayContainer;
1112 if (ac_a == null)
1113 return 0;
1115 var ac_b = b_type as ArrayContainer;
1116 if (ac_b == null)
1117 return 0;
1119 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1120 res |= 2;
1121 continue;
1124 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1125 res |= 1;
1126 continue;
1129 return 0;
1132 return res;
1135 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1137 return MergeGenerated (ctx, userParams, checkConflicts,
1138 new Parameter [] { compilerParams },
1139 new TypeSpec [] { compilerTypes });
1143 // Use this method when you merge compiler generated parameters with user parameters
1145 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1147 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1148 userParams.FixedParameters.CopyTo(all_params, 0);
1150 TypeSpec [] all_types;
1151 if (userParams.types != null) {
1152 all_types = new TypeSpec [all_params.Length];
1153 userParams.Types.CopyTo (all_types, 0);
1154 } else {
1155 all_types = null;
1158 int last_filled = userParams.Count;
1159 int index = 0;
1160 foreach (Parameter p in compilerParams) {
1161 for (int i = 0; i < last_filled; ++i) {
1162 while (p.Name == all_params [i].Name) {
1163 if (checkConflicts && i < userParams.Count) {
1164 ctx.Report.Error (316, userParams[i].Location,
1165 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1167 p.Name = '_' + p.Name;
1170 all_params [last_filled] = p;
1171 if (all_types != null)
1172 all_types [last_filled] = compilerTypes [index++];
1173 ++last_filled;
1176 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1177 parameters.has_params = userParams.has_params;
1178 return parameters;
1181 protected virtual void ErrorDuplicateName (Parameter p, Report Report)
1183 Report.Error (100, p.Location, "The parameter name `{0}' is a duplicate", p.Name);
1186 public bool Resolve (IMemberContext ec)
1188 if (types != null)
1189 return true;
1191 types = new TypeSpec [Count];
1193 bool ok = true;
1194 Parameter p;
1195 for (int i = 0; i < FixedParameters.Length; ++i) {
1196 p = this [i];
1197 TypeSpec t = p.Resolve (ec, i);
1198 if (t == null) {
1199 ok = false;
1200 continue;
1203 types [i] = t;
1206 return ok;
1209 public void ResolveDefaultValues (ResolveContext rc)
1211 for (int i = 0; i < FixedParameters.Length; ++i) {
1212 this [i].ResolveDefaultValue (rc);
1216 // Define each type attribute (in/out/ref) and
1217 // the argument names.
1218 public void ApplyAttributes (MethodBase builder)
1220 if (Count == 0)
1221 return;
1223 MethodBuilder mb = builder as MethodBuilder;
1224 ConstructorBuilder cb = builder as ConstructorBuilder;
1226 for (int i = 0; i < Count; i++) {
1227 this [i].ApplyAttributes (mb, cb, i + 1);
1231 public void VerifyClsCompliance (IMemberContext ctx)
1233 foreach (Parameter p in FixedParameters)
1234 p.IsClsCompliant (ctx);
1237 public Parameter this [int pos] {
1238 get { return (Parameter) parameters [pos]; }
1241 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1243 var initializers = new ArrayInitializer (Count, loc);
1244 foreach (Parameter p in FixedParameters) {
1246 // Each parameter expression is stored to local variable
1247 // to save some memory when referenced later.
1249 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec));
1250 if (se.Resolve (ec))
1251 ec.CurrentBlock.AddScopeStatement (se);
1253 initializers.Add (p.ExpressionTreeVariableReference ());
1256 return new ArrayCreation (
1257 Parameter.ResolveParameterExpressionType (ec, loc),
1258 "[]", initializers, loc);
1261 public ParametersCompiled Clone ()
1263 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1265 p.parameters = new IParameterData [parameters.Length];
1266 for (int i = 0; i < Count; ++i)
1267 p.parameters [i] = this [i].Clone ();
1269 return p;