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);
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 var ctor = rc.CurrentMemberDefinition as Constructor;
403 if (ctor != null && ctor.IsPrimaryConstructor)
404 primary_constructor = ctor;
406 parameter_type = texpr.ResolveAsType (rc);
407 if (parameter_type == null)
412 if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
413 rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
414 GetSignatureForError ());
418 VarianceDecl.CheckTypeVariance (parameter_type,
419 (modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
422 if (parameter_type.IsStatic) {
423 rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
424 texpr.GetSignatureForError ());
425 return parameter_type;
428 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
429 rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
430 parameter_type.GetSignatureForError ());
433 return parameter_type;
436 void ResolveCallerAttributes (ResolveContext rc)
438 var pa = rc.Module.PredefinedAttributes;
439 TypeSpec caller_type;
440 Attribute callerMemberName = null, callerFilePath = null;
442 foreach (var attr in attributes.Attrs) {
443 var atype = attr.ResolveTypeForComparison ();
447 if (atype == pa.CallerMemberNameAttribute) {
448 caller_type = rc.BuiltinTypes.String;
449 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
450 rc.Report.Error (4019, attr.Location,
451 "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
452 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
455 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
456 rc.Report.Warning (4026, 1, attr.Location,
457 "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",
461 modFlags |= Modifier.CallerMemberName;
462 callerMemberName = attr;
466 if (atype == pa.CallerLineNumberAttribute) {
467 caller_type = rc.BuiltinTypes.Int;
468 if (caller_type != parameter_type && !Convert.ImplicitStandardConversionExists (new IntConstant (caller_type, int.MaxValue, Location.Null), parameter_type)) {
469 rc.Report.Error (4017, attr.Location,
470 "The CallerLineNumberAttribute attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
471 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
474 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
475 rc.Report.Warning (4024, 1, attr.Location,
476 "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",
480 modFlags |= Modifier.CallerLineNumber;
484 if (atype == pa.CallerFilePathAttribute) {
485 caller_type = rc.BuiltinTypes.String;
486 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
487 rc.Report.Error (4018, attr.Location,
488 "The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
489 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
492 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
493 rc.Report.Warning (4025, 1, attr.Location,
494 "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",
498 modFlags |= Modifier.CallerFilePath;
499 callerFilePath = attr;
504 if ((modFlags & Modifier.CallerLineNumber) != 0) {
505 if (callerMemberName != null) {
506 rc.Report.Warning (7081, 1, callerMemberName.Location,
507 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
511 if (callerFilePath != null) {
512 rc.Report.Warning (7082, 1, callerFilePath.Location,
513 "The CallerFilePathAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
518 if ((modFlags & Modifier.CallerMemberName) != 0) {
519 if (callerFilePath != null) {
520 rc.Report.Warning (7080, 1, callerFilePath.Location,
521 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerFilePathAttribute",
528 public void ResolveDefaultValue (ResolveContext rc)
531 // Default value was specified using an expression
533 if (default_expr != null) {
534 ((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
535 if (attributes != null)
536 ResolveCallerAttributes (rc);
541 if (attributes == null)
544 var pa = rc.Module.PredefinedAttributes;
545 var def_attr = attributes.Search (pa.DefaultParameterValue);
546 if (def_attr != null) {
547 if (def_attr.Resolve () == null)
550 var default_expr_attr = def_attr.GetParameterDefaultValue ();
551 if (default_expr_attr == null)
554 var dpa_rc = def_attr.CreateResolveContext ();
555 default_expr = default_expr_attr.Resolve (dpa_rc);
557 if (default_expr is BoxedCast)
558 default_expr = ((BoxedCast) default_expr).Child;
560 Constant c = default_expr as Constant;
562 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
563 rc.Report.Error (1910, default_expr.Location,
564 "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
565 default_expr.Type.GetSignatureForError ());
567 rc.Report.Error (1909, default_expr.Location,
568 "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
569 default_expr.Type.GetSignatureForError ());
576 if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
577 (default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
578 parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
583 // LAMESPEC: Some really weird csc behaviour which we have to mimic
584 // User operators returning same type as parameter type are considered
585 // valid for this attribute only
587 // struct S { public static implicit operator S (int i) {} }
589 // void M ([DefaultParameterValue (3)]S s)
591 var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
592 if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
596 rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
600 var opt_attr = attributes.Search (pa.OptionalParameter);
601 if (opt_attr != null) {
602 default_expr = EmptyExpression.MissingValue;
606 public bool HasDefaultValue {
607 get { return default_expr != null; }
610 public bool HasExtensionMethodModifier {
611 get { return (modFlags & Modifier.This) != 0; }
615 // Hoisted parameter variant
617 public HoistedParameter HoistedVariant {
619 return hoisted_variant;
622 hoisted_variant = value;
626 public Modifier ModFlags {
627 get { return modFlags & ~Modifier.This; }
632 set { name = value; }
635 public override AttributeTargets AttributeTargets {
637 return AttributeTargets.Parameter;
641 public void Error_DuplicateName (Report r)
643 r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
646 public virtual string GetSignatureForError ()
649 if (parameter_type != null)
650 type_name = parameter_type.GetSignatureForError ();
652 type_name = texpr.GetSignatureForError ();
654 string mod = GetModifierSignature (modFlags);
656 return String.Concat (mod, " ", type_name);
661 public static string GetModifierSignature (Modifier mod)
666 case Modifier.PARAMS:
677 public void IsClsCompliant (IMemberContext ctx)
679 if (parameter_type.IsCLSCompliant ())
682 ctx.Module.Compiler.Report.Warning (3001, 1, Location,
683 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
686 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
689 throw new InternalErrorException ("builder already exists");
691 var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
692 if (HasOptionalExpression)
693 pattrs |= ParameterAttributes.Optional;
696 builder = cb.DefineParameter (index, pattrs, Name);
698 builder = mb.DefineParameter (index, pattrs, Name);
700 if (OptAttributes != null)
701 OptAttributes.Emit ();
703 if (HasDefaultValue && default_expr.Type != null) {
705 // Emit constant values for true constants only, the other
706 // constant-like expressions will rely on default value expression
708 var def_value = DefaultValue;
709 Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
711 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
712 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
714 builder.SetConstant (c.GetValue ());
716 } else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
718 // Handles special case where default expression is used with value-type or type parameter
720 // void Foo (S s = default (S)) {}
722 builder.SetConstant (null);
726 if (parameter_type != null) {
727 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
728 pa.Dynamic.EmitAttribute (builder);
729 } else if (parameter_type.HasDynamicElement) {
730 pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
735 public Parameter Clone ()
737 Parameter p = (Parameter) MemberwiseClone ();
738 if (attributes != null)
739 p.attributes = attributes.Clone ();
744 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
746 if ((modFlags & Modifier.RefOutMask) != 0)
747 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
749 expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
750 expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
752 Arguments arguments = new Arguments (2);
753 arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
754 arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
755 return new SimpleAssign (ExpressionTreeVariableReference (),
756 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
759 public void Emit (EmitContext ec)
761 ec.EmitArgumentLoad (idx);
764 public void EmitAssign (EmitContext ec)
766 ec.EmitArgumentStore (idx);
769 public void EmitAddressOf (EmitContext ec)
771 if ((ModFlags & Modifier.RefOutMask) != 0) {
772 ec.EmitArgumentLoad (idx);
774 ec.EmitArgumentAddress (idx);
778 public TemporaryVariableReference ExpressionTreeVariableReference ()
780 return expr_tree_variable;
784 // System.Linq.Expressions.ParameterExpression type
786 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
788 TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
789 return new TypeExpression (p_type, location);
792 public void SetIndex (int index)
797 public void Warning_UselessOptionalParameter (Report Report)
799 Report.Warning (1066, 1, Location,
800 "The default value specified for optional parameter `{0}' will never be used",
806 // Imported or resolved parameter information
808 public class ParameterData : IParameterData
810 readonly string name;
811 readonly Parameter.Modifier modifiers;
812 readonly Expression default_value;
814 public ParameterData (string name, Parameter.Modifier modifiers)
817 this.modifiers = modifiers;
820 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
821 : this (name, modifiers)
823 this.default_value = defaultValue;
826 #region IParameterData Members
828 public Expression DefaultValue {
829 get { return default_value; }
832 public bool HasExtensionMethodModifier {
833 get { return (modifiers & Parameter.Modifier.This) != 0; }
836 public bool HasDefaultValue {
837 get { return default_value != null; }
840 public Parameter.Modifier ModFlags {
841 get { return modifiers; }
851 public abstract class AParametersCollection
853 protected bool has_arglist;
854 protected bool has_params;
856 // Null object pattern
857 protected IParameterData [] parameters;
858 protected TypeSpec [] types;
860 public CallingConventions CallingConvention {
863 CallingConventions.VarArgs :
864 CallingConventions.Standard;
869 get { return parameters.Length; }
872 public TypeSpec ExtensionMethodType {
877 return FixedParameters [0].HasExtensionMethodModifier ?
882 public IParameterData [] FixedParameters {
888 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
890 return (modFlags & Parameter.Modifier.OUT) != 0 ?
891 ParameterAttributes.Out : ParameterAttributes.None;
894 // Very expensive operation
895 public MetaType[] GetMetaInfo ()
900 return MetaType.EmptyTypes;
902 types = new MetaType[Count - 1];
905 return MetaType.EmptyTypes;
907 types = new MetaType[Count];
910 for (int i = 0; i < types.Length; ++i) {
911 types[i] = Types[i].GetMetaInfo ();
913 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
916 // TODO MemberCache: Should go to MetaInfo getter
917 types [i] = types [i].MakeByRefType ();
924 // Returns the parameter information based on the name
926 public int GetParameterIndexByName (string name)
928 for (int idx = 0; idx < Count; ++idx) {
929 if (parameters [idx].Name == name)
936 public string GetSignatureForDocumentation ()
941 StringBuilder sb = new StringBuilder ("(");
942 for (int i = 0; i < Count; ++i) {
946 sb.Append (types [i].GetSignatureForDocumentation ());
948 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
953 return sb.ToString ();
956 public string GetSignatureForError ()
958 return GetSignatureForError ("(", ")", Count);
961 public string GetSignatureForError (string start, string end, int count)
963 StringBuilder sb = new StringBuilder (start);
964 for (int i = 0; i < count; ++i) {
967 sb.Append (ParameterDesc (i));
970 return sb.ToString ();
973 public bool HasArglist {
974 get { return has_arglist; }
977 public bool HasExtensionMethodType {
982 return FixedParameters [0].HasExtensionMethodModifier;
986 public bool HasParams {
987 get { return has_params; }
990 public bool IsEmpty {
991 get { return parameters.Length == 0; }
994 public AParametersCollection Inflate (TypeParameterInflator inflator)
996 TypeSpec[] inflated_types = null;
997 bool default_value = false;
999 for (int i = 0; i < Count; ++i) {
1000 var inflated_param = inflator.Inflate (types[i]);
1001 if (inflated_types == null) {
1002 if (inflated_param == types[i])
1005 default_value |= FixedParameters[i].HasDefaultValue;
1006 inflated_types = new TypeSpec[types.Length];
1007 Array.Copy (types, inflated_types, types.Length);
1009 if (inflated_param == types[i])
1012 default_value |= FixedParameters[i].HasDefaultValue;
1015 inflated_types[i] = inflated_param;
1018 if (inflated_types == null)
1021 var clone = (AParametersCollection) MemberwiseClone ();
1022 clone.types = inflated_types;
1025 // Default expression is original expression from the parameter
1026 // declaration context which can be of nested enum in generic class type.
1027 // In such case we end up with expression type of G<T>.E and e.g. parameter
1028 // type of G<int>.E and conversion would fail without inflate in this
1031 if (default_value) {
1032 clone.parameters = new IParameterData[Count];
1033 for (int i = 0; i < Count; ++i) {
1034 var fp = FixedParameters[i];
1035 clone.FixedParameters[i] = fp;
1037 if (!fp.HasDefaultValue)
1040 var expr = fp.DefaultValue;
1042 if (inflated_types[i] == expr.Type)
1045 var c = expr as Constant;
1048 // It may fail we are inflating before type validation is done
1050 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1052 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1055 } else if (expr is DefaultValueExpression)
1056 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1058 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1065 public string ParameterDesc (int pos)
1067 if (types == null || types [pos] == null)
1068 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1070 string type = types [pos].GetSignatureForError ();
1071 if (FixedParameters [pos].HasExtensionMethodModifier)
1072 return "this " + type;
1074 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1078 return Parameter.GetModifierSignature (mod) + " " + type;
1081 public TypeSpec[] Types {
1082 get { return types; }
1083 set { types = value; }
1088 // A collection of imported or resolved parameters
1090 public class ParametersImported : AParametersCollection
1092 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1094 this.parameters = parameters;
1096 this.has_arglist = hasArglist;
1097 this.has_params = hasParams;
1100 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1102 this.parameters = param;
1104 this.has_params = hasParams;
1109 /// Represents the methods parameters
1111 public class ParametersCompiled : AParametersCollection
1113 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1115 // Used by C# 2.0 delegates
1116 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1118 private ParametersCompiled ()
1120 parameters = new Parameter [0];
1121 types = TypeSpec.EmptyTypes;
1124 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1126 this.parameters = parameters;
1130 public ParametersCompiled (params Parameter[] parameters)
1132 if (parameters == null || parameters.Length == 0)
1133 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1135 this.parameters = parameters;
1136 int count = parameters.Length;
1138 for (int i = 0; i < count; i++){
1139 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1143 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1146 this.has_arglist = has_arglist;
1149 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1151 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1154 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1156 return new ParametersCompiled (parameters, types);
1159 public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1161 var ptypes = new TypeSpec [parameters.Count + 1];
1163 Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1165 var param = new Parameter [ptypes.Length];
1167 for (int i = 0; i < parameters.Count; ++i) {
1168 var pi = parameters [i];
1170 pi.SetIndex (i + 1);
1173 return ParametersCompiled.CreateFullyResolved (param, ptypes);
1177 // TODO: This does not fit here, it should go to different version of AParametersCollection
1178 // as the underlying type is not Parameter and some methods will fail to cast
1180 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1182 var pd = new ParameterData [types.Length];
1183 for (int i = 0; i < pd.Length; ++i)
1184 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1186 return new ParametersCompiled (pd, types);
1189 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1191 return new ParametersCompiled (
1192 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1196 public void CheckConstraints (IMemberContext mc)
1198 foreach (Parameter p in parameters) {
1200 // It's null for compiler generated types or special types like __arglist
1202 if (p.TypeExpression != null)
1203 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1208 // Returns non-zero value for equal CLS parameter signatures
1210 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1214 for (int i = 0; i < a.Count; ++i) {
1215 var a_type = a.Types[i];
1216 var b_type = b.Types[i];
1217 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1218 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1224 var ac_a = a_type as ArrayContainer;
1228 var ac_b = b_type as ArrayContainer;
1232 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1237 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1248 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1250 return MergeGenerated (ctx, userParams, checkConflicts,
1251 new Parameter [] { compilerParams },
1252 new TypeSpec [] { compilerTypes });
1256 // Use this method when you merge compiler generated parameters with user parameters
1258 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1260 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1261 userParams.FixedParameters.CopyTo(all_params, 0);
1263 TypeSpec [] all_types;
1264 if (userParams.types != null) {
1265 all_types = new TypeSpec [all_params.Length];
1266 userParams.Types.CopyTo (all_types, 0);
1271 int last_filled = userParams.Count;
1273 foreach (Parameter p in compilerParams) {
1274 for (int i = 0; i < last_filled; ++i) {
1275 while (p.Name == all_params [i].Name) {
1276 if (checkConflicts && i < userParams.Count) {
1277 ctx.Report.Error (316, userParams[i].Location,
1278 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1280 p.Name = '_' + p.Name;
1283 all_params [last_filled] = p;
1284 if (all_types != null)
1285 all_types [last_filled] = compilerTypes [index++];
1289 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1290 parameters.has_params = userParams.has_params;
1295 // Parameters checks for members which don't have a block
1297 public void CheckParameters (MemberCore member)
1299 for (int i = 0; i < parameters.Length; ++i) {
1300 var name = parameters[i].Name;
1301 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1302 if (parameters[ii].Name == name)
1303 this[ii].Error_DuplicateName (member.Compiler.Report);
1308 public bool Resolve (IMemberContext ec)
1313 types = new TypeSpec [Count];
1317 for (int i = 0; i < FixedParameters.Length; ++i) {
1319 TypeSpec t = p.Resolve (ec, i);
1331 public void ResolveDefaultValues (MemberCore m)
1333 ResolveContext rc = null;
1334 for (int i = 0; i < parameters.Length; ++i) {
1335 Parameter p = (Parameter) parameters [i];
1338 // Try not to enter default values resolution if there are is not any default value possible
1340 if (p.HasDefaultValue || p.OptAttributes != null) {
1342 rc = new ResolveContext (m);
1344 p.ResolveDefaultValue (rc);
1349 // Define each type attribute (in/out/ref) and
1350 // the argument names.
1351 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1356 MethodBuilder mb = builder as MethodBuilder;
1357 ConstructorBuilder cb = builder as ConstructorBuilder;
1358 var pa = mc.Module.PredefinedAttributes;
1360 for (int i = 0; i < Count; i++) {
1361 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1365 public void VerifyClsCompliance (IMemberContext ctx)
1367 foreach (Parameter p in FixedParameters)
1368 p.IsClsCompliant (ctx);
1371 public Parameter this [int pos] {
1372 get { return (Parameter) parameters [pos]; }
1375 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1377 var initializers = new ArrayInitializer (Count, loc);
1378 foreach (Parameter p in FixedParameters) {
1380 // Each parameter expression is stored to local variable
1381 // to save some memory when referenced later.
1383 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1384 if (se.Resolve (ec)) {
1385 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1386 ec.CurrentBlock.AddScopeStatement (se);
1389 initializers.Add (p.ExpressionTreeVariableReference ());
1392 return new ArrayCreation (
1393 Parameter.ResolveParameterExpressionType (ec, loc),
1397 public ParametersCompiled Clone ()
1399 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1401 p.parameters = new IParameterData [parameters.Length];
1402 for (int i = 0; i < Count; ++i)
1403 p.parameters [i] = this [i].Clone ();
1410 // Default parameter value expression. We need this wrapper to handle
1411 // default parameter values of folded constants (e.g. indexer parameters).
1412 // The expression is resolved only once but applied to two methods which
1413 // both share reference to this expression and we ensure that resolving
1414 // this expression always returns same instance
1416 public class DefaultParameterValueExpression : CompositeExpression
1418 public DefaultParameterValueExpression (Expression expr)
1423 public void Resolve (ResolveContext rc, Parameter p)
1425 var expr = Resolve (rc);
1427 this.expr = ErrorExpression.Instance;
1433 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) {
1434 if (!(expr is ErrorExpression)) {
1435 rc.Report.Error (1736, Location,
1436 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1443 var parameter_type = p.Type;
1444 if (type == parameter_type)
1447 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1449 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1450 Nullable.Wrap wrap = (Nullable.Wrap) res;
1452 if (!(res is Constant)) {
1453 rc.Report.Error (1770, Location,
1454 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1460 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1461 rc.Report.Error (1763, Location,
1462 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1463 p.Name, parameter_type.GetSignatureForError ());
1472 rc.Report.Error (1750, Location,
1473 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1474 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1476 this.expr = ErrorExpression.Instance;
1479 public override object Accept (StructuralVisitor visitor)
1481 return visitor.Visit (this);