2 // parameter.cs: Parameter definition.
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@seznam.cz)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 // Copyright 2011 Xamarin Inc
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
22 using MetaType = System.Type;
23 using System.Reflection;
24 using System.Reflection.Emit;
27 namespace Mono.CSharp {
30 /// Abstract Base class for parameters of a method.
32 public abstract class ParameterBase : Attributable
34 protected ParameterBuilder builder;
36 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
39 if (a.Type == pa.MarshalAs) {
40 UnmanagedMarshal marshal = a.GetMarshal (this);
41 if (marshal != null) {
42 builder.SetMarshal (marshal);
47 if (a.HasSecurityAttribute) {
48 a.Error_InvalidSecurityParent ();
52 if (a.Type == pa.Dynamic) {
53 a.Error_MisusedDynamicAttribute ();
57 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
60 public ParameterBuilder Builder {
66 public override bool IsClsComplianceRequired()
73 /// Class for applying custom attributes on the return type
75 public class ReturnParameter : ParameterBase
79 // TODO: merge method and mb
80 public ReturnParameter (MemberCore method, MethodBuilder mb, Location location)
84 builder = mb.DefineParameter (0, ParameterAttributes.None, "");
86 catch (ArgumentOutOfRangeException) {
87 method.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type");
91 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
93 if (a.Type == pa.CLSCompliant) {
94 method.Compiler.Report.Warning (3023, 1, a.Location,
95 "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
98 // This occurs after Warning -28
102 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
105 public override AttributeTargets AttributeTargets {
107 return AttributeTargets.ReturnValue;
114 public override string[] ValidAttributeTargets {
121 public class ImplicitLambdaParameter : Parameter
123 public ImplicitLambdaParameter (string name, Location loc)
124 : base (null, name, Modifier.NONE, null, loc)
128 public override TypeSpec Resolve (IMemberContext ec, int index)
130 if (parameter_type == null)
131 throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
135 return parameter_type;
138 public void SetParameterType (TypeSpec type)
140 parameter_type = type;
144 public class ParamsParameter : Parameter {
145 public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
146 base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
150 public override TypeSpec Resolve (IMemberContext ec, int index)
152 if (base.Resolve (ec, index) == null)
155 var ac = parameter_type as ArrayContainer;
156 if (ac == null || ac.Rank != 1) {
157 ec.Module.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
161 return parameter_type;
164 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
166 base.ApplyAttributes (mb, cb, index, pa);
167 pa.ParamArray.EmitAttribute (builder);
171 public class ArglistParameter : Parameter {
172 // Doesn't have proper type because it's never chosen for better conversion
173 public ArglistParameter (Location loc) :
174 base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
176 parameter_type = InternalType.Arglist;
179 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
184 public override bool CheckAccessibility (InterfaceMemberBase member)
189 public override TypeSpec Resolve (IMemberContext ec, int index)
191 return parameter_type;
195 public interface IParameterData
197 Expression DefaultValue { get; }
198 bool HasExtensionMethodModifier { get; }
199 bool HasDefaultValue { get; }
200 Parameter.Modifier ModFlags { get; }
205 // Parameter information created by parser
207 public class Parameter : ParameterBase, IParameterData, ILocalVariable // TODO: INamedBlockVariable
210 public enum Modifier : byte {
216 CallerMemberName = 1 << 4,
217 CallerLineNumber = 1 << 5,
218 CallerFilePath = 1 << 6,
220 RefOutMask = REF | OUT,
221 ModifierMask = PARAMS | REF | OUT | This,
222 CallerMask = CallerMemberName | CallerLineNumber | CallerFilePath
225 static readonly string[] attribute_targets = new string[] { "param" };
226 static readonly string[] attribute_targets_primary = new string[] { "param", "field" };
228 FullNamedExpression texpr;
231 Expression default_expr;
232 protected TypeSpec parameter_type;
233 readonly Location loc;
235 public bool HasAddressTaken;
237 Constructor primary_constructor;
238 TemporaryVariableReference expr_tree_variable;
240 HoistedParameter hoisted_variant;
242 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
249 // Only assign, attributes will be attached during resolve
250 base.attributes = attrs;
255 public Expression DefaultExpression {
261 public DefaultParameterValueExpression DefaultValue {
263 return default_expr as DefaultParameterValueExpression;
266 default_expr = value;
270 Expression IParameterData.DefaultValue {
272 var expr = default_expr as DefaultParameterValueExpression;
273 return expr == null ? default_expr : expr.Child;
277 bool HasOptionalExpression {
279 return default_expr is DefaultParameterValueExpression;
283 public Location Location {
289 public Modifier ParameterModifier {
295 public TypeSpec Type {
297 return parameter_type;
300 parameter_type = value;
304 public FullNamedExpression TypeExpression {
310 public override string[] ValidAttributeTargets {
312 return primary_constructor != null ? attribute_targets_primary : attribute_targets;
318 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
320 if (a.Target == AttributeTargets.Field) {
321 var field = MemberCache.FindMember (primary_constructor.Spec.DeclaringType, MemberFilter.Field (name, parameter_type), BindingRestriction.DeclaredOnly);
322 ((Field)field.MemberDefinition).ApplyAttributeBuilder (a, ctor, cdata, pa);
326 if (a.Type == pa.In && ModFlags == Modifier.OUT) {
327 a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
331 if (a.Type == pa.ParamArray) {
332 a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
336 if (a.Type == pa.Out && (ModFlags & Modifier.REF) != 0 &&
337 !OptAttributes.Contains (pa.In)) {
338 a.Report.Error (662, a.Location,
339 "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
343 if (a.Type == pa.CLSCompliant) {
344 a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
345 } else if (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter) {
346 if (HasOptionalExpression) {
347 a.Report.Error (1745, a.Location,
348 "Cannot specify `{0}' attribute on optional parameter `{1}'",
349 a.Type.GetSignatureForError ().Replace ("Attribute", ""), Name);
352 if (a.Type == pa.DefaultParameterValue)
354 } else if (a.Type == pa.CallerMemberNameAttribute) {
355 if ((modFlags & Modifier.CallerMemberName) == 0) {
356 a.Report.Error (4022, a.Location,
357 "The CallerMemberName attribute can only be applied to parameters with default value");
359 } else if (a.Type == pa.CallerLineNumberAttribute) {
360 if ((modFlags & Modifier.CallerLineNumber) == 0) {
361 a.Report.Error (4020, a.Location,
362 "The CallerLineNumber attribute can only be applied to parameters with default value");
364 } else if (a.Type == pa.CallerFilePathAttribute) {
365 if ((modFlags & Modifier.CallerFilePath) == 0) {
366 a.Report.Error (4021, a.Location,
367 "The CallerFilePath attribute can only be applied to parameters with default value");
371 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
374 public virtual bool CheckAccessibility (InterfaceMemberBase member)
376 if (parameter_type == null)
379 return member.IsAccessibleAs (parameter_type);
383 // Resolve is used in method definitions
385 public virtual TypeSpec Resolve (IMemberContext rc, int index)
387 if (parameter_type != null)
388 return parameter_type;
390 if (attributes != null)
391 attributes.AttachTo (this, rc);
393 var ctor = rc.CurrentMemberDefinition as Constructor;
394 if (ctor != null && ctor.IsPrimaryConstructor)
395 primary_constructor = ctor;
397 parameter_type = texpr.ResolveAsType (rc);
398 if (parameter_type == null)
403 if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
404 rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
405 GetSignatureForError ());
409 VarianceDecl.CheckTypeVariance (parameter_type,
410 (modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
413 if (parameter_type.IsStatic) {
414 rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
415 texpr.GetSignatureForError ());
416 return parameter_type;
419 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
420 rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
421 parameter_type.GetSignatureForError ());
424 return parameter_type;
427 void ResolveCallerAttributes (ResolveContext rc)
429 var pa = rc.Module.PredefinedAttributes;
430 TypeSpec caller_type;
432 foreach (var attr in attributes.Attrs) {
433 var atype = attr.ResolveTypeForComparison ();
437 if (atype == pa.CallerMemberNameAttribute) {
438 caller_type = rc.BuiltinTypes.String;
439 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
440 rc.Report.Error (4019, attr.Location,
441 "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
442 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
445 modFlags |= Modifier.CallerMemberName;
449 if (atype == pa.CallerLineNumberAttribute) {
450 caller_type = rc.BuiltinTypes.Int;
451 if (caller_type != parameter_type && !Convert.ImplicitNumericConversionExists (caller_type, parameter_type)) {
452 rc.Report.Error (4017, attr.Location,
453 "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
454 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
457 modFlags |= Modifier.CallerLineNumber;
461 if (atype == pa.CallerFilePathAttribute) {
462 caller_type = rc.BuiltinTypes.String;
463 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
464 rc.Report.Error (4018, attr.Location,
465 "The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
466 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
469 modFlags |= Modifier.CallerFilePath;
475 public void ResolveDefaultValue (ResolveContext rc)
478 // Default value was specified using an expression
480 if (default_expr != null) {
481 ((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
482 if (attributes != null)
483 ResolveCallerAttributes (rc);
488 if (attributes == null)
491 var pa = rc.Module.PredefinedAttributes;
492 var def_attr = attributes.Search (pa.DefaultParameterValue);
493 if (def_attr != null) {
494 if (def_attr.Resolve () == null)
497 var default_expr_attr = def_attr.GetParameterDefaultValue ();
498 if (default_expr_attr == null)
501 var dpa_rc = def_attr.CreateResolveContext ();
502 default_expr = default_expr_attr.Resolve (dpa_rc);
504 if (default_expr is BoxedCast)
505 default_expr = ((BoxedCast) default_expr).Child;
507 Constant c = default_expr as Constant;
509 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
510 rc.Report.Error (1910, default_expr.Location,
511 "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
512 default_expr.Type.GetSignatureForError ());
514 rc.Report.Error (1909, default_expr.Location,
515 "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
516 default_expr.Type.GetSignatureForError ());
523 if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
524 (default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
525 parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
530 // LAMESPEC: Some really weird csc behaviour which we have to mimic
531 // User operators returning same type as parameter type are considered
532 // valid for this attribute only
534 // struct S { public static implicit operator S (int i) {} }
536 // void M ([DefaultParameterValue (3)]S s)
538 var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
539 if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
543 rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
547 var opt_attr = attributes.Search (pa.OptionalParameter);
548 if (opt_attr != null) {
549 default_expr = EmptyExpression.MissingValue;
553 public bool HasDefaultValue {
554 get { return default_expr != null; }
557 public bool HasExtensionMethodModifier {
558 get { return (modFlags & Modifier.This) != 0; }
562 // Hoisted parameter variant
564 public HoistedParameter HoistedVariant {
566 return hoisted_variant;
569 hoisted_variant = value;
573 public Modifier ModFlags {
574 get { return modFlags & ~Modifier.This; }
579 set { name = value; }
582 public override AttributeTargets AttributeTargets {
584 return AttributeTargets.Parameter;
588 public void Error_DuplicateName (Report r)
590 r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
593 public virtual string GetSignatureForError ()
596 if (parameter_type != null)
597 type_name = parameter_type.GetSignatureForError ();
599 type_name = texpr.GetSignatureForError ();
601 string mod = GetModifierSignature (modFlags);
603 return String.Concat (mod, " ", type_name);
608 public static string GetModifierSignature (Modifier mod)
613 case Modifier.PARAMS:
624 public void IsClsCompliant (IMemberContext ctx)
626 if (parameter_type.IsCLSCompliant ())
629 ctx.Module.Compiler.Report.Warning (3001, 1, Location,
630 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
633 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
636 throw new InternalErrorException ("builder already exists");
638 var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
639 if (HasOptionalExpression)
640 pattrs |= ParameterAttributes.Optional;
643 builder = cb.DefineParameter (index, pattrs, Name);
645 builder = mb.DefineParameter (index, pattrs, Name);
647 if (OptAttributes != null)
648 OptAttributes.Emit ();
650 if (HasDefaultValue && default_expr.Type != null) {
652 // Emit constant values for true constants only, the other
653 // constant-like expressions will rely on default value expression
655 var def_value = DefaultValue;
656 Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
658 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
659 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
661 builder.SetConstant (c.GetValue ());
663 } else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
665 // Handles special case where default expression is used with value-type or type parameter
667 // void Foo (S s = default (S)) {}
669 builder.SetConstant (null);
673 if (parameter_type != null) {
674 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
675 pa.Dynamic.EmitAttribute (builder);
676 } else if (parameter_type.HasDynamicElement) {
677 pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
682 public Parameter Clone ()
684 Parameter p = (Parameter) MemberwiseClone ();
685 if (attributes != null)
686 p.attributes = attributes.Clone ();
691 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
693 if ((modFlags & Modifier.RefOutMask) != 0)
694 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
696 expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
697 expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
699 Arguments arguments = new Arguments (2);
700 arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
701 arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
702 return new SimpleAssign (ExpressionTreeVariableReference (),
703 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
706 public void Emit (EmitContext ec)
708 ec.EmitArgumentLoad (idx);
711 public void EmitAssign (EmitContext ec)
713 ec.EmitArgumentStore (idx);
716 public void EmitAddressOf (EmitContext ec)
718 if ((ModFlags & Modifier.RefOutMask) != 0) {
719 ec.EmitArgumentLoad (idx);
721 ec.EmitArgumentAddress (idx);
725 public TemporaryVariableReference ExpressionTreeVariableReference ()
727 return expr_tree_variable;
731 // System.Linq.Expressions.ParameterExpression type
733 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
735 TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
736 return new TypeExpression (p_type, location);
739 public void Warning_UselessOptionalParameter (Report Report)
741 Report.Warning (1066, 1, Location,
742 "The default value specified for optional parameter `{0}' will never be used",
748 // Imported or resolved parameter information
750 public class ParameterData : IParameterData
752 readonly string name;
753 readonly Parameter.Modifier modifiers;
754 readonly Expression default_value;
756 public ParameterData (string name, Parameter.Modifier modifiers)
759 this.modifiers = modifiers;
762 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
763 : this (name, modifiers)
765 this.default_value = defaultValue;
768 #region IParameterData Members
770 public Expression DefaultValue {
771 get { return default_value; }
774 public bool HasExtensionMethodModifier {
775 get { return (modifiers & Parameter.Modifier.This) != 0; }
778 public bool HasDefaultValue {
779 get { return default_value != null; }
782 public Parameter.Modifier ModFlags {
783 get { return modifiers; }
793 public abstract class AParametersCollection
795 protected bool has_arglist;
796 protected bool has_params;
798 // Null object pattern
799 protected IParameterData [] parameters;
800 protected TypeSpec [] types;
802 public CallingConventions CallingConvention {
805 CallingConventions.VarArgs :
806 CallingConventions.Standard;
811 get { return parameters.Length; }
814 public TypeSpec ExtensionMethodType {
819 return FixedParameters [0].HasExtensionMethodModifier ?
824 public IParameterData [] FixedParameters {
830 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
832 return (modFlags & Parameter.Modifier.OUT) != 0 ?
833 ParameterAttributes.Out : ParameterAttributes.None;
836 // Very expensive operation
837 public MetaType[] GetMetaInfo ()
842 return MetaType.EmptyTypes;
844 types = new MetaType[Count - 1];
847 return MetaType.EmptyTypes;
849 types = new MetaType[Count];
852 for (int i = 0; i < types.Length; ++i) {
853 types[i] = Types[i].GetMetaInfo ();
855 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
858 // TODO MemberCache: Should go to MetaInfo getter
859 types [i] = types [i].MakeByRefType ();
866 // Returns the parameter information based on the name
868 public int GetParameterIndexByName (string name)
870 for (int idx = 0; idx < Count; ++idx) {
871 if (parameters [idx].Name == name)
878 public string GetSignatureForDocumentation ()
883 StringBuilder sb = new StringBuilder ("(");
884 for (int i = 0; i < Count; ++i) {
888 sb.Append (types [i].GetSignatureForDocumentation ());
890 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
895 return sb.ToString ();
898 public string GetSignatureForError ()
900 return GetSignatureForError ("(", ")", Count);
903 public string GetSignatureForError (string start, string end, int count)
905 StringBuilder sb = new StringBuilder (start);
906 for (int i = 0; i < count; ++i) {
909 sb.Append (ParameterDesc (i));
912 return sb.ToString ();
915 public bool HasArglist {
916 get { return has_arglist; }
919 public bool HasExtensionMethodType {
924 return FixedParameters [0].HasExtensionMethodModifier;
928 public bool HasParams {
929 get { return has_params; }
932 public bool IsEmpty {
933 get { return parameters.Length == 0; }
936 public AParametersCollection Inflate (TypeParameterInflator inflator)
938 TypeSpec[] inflated_types = null;
939 bool default_value = false;
941 for (int i = 0; i < Count; ++i) {
942 var inflated_param = inflator.Inflate (types[i]);
943 if (inflated_types == null) {
944 if (inflated_param == types[i])
947 default_value |= FixedParameters[i].HasDefaultValue;
948 inflated_types = new TypeSpec[types.Length];
949 Array.Copy (types, inflated_types, types.Length);
951 if (inflated_param == types[i])
954 default_value |= FixedParameters[i].HasDefaultValue;
957 inflated_types[i] = inflated_param;
960 if (inflated_types == null)
963 var clone = (AParametersCollection) MemberwiseClone ();
964 clone.types = inflated_types;
967 // Default expression is original expression from the parameter
968 // declaration context which can be of nested enum in generic class type.
969 // In such case we end up with expression type of G<T>.E and e.g. parameter
970 // type of G<int>.E and conversion would fail without inflate in this
974 clone.parameters = new IParameterData[Count];
975 for (int i = 0; i < Count; ++i) {
976 var fp = FixedParameters[i];
977 clone.FixedParameters[i] = fp;
979 if (!fp.HasDefaultValue)
982 var expr = fp.DefaultValue;
984 if (inflated_types[i] == expr.Type)
987 var c = expr as Constant;
990 // It may fail we are inflating before type validation is done
992 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
994 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
997 } else if (expr is DefaultValueExpression)
998 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1000 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1007 public string ParameterDesc (int pos)
1009 if (types == null || types [pos] == null)
1010 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1012 string type = types [pos].GetSignatureForError ();
1013 if (FixedParameters [pos].HasExtensionMethodModifier)
1014 return "this " + type;
1016 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1020 return Parameter.GetModifierSignature (mod) + " " + type;
1023 public TypeSpec[] Types {
1024 get { return types; }
1025 set { types = value; }
1030 // A collection of imported or resolved parameters
1032 public class ParametersImported : AParametersCollection
1034 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1036 this.parameters = parameters;
1038 this.has_arglist = hasArglist;
1039 this.has_params = hasParams;
1042 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1044 this.parameters = param;
1046 this.has_params = hasParams;
1051 /// Represents the methods parameters
1053 public class ParametersCompiled : AParametersCollection
1055 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1057 // Used by C# 2.0 delegates
1058 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1060 private ParametersCompiled ()
1062 parameters = new Parameter [0];
1063 types = TypeSpec.EmptyTypes;
1066 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1068 this.parameters = parameters;
1072 public ParametersCompiled (params Parameter[] parameters)
1074 if (parameters == null || parameters.Length == 0)
1075 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1077 this.parameters = parameters;
1078 int count = parameters.Length;
1080 for (int i = 0; i < count; i++){
1081 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1085 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1088 this.has_arglist = has_arglist;
1091 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1093 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1096 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1098 return new ParametersCompiled (parameters, types);
1102 // TODO: This does not fit here, it should go to different version of AParametersCollection
1103 // as the underlying type is not Parameter and some methods will fail to cast
1105 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1107 var pd = new ParameterData [types.Length];
1108 for (int i = 0; i < pd.Length; ++i)
1109 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1111 return new ParametersCompiled (pd, types);
1114 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1116 return new ParametersCompiled (
1117 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1121 public void CheckConstraints (IMemberContext mc)
1123 foreach (Parameter p in parameters) {
1125 // It's null for compiler generated types or special types like __arglist
1127 if (p.TypeExpression != null)
1128 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1133 // Returns non-zero value for equal CLS parameter signatures
1135 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1139 for (int i = 0; i < a.Count; ++i) {
1140 var a_type = a.Types[i];
1141 var b_type = b.Types[i];
1142 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1143 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1149 var ac_a = a_type as ArrayContainer;
1153 var ac_b = b_type as ArrayContainer;
1157 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1162 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1173 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1175 return MergeGenerated (ctx, userParams, checkConflicts,
1176 new Parameter [] { compilerParams },
1177 new TypeSpec [] { compilerTypes });
1181 // Use this method when you merge compiler generated parameters with user parameters
1183 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1185 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1186 userParams.FixedParameters.CopyTo(all_params, 0);
1188 TypeSpec [] all_types;
1189 if (userParams.types != null) {
1190 all_types = new TypeSpec [all_params.Length];
1191 userParams.Types.CopyTo (all_types, 0);
1196 int last_filled = userParams.Count;
1198 foreach (Parameter p in compilerParams) {
1199 for (int i = 0; i < last_filled; ++i) {
1200 while (p.Name == all_params [i].Name) {
1201 if (checkConflicts && i < userParams.Count) {
1202 ctx.Report.Error (316, userParams[i].Location,
1203 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1205 p.Name = '_' + p.Name;
1208 all_params [last_filled] = p;
1209 if (all_types != null)
1210 all_types [last_filled] = compilerTypes [index++];
1214 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1215 parameters.has_params = userParams.has_params;
1220 // Parameters checks for members which don't have a block
1222 public void CheckParameters (MemberCore member)
1224 for (int i = 0; i < parameters.Length; ++i) {
1225 var name = parameters[i].Name;
1226 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1227 if (parameters[ii].Name == name)
1228 this[ii].Error_DuplicateName (member.Compiler.Report);
1233 public bool Resolve (IMemberContext ec)
1238 types = new TypeSpec [Count];
1242 for (int i = 0; i < FixedParameters.Length; ++i) {
1244 TypeSpec t = p.Resolve (ec, i);
1256 public void ResolveDefaultValues (MemberCore m)
1258 ResolveContext rc = null;
1259 for (int i = 0; i < parameters.Length; ++i) {
1260 Parameter p = (Parameter) parameters [i];
1263 // Try not to enter default values resolution if there are is not any default value possible
1265 if (p.HasDefaultValue || p.OptAttributes != null) {
1267 rc = new ResolveContext (m);
1269 p.ResolveDefaultValue (rc);
1274 // Define each type attribute (in/out/ref) and
1275 // the argument names.
1276 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1281 MethodBuilder mb = builder as MethodBuilder;
1282 ConstructorBuilder cb = builder as ConstructorBuilder;
1283 var pa = mc.Module.PredefinedAttributes;
1285 for (int i = 0; i < Count; i++) {
1286 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1290 public void VerifyClsCompliance (IMemberContext ctx)
1292 foreach (Parameter p in FixedParameters)
1293 p.IsClsCompliant (ctx);
1296 public Parameter this [int pos] {
1297 get { return (Parameter) parameters [pos]; }
1300 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1302 var initializers = new ArrayInitializer (Count, loc);
1303 foreach (Parameter p in FixedParameters) {
1305 // Each parameter expression is stored to local variable
1306 // to save some memory when referenced later.
1308 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1309 if (se.Resolve (ec)) {
1310 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1311 ec.CurrentBlock.AddScopeStatement (se);
1314 initializers.Add (p.ExpressionTreeVariableReference ());
1317 return new ArrayCreation (
1318 Parameter.ResolveParameterExpressionType (ec, loc),
1322 public ParametersCompiled Clone ()
1324 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1326 p.parameters = new IParameterData [parameters.Length];
1327 for (int i = 0; i < Count; ++i)
1328 p.parameters [i] = this [i].Clone ();
1335 // Default parameter value expression. We need this wrapper to handle
1336 // default parameter values of folded constants (e.g. indexer parameters).
1337 // The expression is resolved only once but applied to two methods which
1338 // both share reference to this expression and we ensure that resolving
1339 // this expression always returns same instance
1341 public class DefaultParameterValueExpression : CompositeExpression
1343 public DefaultParameterValueExpression (Expression expr)
1348 public void Resolve (ResolveContext rc, Parameter p)
1350 var expr = Resolve (rc);
1352 this.expr = ErrorExpression.Instance;
1358 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) {
1359 rc.Report.Error (1736, Location,
1360 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1366 var parameter_type = p.Type;
1367 if (type == parameter_type)
1370 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1372 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1373 Nullable.Wrap wrap = (Nullable.Wrap) res;
1375 if (!(res is Constant)) {
1376 rc.Report.Error (1770, Location,
1377 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1383 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1384 rc.Report.Error (1763, Location,
1385 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1386 p.Name, parameter_type.GetSignatureForError ());
1395 rc.Report.Error (1750, Location,
1396 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1397 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1399 this.expr = ErrorExpression.Instance;
1402 public override object Accept (StructuralVisitor visitor)
1404 return visitor.Visit (this);