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);
730 if (parameter_type.HasNamedTupleElement) {
731 pa.TupleElementNames.EmitAttribute (builder, parameter_type, Location);
736 public Parameter Clone ()
738 Parameter p = (Parameter) MemberwiseClone ();
739 if (attributes != null)
740 p.attributes = attributes.Clone ();
745 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
747 if ((modFlags & Modifier.RefOutMask) != 0)
748 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
750 expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
751 expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
753 Arguments arguments = new Arguments (2);
754 arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
755 arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
756 return new SimpleAssign (ExpressionTreeVariableReference (),
757 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
760 public void Emit (EmitContext ec)
762 ec.EmitArgumentLoad (idx);
765 public void EmitAssign (EmitContext ec)
767 ec.EmitArgumentStore (idx);
770 public void EmitAddressOf (EmitContext ec)
772 if ((ModFlags & Modifier.RefOutMask) != 0) {
773 ec.EmitArgumentLoad (idx);
775 ec.EmitArgumentAddress (idx);
779 public TemporaryVariableReference ExpressionTreeVariableReference ()
781 return expr_tree_variable;
785 // System.Linq.Expressions.ParameterExpression type
787 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
789 TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
790 return new TypeExpression (p_type, location);
793 public void SetIndex (int index)
798 public void Warning_UselessOptionalParameter (Report Report)
800 Report.Warning (1066, 1, Location,
801 "The default value specified for optional parameter `{0}' will never be used",
807 // Imported or resolved parameter information
809 public class ParameterData : IParameterData
811 readonly string name;
812 readonly Parameter.Modifier modifiers;
813 readonly Expression default_value;
815 public ParameterData (string name, Parameter.Modifier modifiers)
818 this.modifiers = modifiers;
821 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
822 : this (name, modifiers)
824 this.default_value = defaultValue;
827 #region IParameterData Members
829 public Expression DefaultValue {
830 get { return default_value; }
833 public bool HasExtensionMethodModifier {
834 get { return (modifiers & Parameter.Modifier.This) != 0; }
837 public bool HasDefaultValue {
838 get { return default_value != null; }
841 public Parameter.Modifier ModFlags {
842 get { return modifiers; }
852 public abstract class AParametersCollection
854 protected bool has_arglist;
855 protected bool has_params;
857 // Null object pattern
858 protected IParameterData [] parameters;
859 protected TypeSpec [] types;
861 public CallingConventions CallingConvention {
864 CallingConventions.VarArgs :
865 CallingConventions.Standard;
870 get { return parameters.Length; }
873 public TypeSpec ExtensionMethodType {
878 return FixedParameters [0].HasExtensionMethodModifier ?
883 public IParameterData [] FixedParameters {
889 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
891 return (modFlags & Parameter.Modifier.OUT) != 0 ?
892 ParameterAttributes.Out : ParameterAttributes.None;
895 // Very expensive operation
896 public MetaType[] GetMetaInfo ()
901 return MetaType.EmptyTypes;
903 types = new MetaType[Count - 1];
906 return MetaType.EmptyTypes;
908 types = new MetaType[Count];
911 for (int i = 0; i < types.Length; ++i) {
912 types[i] = Types[i].GetMetaInfo ();
914 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
917 // TODO MemberCache: Should go to MetaInfo getter
918 types [i] = types [i].MakeByRefType ();
925 // Returns the parameter information based on the name
927 public int GetParameterIndexByName (string name)
929 for (int idx = 0; idx < Count; ++idx) {
930 if (parameters [idx].Name == name)
937 public string GetSignatureForDocumentation ()
942 StringBuilder sb = new StringBuilder ("(");
943 for (int i = 0; i < Count; ++i) {
947 sb.Append (types [i].GetSignatureForDocumentation ());
949 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
954 return sb.ToString ();
957 public string GetSignatureForError ()
959 return GetSignatureForError ("(", ")", Count);
962 public string GetSignatureForError (string start, string end, int count)
964 StringBuilder sb = new StringBuilder (start);
965 for (int i = 0; i < count; ++i) {
968 sb.Append (ParameterDesc (i));
971 return sb.ToString ();
974 public static bool HasSameParameterDefaults (AParametersCollection a, AParametersCollection b)
979 for (int i = 0; i < a.Count; ++i) {
980 if (a.FixedParameters [i].HasDefaultValue != b.FixedParameters [i].HasDefaultValue)
987 public bool HasArglist {
988 get { return has_arglist; }
991 public bool HasExtensionMethodType {
996 return FixedParameters [0].HasExtensionMethodModifier;
1000 public bool HasParams {
1001 get { return has_params; }
1004 public bool IsEmpty {
1005 get { return parameters.Length == 0; }
1008 public AParametersCollection Inflate (TypeParameterInflator inflator)
1010 TypeSpec[] inflated_types = null;
1011 bool default_value = false;
1013 for (int i = 0; i < Count; ++i) {
1014 var inflated_param = inflator.Inflate (types[i]);
1015 if (inflated_types == null) {
1016 if (inflated_param == types[i])
1019 default_value |= FixedParameters[i].HasDefaultValue;
1020 inflated_types = new TypeSpec[types.Length];
1021 Array.Copy (types, inflated_types, types.Length);
1023 if (inflated_param == types[i])
1026 default_value |= FixedParameters[i].HasDefaultValue;
1029 inflated_types[i] = inflated_param;
1032 if (inflated_types == null)
1035 var clone = (AParametersCollection) MemberwiseClone ();
1036 clone.types = inflated_types;
1039 // Default expression is original expression from the parameter
1040 // declaration context which can be of nested enum in generic class type.
1041 // In such case we end up with expression type of G<T>.E and e.g. parameter
1042 // type of G<int>.E and conversion would fail without inflate in this
1045 if (default_value) {
1046 clone.parameters = new IParameterData[Count];
1047 for (int i = 0; i < Count; ++i) {
1048 var fp = FixedParameters[i];
1049 clone.FixedParameters[i] = fp;
1051 if (!fp.HasDefaultValue)
1054 var expr = fp.DefaultValue;
1056 if (inflated_types[i] == expr.Type)
1059 var c = expr as Constant;
1062 // It may fail we are inflating before type validation is done
1064 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1066 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1069 } else if (expr is DefaultValueExpression)
1070 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1072 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1079 public string ParameterDesc (int pos)
1081 if (types == null || types [pos] == null)
1082 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1084 string type = types [pos].GetSignatureForError ();
1085 if (FixedParameters [pos].HasExtensionMethodModifier)
1086 return "this " + type;
1088 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1092 return Parameter.GetModifierSignature (mod) + " " + type;
1095 public TypeSpec[] Types {
1096 get { return types; }
1097 set { types = value; }
1102 // A collection of imported or resolved parameters
1104 public class ParametersImported : AParametersCollection
1106 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1108 this.parameters = parameters;
1110 this.has_arglist = hasArglist;
1111 this.has_params = hasParams;
1114 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1116 this.parameters = param;
1118 this.has_params = hasParams;
1123 /// Represents the methods parameters
1125 public class ParametersCompiled : AParametersCollection
1127 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1129 // Used by C# 2.0 delegates
1130 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1132 private ParametersCompiled ()
1134 parameters = new Parameter [0];
1135 types = TypeSpec.EmptyTypes;
1138 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1140 this.parameters = parameters;
1144 public ParametersCompiled (params Parameter[] parameters)
1146 if (parameters == null || parameters.Length == 0)
1147 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1149 this.parameters = parameters;
1150 int count = parameters.Length;
1152 for (int i = 0; i < count; i++){
1153 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1157 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1160 this.has_arglist = has_arglist;
1163 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1165 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1168 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1170 return new ParametersCompiled (parameters, types);
1173 public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1175 var ptypes = new TypeSpec [parameters.Count + 1];
1177 Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1179 var param = new Parameter [ptypes.Length];
1181 for (int i = 0; i < parameters.Count; ++i) {
1182 var pi = parameters [i];
1184 pi.SetIndex (i + 1);
1187 return ParametersCompiled.CreateFullyResolved (param, ptypes);
1191 // TODO: This does not fit here, it should go to different version of AParametersCollection
1192 // as the underlying type is not Parameter and some methods will fail to cast
1194 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1196 var pd = new ParameterData [types.Length];
1197 for (int i = 0; i < pd.Length; ++i)
1198 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1200 return new ParametersCompiled (pd, types);
1203 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1205 return new ParametersCompiled (
1206 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1210 public void CheckConstraints (IMemberContext mc)
1212 foreach (Parameter p in parameters) {
1214 // It's null for compiler generated types or special types like __arglist
1216 if (p.TypeExpression != null)
1217 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1222 // Returns non-zero value for equal CLS parameter signatures
1224 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1228 for (int i = 0; i < a.Count; ++i) {
1229 var a_type = a.Types[i];
1230 var b_type = b.Types[i];
1231 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1232 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1238 var ac_a = a_type as ArrayContainer;
1242 var ac_b = b_type as ArrayContainer;
1246 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1251 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1262 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1264 return MergeGenerated (ctx, userParams, checkConflicts,
1265 new Parameter [] { compilerParams },
1266 new TypeSpec [] { compilerTypes });
1270 // Use this method when you merge compiler generated parameters with user parameters
1272 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1274 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1275 userParams.FixedParameters.CopyTo(all_params, 0);
1277 TypeSpec [] all_types;
1278 if (userParams.types != null) {
1279 all_types = new TypeSpec [all_params.Length];
1280 userParams.Types.CopyTo (all_types, 0);
1285 int last_filled = userParams.Count;
1287 foreach (Parameter p in compilerParams) {
1288 for (int i = 0; i < last_filled; ++i) {
1289 while (p.Name == all_params [i].Name) {
1290 if (checkConflicts && i < userParams.Count) {
1291 ctx.Report.Error (316, userParams[i].Location,
1292 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1294 p.Name = '_' + p.Name;
1297 all_params [last_filled] = p;
1298 if (all_types != null)
1299 all_types [last_filled] = compilerTypes [index++];
1303 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1304 parameters.has_params = userParams.has_params;
1309 // Parameters checks for members which don't have a block
1311 public void CheckParameters (MemberCore member)
1313 for (int i = 0; i < parameters.Length; ++i) {
1314 var name = parameters[i].Name;
1315 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1316 if (parameters[ii].Name == name)
1317 this[ii].Error_DuplicateName (member.Compiler.Report);
1322 public bool Resolve (IMemberContext ec)
1327 types = new TypeSpec [Count];
1331 for (int i = 0; i < FixedParameters.Length; ++i) {
1333 TypeSpec t = p.Resolve (ec, i);
1345 public void ResolveDefaultValues (MemberCore m)
1347 ResolveContext rc = null;
1348 for (int i = 0; i < parameters.Length; ++i) {
1349 Parameter p = (Parameter) parameters [i];
1352 p.Type.CheckObsoleteness (m, p.Location);
1355 // Try not to enter default values resolution if there are is not any default value possible
1357 if (p.HasDefaultValue || p.OptAttributes != null) {
1359 rc = new ResolveContext (m);
1361 p.ResolveDefaultValue (rc);
1366 // Define each type attribute (in/out/ref) and
1367 // the argument names.
1368 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1373 MethodBuilder mb = builder as MethodBuilder;
1374 ConstructorBuilder cb = builder as ConstructorBuilder;
1375 var pa = mc.Module.PredefinedAttributes;
1377 for (int i = 0; i < Count; i++) {
1378 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1382 public void VerifyClsCompliance (IMemberContext ctx)
1384 foreach (Parameter p in FixedParameters)
1385 p.IsClsCompliant (ctx);
1388 public Parameter this [int pos] {
1389 get { return (Parameter) parameters [pos]; }
1392 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1394 var initializers = new ArrayInitializer (Count, loc);
1395 foreach (Parameter p in FixedParameters) {
1397 // Each parameter expression is stored to local variable
1398 // to save some memory when referenced later.
1400 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1401 if (se.Resolve (ec)) {
1402 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1403 ec.CurrentBlock.AddScopeStatement (se);
1406 initializers.Add (p.ExpressionTreeVariableReference ());
1409 return new ArrayCreation (
1410 Parameter.ResolveParameterExpressionType (ec, loc),
1414 public ParametersCompiled Clone ()
1416 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1418 p.parameters = new IParameterData [parameters.Length];
1419 for (int i = 0; i < Count; ++i)
1420 p.parameters [i] = this [i].Clone ();
1427 // Default parameter value expression. We need this wrapper to handle
1428 // default parameter values of folded constants (e.g. indexer parameters).
1429 // The expression is resolved only once but applied to two methods which
1430 // both share reference to this expression and we ensure that resolving
1431 // this expression always returns same instance
1433 public class DefaultParameterValueExpression : CompositeExpression
1435 public DefaultParameterValueExpression (Expression expr)
1440 public void Resolve (ResolveContext rc, Parameter p)
1442 var expr = Resolve (rc);
1444 this.expr = ErrorExpression.Instance;
1450 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsGeneratedStructConstructor))) {
1451 if (!(expr is ErrorExpression)) {
1452 rc.Report.Error (1736, Location,
1453 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1460 var parameter_type = p.Type;
1461 if (type == parameter_type)
1464 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1466 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1467 Nullable.Wrap wrap = (Nullable.Wrap) res;
1469 if (!(res is Constant)) {
1470 rc.Report.Error (1770, Location,
1471 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1477 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1478 rc.Report.Error (1763, Location,
1479 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1480 p.Name, parameter_type.GetSignatureForError ());
1489 rc.Report.Error (1750, Location,
1490 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1491 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1493 this.expr = ErrorExpression.Instance;
1496 public override object Accept (StructuralVisitor visitor)
1498 return visitor.Visit (this);