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.ImplicitNumericConversionExists (caller_type, 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 Warning_UselessOptionalParameter (Report Report)
794 Report.Warning (1066, 1, Location,
795 "The default value specified for optional parameter `{0}' will never be used",
801 // Imported or resolved parameter information
803 public class ParameterData : IParameterData
805 readonly string name;
806 readonly Parameter.Modifier modifiers;
807 readonly Expression default_value;
809 public ParameterData (string name, Parameter.Modifier modifiers)
812 this.modifiers = modifiers;
815 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
816 : this (name, modifiers)
818 this.default_value = defaultValue;
821 #region IParameterData Members
823 public Expression DefaultValue {
824 get { return default_value; }
827 public bool HasExtensionMethodModifier {
828 get { return (modifiers & Parameter.Modifier.This) != 0; }
831 public bool HasDefaultValue {
832 get { return default_value != null; }
835 public Parameter.Modifier ModFlags {
836 get { return modifiers; }
846 public abstract class AParametersCollection
848 protected bool has_arglist;
849 protected bool has_params;
851 // Null object pattern
852 protected IParameterData [] parameters;
853 protected TypeSpec [] types;
855 public CallingConventions CallingConvention {
858 CallingConventions.VarArgs :
859 CallingConventions.Standard;
864 get { return parameters.Length; }
867 public TypeSpec ExtensionMethodType {
872 return FixedParameters [0].HasExtensionMethodModifier ?
877 public IParameterData [] FixedParameters {
883 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
885 return (modFlags & Parameter.Modifier.OUT) != 0 ?
886 ParameterAttributes.Out : ParameterAttributes.None;
889 // Very expensive operation
890 public MetaType[] GetMetaInfo ()
895 return MetaType.EmptyTypes;
897 types = new MetaType[Count - 1];
900 return MetaType.EmptyTypes;
902 types = new MetaType[Count];
905 for (int i = 0; i < types.Length; ++i) {
906 types[i] = Types[i].GetMetaInfo ();
908 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
911 // TODO MemberCache: Should go to MetaInfo getter
912 types [i] = types [i].MakeByRefType ();
919 // Returns the parameter information based on the name
921 public int GetParameterIndexByName (string name)
923 for (int idx = 0; idx < Count; ++idx) {
924 if (parameters [idx].Name == name)
931 public string GetSignatureForDocumentation ()
936 StringBuilder sb = new StringBuilder ("(");
937 for (int i = 0; i < Count; ++i) {
941 sb.Append (types [i].GetSignatureForDocumentation ());
943 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
948 return sb.ToString ();
951 public string GetSignatureForError ()
953 return GetSignatureForError ("(", ")", Count);
956 public string GetSignatureForError (string start, string end, int count)
958 StringBuilder sb = new StringBuilder (start);
959 for (int i = 0; i < count; ++i) {
962 sb.Append (ParameterDesc (i));
965 return sb.ToString ();
968 public bool HasArglist {
969 get { return has_arglist; }
972 public bool HasExtensionMethodType {
977 return FixedParameters [0].HasExtensionMethodModifier;
981 public bool HasParams {
982 get { return has_params; }
985 public bool IsEmpty {
986 get { return parameters.Length == 0; }
989 public AParametersCollection Inflate (TypeParameterInflator inflator)
991 TypeSpec[] inflated_types = null;
992 bool default_value = false;
994 for (int i = 0; i < Count; ++i) {
995 var inflated_param = inflator.Inflate (types[i]);
996 if (inflated_types == null) {
997 if (inflated_param == types[i])
1000 default_value |= FixedParameters[i].HasDefaultValue;
1001 inflated_types = new TypeSpec[types.Length];
1002 Array.Copy (types, inflated_types, types.Length);
1004 if (inflated_param == types[i])
1007 default_value |= FixedParameters[i].HasDefaultValue;
1010 inflated_types[i] = inflated_param;
1013 if (inflated_types == null)
1016 var clone = (AParametersCollection) MemberwiseClone ();
1017 clone.types = inflated_types;
1020 // Default expression is original expression from the parameter
1021 // declaration context which can be of nested enum in generic class type.
1022 // In such case we end up with expression type of G<T>.E and e.g. parameter
1023 // type of G<int>.E and conversion would fail without inflate in this
1026 if (default_value) {
1027 clone.parameters = new IParameterData[Count];
1028 for (int i = 0; i < Count; ++i) {
1029 var fp = FixedParameters[i];
1030 clone.FixedParameters[i] = fp;
1032 if (!fp.HasDefaultValue)
1035 var expr = fp.DefaultValue;
1037 if (inflated_types[i] == expr.Type)
1040 var c = expr as Constant;
1043 // It may fail we are inflating before type validation is done
1045 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1047 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1050 } else if (expr is DefaultValueExpression)
1051 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1053 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1060 public string ParameterDesc (int pos)
1062 if (types == null || types [pos] == null)
1063 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1065 string type = types [pos].GetSignatureForError ();
1066 if (FixedParameters [pos].HasExtensionMethodModifier)
1067 return "this " + type;
1069 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1073 return Parameter.GetModifierSignature (mod) + " " + type;
1076 public TypeSpec[] Types {
1077 get { return types; }
1078 set { types = value; }
1083 // A collection of imported or resolved parameters
1085 public class ParametersImported : AParametersCollection
1087 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1089 this.parameters = parameters;
1091 this.has_arglist = hasArglist;
1092 this.has_params = hasParams;
1095 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1097 this.parameters = param;
1099 this.has_params = hasParams;
1104 /// Represents the methods parameters
1106 public class ParametersCompiled : AParametersCollection
1108 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1110 // Used by C# 2.0 delegates
1111 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1113 private ParametersCompiled ()
1115 parameters = new Parameter [0];
1116 types = TypeSpec.EmptyTypes;
1119 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1121 this.parameters = parameters;
1125 public ParametersCompiled (params Parameter[] parameters)
1127 if (parameters == null || parameters.Length == 0)
1128 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1130 this.parameters = parameters;
1131 int count = parameters.Length;
1133 for (int i = 0; i < count; i++){
1134 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1138 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1141 this.has_arglist = has_arglist;
1144 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1146 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1149 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1151 return new ParametersCompiled (parameters, types);
1155 // TODO: This does not fit here, it should go to different version of AParametersCollection
1156 // as the underlying type is not Parameter and some methods will fail to cast
1158 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1160 var pd = new ParameterData [types.Length];
1161 for (int i = 0; i < pd.Length; ++i)
1162 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1164 return new ParametersCompiled (pd, types);
1167 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1169 return new ParametersCompiled (
1170 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1174 public void CheckConstraints (IMemberContext mc)
1176 foreach (Parameter p in parameters) {
1178 // It's null for compiler generated types or special types like __arglist
1180 if (p.TypeExpression != null)
1181 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1186 // Returns non-zero value for equal CLS parameter signatures
1188 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1192 for (int i = 0; i < a.Count; ++i) {
1193 var a_type = a.Types[i];
1194 var b_type = b.Types[i];
1195 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1196 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1202 var ac_a = a_type as ArrayContainer;
1206 var ac_b = b_type as ArrayContainer;
1210 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1215 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1226 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1228 return MergeGenerated (ctx, userParams, checkConflicts,
1229 new Parameter [] { compilerParams },
1230 new TypeSpec [] { compilerTypes });
1234 // Use this method when you merge compiler generated parameters with user parameters
1236 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1238 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1239 userParams.FixedParameters.CopyTo(all_params, 0);
1241 TypeSpec [] all_types;
1242 if (userParams.types != null) {
1243 all_types = new TypeSpec [all_params.Length];
1244 userParams.Types.CopyTo (all_types, 0);
1249 int last_filled = userParams.Count;
1251 foreach (Parameter p in compilerParams) {
1252 for (int i = 0; i < last_filled; ++i) {
1253 while (p.Name == all_params [i].Name) {
1254 if (checkConflicts && i < userParams.Count) {
1255 ctx.Report.Error (316, userParams[i].Location,
1256 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1258 p.Name = '_' + p.Name;
1261 all_params [last_filled] = p;
1262 if (all_types != null)
1263 all_types [last_filled] = compilerTypes [index++];
1267 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1268 parameters.has_params = userParams.has_params;
1273 // Parameters checks for members which don't have a block
1275 public void CheckParameters (MemberCore member)
1277 for (int i = 0; i < parameters.Length; ++i) {
1278 var name = parameters[i].Name;
1279 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1280 if (parameters[ii].Name == name)
1281 this[ii].Error_DuplicateName (member.Compiler.Report);
1286 public bool Resolve (IMemberContext ec)
1291 types = new TypeSpec [Count];
1295 for (int i = 0; i < FixedParameters.Length; ++i) {
1297 TypeSpec t = p.Resolve (ec, i);
1309 public void ResolveDefaultValues (MemberCore m)
1311 ResolveContext rc = null;
1312 for (int i = 0; i < parameters.Length; ++i) {
1313 Parameter p = (Parameter) parameters [i];
1316 // Try not to enter default values resolution if there are is not any default value possible
1318 if (p.HasDefaultValue || p.OptAttributes != null) {
1320 rc = new ResolveContext (m);
1322 p.ResolveDefaultValue (rc);
1327 // Define each type attribute (in/out/ref) and
1328 // the argument names.
1329 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1334 MethodBuilder mb = builder as MethodBuilder;
1335 ConstructorBuilder cb = builder as ConstructorBuilder;
1336 var pa = mc.Module.PredefinedAttributes;
1338 for (int i = 0; i < Count; i++) {
1339 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1343 public void VerifyClsCompliance (IMemberContext ctx)
1345 foreach (Parameter p in FixedParameters)
1346 p.IsClsCompliant (ctx);
1349 public Parameter this [int pos] {
1350 get { return (Parameter) parameters [pos]; }
1353 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1355 var initializers = new ArrayInitializer (Count, loc);
1356 foreach (Parameter p in FixedParameters) {
1358 // Each parameter expression is stored to local variable
1359 // to save some memory when referenced later.
1361 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1362 if (se.Resolve (ec)) {
1363 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1364 ec.CurrentBlock.AddScopeStatement (se);
1367 initializers.Add (p.ExpressionTreeVariableReference ());
1370 return new ArrayCreation (
1371 Parameter.ResolveParameterExpressionType (ec, loc),
1375 public ParametersCompiled Clone ()
1377 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1379 p.parameters = new IParameterData [parameters.Length];
1380 for (int i = 0; i < Count; ++i)
1381 p.parameters [i] = this [i].Clone ();
1388 // Default parameter value expression. We need this wrapper to handle
1389 // default parameter values of folded constants (e.g. indexer parameters).
1390 // The expression is resolved only once but applied to two methods which
1391 // both share reference to this expression and we ensure that resolving
1392 // this expression always returns same instance
1394 public class DefaultParameterValueExpression : CompositeExpression
1396 public DefaultParameterValueExpression (Expression expr)
1401 public void Resolve (ResolveContext rc, Parameter p)
1403 var expr = Resolve (rc);
1405 this.expr = ErrorExpression.Instance;
1411 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) {
1412 rc.Report.Error (1736, Location,
1413 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1419 var parameter_type = p.Type;
1420 if (type == parameter_type)
1423 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1425 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1426 Nullable.Wrap wrap = (Nullable.Wrap) res;
1428 if (!(res is Constant)) {
1429 rc.Report.Error (1770, Location,
1430 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1436 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1437 rc.Report.Error (1763, Location,
1438 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1439 p.Name, parameter_type.GetSignatureForError ());
1448 rc.Report.Error (1750, Location,
1449 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1450 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1452 this.expr = ErrorExpression.Instance;
1455 public override object Accept (StructuralVisitor visitor)
1457 return visitor.Visit (this);