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 {
146 bool ParamsAttributeEmit;
148 public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
149 base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
153 public override TypeSpec Resolve (IMemberContext ec, int index)
155 if (base.Resolve (ec, index) == null)
158 var ac = parameter_type as ArrayContainer;
159 if (ac == null || ac.Rank != 1) {
160 ec.Module.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array");
164 var mc = ec as MemberCore;
165 ParamsAttributeEmit = mc == null || (mc.ModFlags & Modifiers.OVERRIDE) == 0;
167 return parameter_type;
170 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
172 base.ApplyAttributes (mb, cb, index, pa);
174 if (ParamsAttributeEmit)
175 pa.ParamArray.EmitAttribute (builder);
179 public class ArglistParameter : Parameter {
180 // Doesn't have proper type because it's never chosen for better conversion
181 public ArglistParameter (Location loc) :
182 base (null, String.Empty, Parameter.Modifier.NONE, null, loc)
184 parameter_type = InternalType.Arglist;
187 public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
192 public override bool CheckAccessibility (InterfaceMemberBase member)
197 public override TypeSpec Resolve (IMemberContext ec, int index)
199 return parameter_type;
203 public interface IParameterData
205 Expression DefaultValue { get; }
206 bool HasExtensionMethodModifier { get; }
207 bool HasDefaultValue { get; }
208 Parameter.Modifier ModFlags { get; }
213 // Parameter information created by parser
215 public class Parameter : ParameterBase, IParameterData, ILocalVariable // TODO: INamedBlockVariable
218 public enum Modifier : byte {
224 CallerMemberName = 1 << 4,
225 CallerLineNumber = 1 << 5,
226 CallerFilePath = 1 << 6,
228 RefOutMask = REF | OUT,
229 ModifierMask = PARAMS | REF | OUT | This,
230 CallerMask = CallerMemberName | CallerLineNumber | CallerFilePath
233 static readonly string[] attribute_targets = new [] { "param" };
235 FullNamedExpression texpr;
238 Expression default_expr;
239 protected TypeSpec parameter_type;
240 readonly Location loc;
242 public bool HasAddressTaken;
244 TemporaryVariableReference expr_tree_variable;
246 HoistedParameter hoisted_variant;
248 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
255 // Only assign, attributes will be attached during resolve
256 base.attributes = attrs;
261 public Expression DefaultExpression {
267 public DefaultParameterValueExpression DefaultValue {
269 return default_expr as DefaultParameterValueExpression;
272 default_expr = value;
276 Expression IParameterData.DefaultValue {
278 var expr = default_expr as DefaultParameterValueExpression;
279 return expr == null ? default_expr : expr.Child;
283 bool HasOptionalExpression {
285 return default_expr is DefaultParameterValueExpression;
289 public Location Location {
295 public Modifier ParameterModifier {
301 public TypeSpec Type {
303 return parameter_type;
306 parameter_type = value;
310 public FullNamedExpression TypeExpression {
316 public override string[] ValidAttributeTargets {
318 return attribute_targets;
324 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes 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);
382 bool IsValidCallerContext (MemberCore memberContext)
384 var m = memberContext as Method;
386 return !m.IsPartialImplementation;
392 // Resolve is used in method definitions
394 public virtual TypeSpec Resolve (IMemberContext rc, int index)
396 if (parameter_type != null)
397 return parameter_type;
399 if (attributes != null)
400 attributes.AttachTo (this, rc);
402 parameter_type = texpr.ResolveAsType (rc);
403 if (parameter_type == null)
408 if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
409 rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
410 GetSignatureForError ());
414 VarianceDecl.CheckTypeVariance (parameter_type,
415 (modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
418 if (parameter_type.IsStatic) {
419 rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
420 texpr.GetSignatureForError ());
421 return parameter_type;
424 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
425 rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
426 parameter_type.GetSignatureForError ());
429 return parameter_type;
432 void ResolveCallerAttributes (ResolveContext rc)
434 var pa = rc.Module.PredefinedAttributes;
435 TypeSpec caller_type;
436 Attribute callerMemberName = null, callerFilePath = null;
438 foreach (var attr in attributes.Attrs) {
439 var atype = attr.ResolveTypeForComparison ();
443 if (atype == pa.CallerMemberNameAttribute) {
444 caller_type = rc.BuiltinTypes.String;
445 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
446 rc.Report.Error (4019, attr.Location,
447 "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
448 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
451 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
452 rc.Report.Warning (4026, 1, attr.Location,
453 "The CallerMemberName applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
457 modFlags |= Modifier.CallerMemberName;
458 callerMemberName = attr;
462 if (atype == pa.CallerLineNumberAttribute) {
463 caller_type = rc.BuiltinTypes.Int;
464 if (caller_type != parameter_type && !Convert.ImplicitStandardConversionExists (new IntConstant (caller_type, int.MaxValue, Location.Null), parameter_type)) {
465 rc.Report.Error (4017, attr.Location,
466 "The CallerLineNumberAttribute attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
467 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
470 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
471 rc.Report.Warning (4024, 1, attr.Location,
472 "The CallerLineNumberAttribute applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
476 modFlags |= Modifier.CallerLineNumber;
480 if (atype == pa.CallerFilePathAttribute) {
481 caller_type = rc.BuiltinTypes.String;
482 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
483 rc.Report.Error (4018, attr.Location,
484 "The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
485 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
488 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
489 rc.Report.Warning (4025, 1, attr.Location,
490 "The CallerFilePath applied to parameter `{0}' will have no effect because it applies to a member that is used in context that do not allow optional arguments",
494 modFlags |= Modifier.CallerFilePath;
495 callerFilePath = attr;
500 if ((modFlags & Modifier.CallerLineNumber) != 0) {
501 if (callerMemberName != null) {
502 rc.Report.Warning (7081, 1, callerMemberName.Location,
503 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
507 if (callerFilePath != null) {
508 rc.Report.Warning (7082, 1, callerFilePath.Location,
509 "The CallerFilePathAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
514 if ((modFlags & Modifier.CallerMemberName) != 0) {
515 if (callerFilePath != null) {
516 rc.Report.Warning (7080, 1, callerFilePath.Location,
517 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerFilePathAttribute",
524 public void ResolveDefaultValue (ResolveContext rc)
527 // Default value was specified using an expression
529 if (default_expr != null) {
530 ((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
531 if (attributes != null)
532 ResolveCallerAttributes (rc);
537 if (attributes == null)
540 var pa = rc.Module.PredefinedAttributes;
541 var def_attr = attributes.Search (pa.DefaultParameterValue);
542 if (def_attr != null) {
543 if (def_attr.Resolve () == null)
546 var default_expr_attr = def_attr.GetParameterDefaultValue ();
547 if (default_expr_attr == null)
550 var dpa_rc = def_attr.CreateResolveContext ();
551 default_expr = default_expr_attr.Resolve (dpa_rc);
553 if (default_expr is BoxedCast)
554 default_expr = ((BoxedCast) default_expr).Child;
556 Constant c = default_expr as Constant;
558 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
559 rc.Report.Error (1910, default_expr.Location,
560 "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
561 default_expr.Type.GetSignatureForError ());
563 rc.Report.Error (1909, default_expr.Location,
564 "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
565 default_expr.Type.GetSignatureForError ());
572 if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
573 (default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
574 parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object ||
575 parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
580 // LAMESPEC: Some really weird csc behaviour which we have to mimic
581 // User operators returning same type as parameter type are considered
582 // valid for this attribute only
584 // struct S { public static implicit operator S (int i) {} }
586 // void M ([DefaultParameterValue (3)]S s)
588 var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
589 if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
593 rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
597 var opt_attr = attributes.Search (pa.OptionalParameter);
598 if (opt_attr != null) {
599 default_expr = EmptyExpression.MissingValue;
603 public bool HasDefaultValue {
604 get { return default_expr != null; }
607 public bool HasExtensionMethodModifier {
608 get { return (modFlags & Modifier.This) != 0; }
612 // Hoisted parameter variant
614 public HoistedParameter HoistedVariant {
616 return hoisted_variant;
619 hoisted_variant = value;
623 public Modifier ModFlags {
624 get { return modFlags & ~Modifier.This; }
629 set { name = value; }
632 public override AttributeTargets AttributeTargets {
634 return AttributeTargets.Parameter;
638 public void Error_DuplicateName (Report r)
640 r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
643 public virtual string GetSignatureForError ()
646 if (parameter_type != null)
647 type_name = parameter_type.GetSignatureForError ();
649 type_name = texpr.GetSignatureForError ();
651 string mod = GetModifierSignature (modFlags);
653 return String.Concat (mod, " ", type_name);
658 public static string GetModifierSignature (Modifier mod)
663 case Modifier.PARAMS:
674 public void IsClsCompliant (IMemberContext ctx)
676 if (parameter_type.IsCLSCompliant ())
679 ctx.Module.Compiler.Report.Warning (3001, 1, Location,
680 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
683 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
686 throw new InternalErrorException ("builder already exists");
688 var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
689 if (HasOptionalExpression)
690 pattrs |= ParameterAttributes.Optional;
693 builder = cb.DefineParameter (index, pattrs, Name);
695 builder = mb.DefineParameter (index, pattrs, Name);
697 if (OptAttributes != null)
698 OptAttributes.Emit ();
700 if (HasDefaultValue && default_expr.Type != null) {
702 // Emit constant values for true constants only, the other
703 // constant-like expressions will rely on default value expression
705 var def_value = DefaultValue;
706 Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
708 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
709 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
711 builder.SetConstant (c.GetValue ());
713 } else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
715 // Handles special case where default expression is used with value-type or type parameter
717 // void Foo (S s = default (S)) {}
719 builder.SetConstant (null);
723 if (parameter_type != null) {
724 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
725 pa.Dynamic.EmitAttribute (builder);
726 } else if (parameter_type.HasDynamicElement) {
727 pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
732 public Parameter Clone ()
734 Parameter p = (Parameter) MemberwiseClone ();
735 if (attributes != null)
736 p.attributes = attributes.Clone ();
741 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
743 if ((modFlags & Modifier.RefOutMask) != 0)
744 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
746 expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
747 expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
749 Arguments arguments = new Arguments (2);
750 arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
751 arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
752 return new SimpleAssign (ExpressionTreeVariableReference (),
753 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
756 public void Emit (EmitContext ec)
758 ec.EmitArgumentLoad (idx);
761 public void EmitAssign (EmitContext ec)
763 ec.EmitArgumentStore (idx);
766 public void EmitAddressOf (EmitContext ec)
768 if ((ModFlags & Modifier.RefOutMask) != 0) {
769 ec.EmitArgumentLoad (idx);
771 ec.EmitArgumentAddress (idx);
775 public TemporaryVariableReference ExpressionTreeVariableReference ()
777 return expr_tree_variable;
781 // System.Linq.Expressions.ParameterExpression type
783 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
785 TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
786 return new TypeExpression (p_type, location);
789 public void SetIndex (int index)
794 public void Warning_UselessOptionalParameter (Report Report)
796 Report.Warning (1066, 1, Location,
797 "The default value specified for optional parameter `{0}' will never be used",
803 // Imported or resolved parameter information
805 public class ParameterData : IParameterData
807 readonly string name;
808 readonly Parameter.Modifier modifiers;
809 readonly Expression default_value;
811 public ParameterData (string name, Parameter.Modifier modifiers)
814 this.modifiers = modifiers;
817 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
818 : this (name, modifiers)
820 this.default_value = defaultValue;
823 #region IParameterData Members
825 public Expression DefaultValue {
826 get { return default_value; }
829 public bool HasExtensionMethodModifier {
830 get { return (modifiers & Parameter.Modifier.This) != 0; }
833 public bool HasDefaultValue {
834 get { return default_value != null; }
837 public Parameter.Modifier ModFlags {
838 get { return modifiers; }
848 public abstract class AParametersCollection
850 protected bool has_arglist;
851 protected bool has_params;
853 // Null object pattern
854 protected IParameterData [] parameters;
855 protected TypeSpec [] types;
857 public CallingConventions CallingConvention {
860 CallingConventions.VarArgs :
861 CallingConventions.Standard;
866 get { return parameters.Length; }
869 public TypeSpec ExtensionMethodType {
874 return FixedParameters [0].HasExtensionMethodModifier ?
879 public IParameterData [] FixedParameters {
885 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
887 return (modFlags & Parameter.Modifier.OUT) != 0 ?
888 ParameterAttributes.Out : ParameterAttributes.None;
891 // Very expensive operation
892 public MetaType[] GetMetaInfo ()
897 return MetaType.EmptyTypes;
899 types = new MetaType[Count - 1];
902 return MetaType.EmptyTypes;
904 types = new MetaType[Count];
907 for (int i = 0; i < types.Length; ++i) {
908 types[i] = Types[i].GetMetaInfo ();
910 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
913 // TODO MemberCache: Should go to MetaInfo getter
914 types [i] = types [i].MakeByRefType ();
921 // Returns the parameter information based on the name
923 public int GetParameterIndexByName (string name)
925 for (int idx = 0; idx < Count; ++idx) {
926 if (parameters [idx].Name == name)
933 public string GetSignatureForDocumentation ()
938 StringBuilder sb = new StringBuilder ("(");
939 for (int i = 0; i < Count; ++i) {
943 sb.Append (types [i].GetSignatureForDocumentation ());
945 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
950 return sb.ToString ();
953 public string GetSignatureForError ()
955 return GetSignatureForError ("(", ")", Count);
958 public string GetSignatureForError (string start, string end, int count)
960 StringBuilder sb = new StringBuilder (start);
961 for (int i = 0; i < count; ++i) {
964 sb.Append (ParameterDesc (i));
967 return sb.ToString ();
970 public static bool HasSameParameterDefaults (AParametersCollection a, AParametersCollection b)
975 for (int i = 0; i < a.Count; ++i) {
976 if (a.FixedParameters [i].HasDefaultValue != b.FixedParameters [i].HasDefaultValue)
983 public bool HasArglist {
984 get { return has_arglist; }
987 public bool HasExtensionMethodType {
992 return FixedParameters [0].HasExtensionMethodModifier;
996 public bool HasParams {
997 get { return has_params; }
1000 public bool IsEmpty {
1001 get { return parameters.Length == 0; }
1004 public AParametersCollection Inflate (TypeParameterInflator inflator)
1006 TypeSpec[] inflated_types = null;
1007 bool default_value = false;
1009 for (int i = 0; i < Count; ++i) {
1010 var inflated_param = inflator.Inflate (types[i]);
1011 if (inflated_types == null) {
1012 if (inflated_param == types[i])
1015 default_value |= FixedParameters[i].HasDefaultValue;
1016 inflated_types = new TypeSpec[types.Length];
1017 Array.Copy (types, inflated_types, types.Length);
1019 if (inflated_param == types[i])
1022 default_value |= FixedParameters[i].HasDefaultValue;
1025 inflated_types[i] = inflated_param;
1028 if (inflated_types == null)
1031 var clone = (AParametersCollection) MemberwiseClone ();
1032 clone.types = inflated_types;
1035 // Default expression is original expression from the parameter
1036 // declaration context which can be of nested enum in generic class type.
1037 // In such case we end up with expression type of G<T>.E and e.g. parameter
1038 // type of G<int>.E and conversion would fail without inflate in this
1041 if (default_value) {
1042 clone.parameters = new IParameterData[Count];
1043 for (int i = 0; i < Count; ++i) {
1044 var fp = FixedParameters[i];
1045 clone.FixedParameters[i] = fp;
1047 if (!fp.HasDefaultValue)
1050 var expr = fp.DefaultValue;
1052 if (inflated_types[i] == expr.Type)
1055 var c = expr as Constant;
1058 // It may fail we are inflating before type validation is done
1060 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1062 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1065 } else if (expr is DefaultValueExpression)
1066 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1068 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1075 public string ParameterDesc (int pos)
1077 if (types == null || types [pos] == null)
1078 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1080 string type = types [pos].GetSignatureForError ();
1081 if (FixedParameters [pos].HasExtensionMethodModifier)
1082 return "this " + type;
1084 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1088 return Parameter.GetModifierSignature (mod) + " " + type;
1091 public TypeSpec[] Types {
1092 get { return types; }
1093 set { types = value; }
1098 // A collection of imported or resolved parameters
1100 public class ParametersImported : AParametersCollection
1102 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1104 this.parameters = parameters;
1106 this.has_arglist = hasArglist;
1107 this.has_params = hasParams;
1110 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1112 this.parameters = param;
1114 this.has_params = hasParams;
1119 /// Represents the methods parameters
1121 public class ParametersCompiled : AParametersCollection
1123 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1125 // Used by C# 2.0 delegates
1126 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1128 private ParametersCompiled ()
1130 parameters = new Parameter [0];
1131 types = TypeSpec.EmptyTypes;
1134 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1136 this.parameters = parameters;
1140 public ParametersCompiled (params Parameter[] parameters)
1142 if (parameters == null || parameters.Length == 0)
1143 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1145 this.parameters = parameters;
1146 int count = parameters.Length;
1148 for (int i = 0; i < count; i++){
1149 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1153 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1156 this.has_arglist = has_arglist;
1159 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1161 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1164 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1166 return new ParametersCompiled (parameters, types);
1169 public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1171 var ptypes = new TypeSpec [parameters.Count + 1];
1173 Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1175 var param = new Parameter [ptypes.Length];
1177 for (int i = 0; i < parameters.Count; ++i) {
1178 var pi = parameters [i];
1180 pi.SetIndex (i + 1);
1183 return ParametersCompiled.CreateFullyResolved (param, ptypes);
1187 // TODO: This does not fit here, it should go to different version of AParametersCollection
1188 // as the underlying type is not Parameter and some methods will fail to cast
1190 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1192 var pd = new ParameterData [types.Length];
1193 for (int i = 0; i < pd.Length; ++i)
1194 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1196 return new ParametersCompiled (pd, types);
1199 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1201 return new ParametersCompiled (
1202 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1206 public void CheckConstraints (IMemberContext mc)
1208 foreach (Parameter p in parameters) {
1210 // It's null for compiler generated types or special types like __arglist
1212 if (p.TypeExpression != null)
1213 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1218 // Returns non-zero value for equal CLS parameter signatures
1220 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1224 for (int i = 0; i < a.Count; ++i) {
1225 var a_type = a.Types[i];
1226 var b_type = b.Types[i];
1227 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1228 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1234 var ac_a = a_type as ArrayContainer;
1238 var ac_b = b_type as ArrayContainer;
1242 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1247 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1258 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1260 return MergeGenerated (ctx, userParams, checkConflicts,
1261 new Parameter [] { compilerParams },
1262 new TypeSpec [] { compilerTypes });
1266 // Use this method when you merge compiler generated parameters with user parameters
1268 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1270 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1271 userParams.FixedParameters.CopyTo(all_params, 0);
1273 TypeSpec [] all_types;
1274 if (userParams.types != null) {
1275 all_types = new TypeSpec [all_params.Length];
1276 userParams.Types.CopyTo (all_types, 0);
1281 int last_filled = userParams.Count;
1283 foreach (Parameter p in compilerParams) {
1284 for (int i = 0; i < last_filled; ++i) {
1285 while (p.Name == all_params [i].Name) {
1286 if (checkConflicts && i < userParams.Count) {
1287 ctx.Report.Error (316, userParams[i].Location,
1288 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1290 p.Name = '_' + p.Name;
1293 all_params [last_filled] = p;
1294 if (all_types != null)
1295 all_types [last_filled] = compilerTypes [index++];
1299 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1300 parameters.has_params = userParams.has_params;
1305 // Parameters checks for members which don't have a block
1307 public void CheckParameters (MemberCore member)
1309 for (int i = 0; i < parameters.Length; ++i) {
1310 var name = parameters[i].Name;
1311 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1312 if (parameters[ii].Name == name)
1313 this[ii].Error_DuplicateName (member.Compiler.Report);
1318 public bool Resolve (IMemberContext ec)
1323 types = new TypeSpec [Count];
1327 for (int i = 0; i < FixedParameters.Length; ++i) {
1329 TypeSpec t = p.Resolve (ec, i);
1341 public void ResolveDefaultValues (MemberCore m)
1343 ResolveContext rc = null;
1344 for (int i = 0; i < parameters.Length; ++i) {
1345 Parameter p = (Parameter) parameters [i];
1348 p.Type.CheckObsoleteness (m, p.Location);
1351 // Try not to enter default values resolution if there are is not any default value possible
1353 if (p.HasDefaultValue || p.OptAttributes != null) {
1355 rc = new ResolveContext (m);
1357 p.ResolveDefaultValue (rc);
1362 // Define each type attribute (in/out/ref) and
1363 // the argument names.
1364 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1369 MethodBuilder mb = builder as MethodBuilder;
1370 ConstructorBuilder cb = builder as ConstructorBuilder;
1371 var pa = mc.Module.PredefinedAttributes;
1373 for (int i = 0; i < Count; i++) {
1374 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1378 public void VerifyClsCompliance (IMemberContext ctx)
1380 foreach (Parameter p in FixedParameters)
1381 p.IsClsCompliant (ctx);
1384 public Parameter this [int pos] {
1385 get { return (Parameter) parameters [pos]; }
1388 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1390 var initializers = new ArrayInitializer (Count, loc);
1391 foreach (Parameter p in FixedParameters) {
1393 // Each parameter expression is stored to local variable
1394 // to save some memory when referenced later.
1396 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1397 if (se.Resolve (ec)) {
1398 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1399 ec.CurrentBlock.AddScopeStatement (se);
1402 initializers.Add (p.ExpressionTreeVariableReference ());
1405 return new ArrayCreation (
1406 Parameter.ResolveParameterExpressionType (ec, loc),
1410 public ParametersCompiled Clone ()
1412 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1414 p.parameters = new IParameterData [parameters.Length];
1415 for (int i = 0; i < Count; ++i)
1416 p.parameters [i] = this [i].Clone ();
1423 // Default parameter value expression. We need this wrapper to handle
1424 // default parameter values of folded constants (e.g. indexer parameters).
1425 // The expression is resolved only once but applied to two methods which
1426 // both share reference to this expression and we ensure that resolving
1427 // this expression always returns same instance
1429 public class DefaultParameterValueExpression : CompositeExpression
1431 public DefaultParameterValueExpression (Expression expr)
1436 public void Resolve (ResolveContext rc, Parameter p)
1438 var expr = Resolve (rc);
1440 this.expr = ErrorExpression.Instance;
1446 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsGeneratedStructConstructor))) {
1447 if (!(expr is ErrorExpression)) {
1448 rc.Report.Error (1736, Location,
1449 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1456 var parameter_type = p.Type;
1457 if (type == parameter_type)
1460 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1462 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1463 Nullable.Wrap wrap = (Nullable.Wrap) res;
1465 if (!(res is Constant)) {
1466 rc.Report.Error (1770, Location,
1467 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1473 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1474 rc.Report.Error (1763, Location,
1475 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1476 p.Name, parameter_type.GetSignatureForError ());
1485 rc.Report.Error (1750, Location,
1486 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1487 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1489 this.expr = ErrorExpression.Instance;
1492 public override object Accept (StructuralVisitor visitor)
1494 return visitor.Visit (this);