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 [] { "param" };
227 FullNamedExpression texpr;
230 Expression default_expr;
231 protected TypeSpec parameter_type;
232 readonly Location loc;
234 public bool HasAddressTaken;
236 TemporaryVariableReference expr_tree_variable;
238 HoistedParameter hoisted_variant;
240 public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
247 // Only assign, attributes will be attached during resolve
248 base.attributes = attrs;
253 public Expression DefaultExpression {
259 public DefaultParameterValueExpression DefaultValue {
261 return default_expr as DefaultParameterValueExpression;
264 default_expr = value;
268 Expression IParameterData.DefaultValue {
270 var expr = default_expr as DefaultParameterValueExpression;
271 return expr == null ? default_expr : expr.Child;
275 bool HasOptionalExpression {
277 return default_expr is DefaultParameterValueExpression;
281 public Location Location {
287 public Modifier ParameterModifier {
293 public TypeSpec Type {
295 return parameter_type;
298 parameter_type = value;
302 public FullNamedExpression TypeExpression {
308 public override string[] ValidAttributeTargets {
310 return attribute_targets;
316 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
318 if (a.Type == pa.In && ModFlags == Modifier.OUT) {
319 a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
323 if (a.Type == pa.ParamArray) {
324 a.Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
328 if (a.Type == pa.Out && (ModFlags & Modifier.REF) != 0 &&
329 !OptAttributes.Contains (pa.In)) {
330 a.Report.Error (662, a.Location,
331 "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
335 if (a.Type == pa.CLSCompliant) {
336 a.Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
337 } else if (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter) {
338 if (HasOptionalExpression) {
339 a.Report.Error (1745, a.Location,
340 "Cannot specify `{0}' attribute on optional parameter `{1}'",
341 a.Type.GetSignatureForError ().Replace ("Attribute", ""), Name);
344 if (a.Type == pa.DefaultParameterValue)
346 } else if (a.Type == pa.CallerMemberNameAttribute) {
347 if ((modFlags & Modifier.CallerMemberName) == 0) {
348 a.Report.Error (4022, a.Location,
349 "The CallerMemberName attribute can only be applied to parameters with default value");
351 } else if (a.Type == pa.CallerLineNumberAttribute) {
352 if ((modFlags & Modifier.CallerLineNumber) == 0) {
353 a.Report.Error (4020, a.Location,
354 "The CallerLineNumber attribute can only be applied to parameters with default value");
356 } else if (a.Type == pa.CallerFilePathAttribute) {
357 if ((modFlags & Modifier.CallerFilePath) == 0) {
358 a.Report.Error (4021, a.Location,
359 "The CallerFilePath attribute can only be applied to parameters with default value");
363 base.ApplyAttributeBuilder (a, ctor, cdata, pa);
366 public virtual bool CheckAccessibility (InterfaceMemberBase member)
368 if (parameter_type == null)
371 return member.IsAccessibleAs (parameter_type);
374 bool IsValidCallerContext (MemberCore memberContext)
376 var m = memberContext as Method;
378 return !m.IsPartialImplementation;
384 // Resolve is used in method definitions
386 public virtual TypeSpec Resolve (IMemberContext rc, int index)
388 if (parameter_type != null)
389 return parameter_type;
391 if (attributes != null)
392 attributes.AttachTo (this, rc);
394 parameter_type = texpr.ResolveAsType (rc);
395 if (parameter_type == null)
400 if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
401 rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
402 GetSignatureForError ());
406 VarianceDecl.CheckTypeVariance (parameter_type,
407 (modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
410 if (parameter_type.IsStatic) {
411 rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
412 texpr.GetSignatureForError ());
413 return parameter_type;
416 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
417 rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
418 parameter_type.GetSignatureForError ());
421 return parameter_type;
424 void ResolveCallerAttributes (ResolveContext rc)
426 var pa = rc.Module.PredefinedAttributes;
427 TypeSpec caller_type;
428 Attribute callerMemberName = null, callerFilePath = null;
430 foreach (var attr in attributes.Attrs) {
431 var atype = attr.ResolveTypeForComparison ();
435 if (atype == pa.CallerMemberNameAttribute) {
436 caller_type = rc.BuiltinTypes.String;
437 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
438 rc.Report.Error (4019, attr.Location,
439 "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
440 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
443 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
444 rc.Report.Warning (4026, 1, attr.Location,
445 "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",
449 modFlags |= Modifier.CallerMemberName;
450 callerMemberName = attr;
454 if (atype == pa.CallerLineNumberAttribute) {
455 caller_type = rc.BuiltinTypes.Int;
456 if (caller_type != parameter_type && !Convert.ImplicitStandardConversionExists (new IntConstant (caller_type, int.MaxValue, Location.Null), parameter_type)) {
457 rc.Report.Error (4017, attr.Location,
458 "The CallerLineNumberAttribute attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
459 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
462 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
463 rc.Report.Warning (4024, 1, attr.Location,
464 "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",
468 modFlags |= Modifier.CallerLineNumber;
472 if (atype == pa.CallerFilePathAttribute) {
473 caller_type = rc.BuiltinTypes.String;
474 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
475 rc.Report.Error (4018, attr.Location,
476 "The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
477 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
480 if (!IsValidCallerContext (rc.CurrentMemberDefinition)) {
481 rc.Report.Warning (4025, 1, attr.Location,
482 "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",
486 modFlags |= Modifier.CallerFilePath;
487 callerFilePath = attr;
492 if ((modFlags & Modifier.CallerLineNumber) != 0) {
493 if (callerMemberName != null) {
494 rc.Report.Warning (7081, 1, callerMemberName.Location,
495 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
499 if (callerFilePath != null) {
500 rc.Report.Warning (7082, 1, callerFilePath.Location,
501 "The CallerFilePathAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerLineNumberAttribute",
506 if ((modFlags & Modifier.CallerMemberName) != 0) {
507 if (callerFilePath != null) {
508 rc.Report.Warning (7080, 1, callerFilePath.Location,
509 "The CallerMemberNameAttribute applied to parameter `{0}' will have no effect. It is overridden by the CallerFilePathAttribute",
516 public void ResolveDefaultValue (ResolveContext rc)
519 // Default value was specified using an expression
521 if (default_expr != null) {
522 ((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
523 if (attributes != null)
524 ResolveCallerAttributes (rc);
529 if (attributes == null)
532 var pa = rc.Module.PredefinedAttributes;
533 var def_attr = attributes.Search (pa.DefaultParameterValue);
534 if (def_attr != null) {
535 if (def_attr.Resolve () == null)
538 var default_expr_attr = def_attr.GetParameterDefaultValue ();
539 if (default_expr_attr == null)
542 var dpa_rc = def_attr.CreateResolveContext ();
543 default_expr = default_expr_attr.Resolve (dpa_rc);
545 if (default_expr is BoxedCast)
546 default_expr = ((BoxedCast) default_expr).Child;
548 Constant c = default_expr as Constant;
550 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
551 rc.Report.Error (1910, default_expr.Location,
552 "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
553 default_expr.Type.GetSignatureForError ());
555 rc.Report.Error (1909, default_expr.Location,
556 "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
557 default_expr.Type.GetSignatureForError ());
564 if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
565 (default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
566 parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object ||
567 parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
572 // LAMESPEC: Some really weird csc behaviour which we have to mimic
573 // User operators returning same type as parameter type are considered
574 // valid for this attribute only
576 // struct S { public static implicit operator S (int i) {} }
578 // void M ([DefaultParameterValue (3)]S s)
580 var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
581 if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
585 rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
589 var opt_attr = attributes.Search (pa.OptionalParameter);
590 if (opt_attr != null) {
591 default_expr = EmptyExpression.MissingValue;
595 public bool HasDefaultValue {
596 get { return default_expr != null; }
599 public bool HasExtensionMethodModifier {
600 get { return (modFlags & Modifier.This) != 0; }
604 // Hoisted parameter variant
606 public HoistedParameter HoistedVariant {
608 return hoisted_variant;
611 hoisted_variant = value;
615 public Modifier ModFlags {
616 get { return modFlags & ~Modifier.This; }
621 set { name = value; }
624 public override AttributeTargets AttributeTargets {
626 return AttributeTargets.Parameter;
630 public void Error_DuplicateName (Report r)
632 r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
635 public virtual string GetSignatureForError ()
638 if (parameter_type != null)
639 type_name = parameter_type.GetSignatureForError ();
641 type_name = texpr.GetSignatureForError ();
643 string mod = GetModifierSignature (modFlags);
645 return String.Concat (mod, " ", type_name);
650 public static string GetModifierSignature (Modifier mod)
655 case Modifier.PARAMS:
666 public void IsClsCompliant (IMemberContext ctx)
668 if (parameter_type.IsCLSCompliant ())
671 ctx.Module.Compiler.Report.Warning (3001, 1, Location,
672 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
675 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
678 throw new InternalErrorException ("builder already exists");
680 var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
681 if (HasOptionalExpression)
682 pattrs |= ParameterAttributes.Optional;
685 builder = cb.DefineParameter (index, pattrs, Name);
687 builder = mb.DefineParameter (index, pattrs, Name);
689 if (OptAttributes != null)
690 OptAttributes.Emit ();
692 if (HasDefaultValue && default_expr.Type != null) {
694 // Emit constant values for true constants only, the other
695 // constant-like expressions will rely on default value expression
697 var def_value = DefaultValue;
698 Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
700 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
701 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
703 builder.SetConstant (c.GetValue ());
705 } else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
707 // Handles special case where default expression is used with value-type or type parameter
709 // void Foo (S s = default (S)) {}
711 builder.SetConstant (null);
715 if (parameter_type != null) {
716 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
717 pa.Dynamic.EmitAttribute (builder);
718 } else if (parameter_type.HasDynamicElement) {
719 pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
724 public Parameter Clone ()
726 Parameter p = (Parameter) MemberwiseClone ();
727 if (attributes != null)
728 p.attributes = attributes.Clone ();
733 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
735 if ((modFlags & Modifier.RefOutMask) != 0)
736 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
738 expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
739 expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
741 Arguments arguments = new Arguments (2);
742 arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
743 arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
744 return new SimpleAssign (ExpressionTreeVariableReference (),
745 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
748 public void Emit (EmitContext ec)
750 ec.EmitArgumentLoad (idx);
753 public void EmitAssign (EmitContext ec)
755 ec.EmitArgumentStore (idx);
758 public void EmitAddressOf (EmitContext ec)
760 if ((ModFlags & Modifier.RefOutMask) != 0) {
761 ec.EmitArgumentLoad (idx);
763 ec.EmitArgumentAddress (idx);
767 public TemporaryVariableReference ExpressionTreeVariableReference ()
769 return expr_tree_variable;
773 // System.Linq.Expressions.ParameterExpression type
775 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
777 TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
778 return new TypeExpression (p_type, location);
781 public void SetIndex (int index)
786 public void Warning_UselessOptionalParameter (Report Report)
788 Report.Warning (1066, 1, Location,
789 "The default value specified for optional parameter `{0}' will never be used",
795 // Imported or resolved parameter information
797 public class ParameterData : IParameterData
799 readonly string name;
800 readonly Parameter.Modifier modifiers;
801 readonly Expression default_value;
803 public ParameterData (string name, Parameter.Modifier modifiers)
806 this.modifiers = modifiers;
809 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
810 : this (name, modifiers)
812 this.default_value = defaultValue;
815 #region IParameterData Members
817 public Expression DefaultValue {
818 get { return default_value; }
821 public bool HasExtensionMethodModifier {
822 get { return (modifiers & Parameter.Modifier.This) != 0; }
825 public bool HasDefaultValue {
826 get { return default_value != null; }
829 public Parameter.Modifier ModFlags {
830 get { return modifiers; }
840 public abstract class AParametersCollection
842 protected bool has_arglist;
843 protected bool has_params;
845 // Null object pattern
846 protected IParameterData [] parameters;
847 protected TypeSpec [] types;
849 public CallingConventions CallingConvention {
852 CallingConventions.VarArgs :
853 CallingConventions.Standard;
858 get { return parameters.Length; }
861 public TypeSpec ExtensionMethodType {
866 return FixedParameters [0].HasExtensionMethodModifier ?
871 public IParameterData [] FixedParameters {
877 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
879 return (modFlags & Parameter.Modifier.OUT) != 0 ?
880 ParameterAttributes.Out : ParameterAttributes.None;
883 // Very expensive operation
884 public MetaType[] GetMetaInfo ()
889 return MetaType.EmptyTypes;
891 types = new MetaType[Count - 1];
894 return MetaType.EmptyTypes;
896 types = new MetaType[Count];
899 for (int i = 0; i < types.Length; ++i) {
900 types[i] = Types[i].GetMetaInfo ();
902 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
905 // TODO MemberCache: Should go to MetaInfo getter
906 types [i] = types [i].MakeByRefType ();
913 // Returns the parameter information based on the name
915 public int GetParameterIndexByName (string name)
917 for (int idx = 0; idx < Count; ++idx) {
918 if (parameters [idx].Name == name)
925 public string GetSignatureForDocumentation ()
930 StringBuilder sb = new StringBuilder ("(");
931 for (int i = 0; i < Count; ++i) {
935 sb.Append (types [i].GetSignatureForDocumentation ());
937 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
942 return sb.ToString ();
945 public string GetSignatureForError ()
947 return GetSignatureForError ("(", ")", Count);
950 public string GetSignatureForError (string start, string end, int count)
952 StringBuilder sb = new StringBuilder (start);
953 for (int i = 0; i < count; ++i) {
956 sb.Append (ParameterDesc (i));
959 return sb.ToString ();
962 public static bool HasSameParameterDefaults (AParametersCollection a, AParametersCollection b)
967 for (int i = 0; i < a.Count; ++i) {
968 if (a.FixedParameters [i].HasDefaultValue != b.FixedParameters [i].HasDefaultValue)
975 public bool HasArglist {
976 get { return has_arglist; }
979 public bool HasExtensionMethodType {
984 return FixedParameters [0].HasExtensionMethodModifier;
988 public bool HasParams {
989 get { return has_params; }
992 public bool IsEmpty {
993 get { return parameters.Length == 0; }
996 public AParametersCollection Inflate (TypeParameterInflator inflator)
998 TypeSpec[] inflated_types = null;
999 bool default_value = false;
1001 for (int i = 0; i < Count; ++i) {
1002 var inflated_param = inflator.Inflate (types[i]);
1003 if (inflated_types == null) {
1004 if (inflated_param == types[i])
1007 default_value |= FixedParameters[i].HasDefaultValue;
1008 inflated_types = new TypeSpec[types.Length];
1009 Array.Copy (types, inflated_types, types.Length);
1011 if (inflated_param == types[i])
1014 default_value |= FixedParameters[i].HasDefaultValue;
1017 inflated_types[i] = inflated_param;
1020 if (inflated_types == null)
1023 var clone = (AParametersCollection) MemberwiseClone ();
1024 clone.types = inflated_types;
1027 // Default expression is original expression from the parameter
1028 // declaration context which can be of nested enum in generic class type.
1029 // In such case we end up with expression type of G<T>.E and e.g. parameter
1030 // type of G<int>.E and conversion would fail without inflate in this
1033 if (default_value) {
1034 clone.parameters = new IParameterData[Count];
1035 for (int i = 0; i < Count; ++i) {
1036 var fp = FixedParameters[i];
1037 clone.FixedParameters[i] = fp;
1039 if (!fp.HasDefaultValue)
1042 var expr = fp.DefaultValue;
1044 if (inflated_types[i] == expr.Type)
1047 var c = expr as Constant;
1050 // It may fail we are inflating before type validation is done
1052 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1054 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1057 } else if (expr is DefaultValueExpression)
1058 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1060 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1067 public string ParameterDesc (int pos)
1069 if (types == null || types [pos] == null)
1070 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1072 string type = types [pos].GetSignatureForError ();
1073 if (FixedParameters [pos].HasExtensionMethodModifier)
1074 return "this " + type;
1076 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1080 return Parameter.GetModifierSignature (mod) + " " + type;
1083 public TypeSpec[] Types {
1084 get { return types; }
1085 set { types = value; }
1090 // A collection of imported or resolved parameters
1092 public class ParametersImported : AParametersCollection
1094 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1096 this.parameters = parameters;
1098 this.has_arglist = hasArglist;
1099 this.has_params = hasParams;
1102 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1104 this.parameters = param;
1106 this.has_params = hasParams;
1111 /// Represents the methods parameters
1113 public class ParametersCompiled : AParametersCollection
1115 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1117 // Used by C# 2.0 delegates
1118 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1120 private ParametersCompiled ()
1122 parameters = new Parameter [0];
1123 types = TypeSpec.EmptyTypes;
1126 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1128 this.parameters = parameters;
1132 public ParametersCompiled (params Parameter[] parameters)
1134 if (parameters == null || parameters.Length == 0)
1135 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1137 this.parameters = parameters;
1138 int count = parameters.Length;
1140 for (int i = 0; i < count; i++){
1141 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1145 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1148 this.has_arglist = has_arglist;
1151 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1153 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1156 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1158 return new ParametersCompiled (parameters, types);
1161 public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1163 var ptypes = new TypeSpec [parameters.Count + 1];
1165 Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1167 var param = new Parameter [ptypes.Length];
1169 for (int i = 0; i < parameters.Count; ++i) {
1170 var pi = parameters [i];
1172 pi.SetIndex (i + 1);
1175 return ParametersCompiled.CreateFullyResolved (param, ptypes);
1179 // TODO: This does not fit here, it should go to different version of AParametersCollection
1180 // as the underlying type is not Parameter and some methods will fail to cast
1182 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1184 var pd = new ParameterData [types.Length];
1185 for (int i = 0; i < pd.Length; ++i)
1186 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1188 return new ParametersCompiled (pd, types);
1191 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1193 return new ParametersCompiled (
1194 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1198 public void CheckConstraints (IMemberContext mc)
1200 foreach (Parameter p in parameters) {
1202 // It's null for compiler generated types or special types like __arglist
1204 if (p.TypeExpression != null)
1205 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1210 // Returns non-zero value for equal CLS parameter signatures
1212 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1216 for (int i = 0; i < a.Count; ++i) {
1217 var a_type = a.Types[i];
1218 var b_type = b.Types[i];
1219 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1220 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1226 var ac_a = a_type as ArrayContainer;
1230 var ac_b = b_type as ArrayContainer;
1234 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1239 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1250 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1252 return MergeGenerated (ctx, userParams, checkConflicts,
1253 new Parameter [] { compilerParams },
1254 new TypeSpec [] { compilerTypes });
1258 // Use this method when you merge compiler generated parameters with user parameters
1260 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1262 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1263 userParams.FixedParameters.CopyTo(all_params, 0);
1265 TypeSpec [] all_types;
1266 if (userParams.types != null) {
1267 all_types = new TypeSpec [all_params.Length];
1268 userParams.Types.CopyTo (all_types, 0);
1273 int last_filled = userParams.Count;
1275 foreach (Parameter p in compilerParams) {
1276 for (int i = 0; i < last_filled; ++i) {
1277 while (p.Name == all_params [i].Name) {
1278 if (checkConflicts && i < userParams.Count) {
1279 ctx.Report.Error (316, userParams[i].Location,
1280 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1282 p.Name = '_' + p.Name;
1285 all_params [last_filled] = p;
1286 if (all_types != null)
1287 all_types [last_filled] = compilerTypes [index++];
1291 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1292 parameters.has_params = userParams.has_params;
1297 // Parameters checks for members which don't have a block
1299 public void CheckParameters (MemberCore member)
1301 for (int i = 0; i < parameters.Length; ++i) {
1302 var name = parameters[i].Name;
1303 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1304 if (parameters[ii].Name == name)
1305 this[ii].Error_DuplicateName (member.Compiler.Report);
1310 public bool Resolve (IMemberContext ec)
1315 types = new TypeSpec [Count];
1319 for (int i = 0; i < FixedParameters.Length; ++i) {
1321 TypeSpec t = p.Resolve (ec, i);
1333 public void ResolveDefaultValues (MemberCore m)
1335 ResolveContext rc = null;
1336 for (int i = 0; i < parameters.Length; ++i) {
1337 Parameter p = (Parameter) parameters [i];
1340 p.Type.CheckObsoleteness (m, p.Location);
1343 // Try not to enter default values resolution if there are is not any default value possible
1345 if (p.HasDefaultValue || p.OptAttributes != null) {
1347 rc = new ResolveContext (m);
1349 p.ResolveDefaultValue (rc);
1354 // Define each type attribute (in/out/ref) and
1355 // the argument names.
1356 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1361 MethodBuilder mb = builder as MethodBuilder;
1362 ConstructorBuilder cb = builder as ConstructorBuilder;
1363 var pa = mc.Module.PredefinedAttributes;
1365 for (int i = 0; i < Count; i++) {
1366 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1370 public void VerifyClsCompliance (IMemberContext ctx)
1372 foreach (Parameter p in FixedParameters)
1373 p.IsClsCompliant (ctx);
1376 public Parameter this [int pos] {
1377 get { return (Parameter) parameters [pos]; }
1380 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1382 var initializers = new ArrayInitializer (Count, loc);
1383 foreach (Parameter p in FixedParameters) {
1385 // Each parameter expression is stored to local variable
1386 // to save some memory when referenced later.
1388 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1389 if (se.Resolve (ec)) {
1390 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1391 ec.CurrentBlock.AddScopeStatement (se);
1394 initializers.Add (p.ExpressionTreeVariableReference ());
1397 return new ArrayCreation (
1398 Parameter.ResolveParameterExpressionType (ec, loc),
1402 public ParametersCompiled Clone ()
1404 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1406 p.parameters = new IParameterData [parameters.Length];
1407 for (int i = 0; i < Count; ++i)
1408 p.parameters [i] = this [i].Clone ();
1415 // Default parameter value expression. We need this wrapper to handle
1416 // default parameter values of folded constants (e.g. indexer parameters).
1417 // The expression is resolved only once but applied to two methods which
1418 // both share reference to this expression and we ensure that resolving
1419 // this expression always returns same instance
1421 public class DefaultParameterValueExpression : CompositeExpression
1423 public DefaultParameterValueExpression (Expression expr)
1428 public void Resolve (ResolveContext rc, Parameter p)
1430 var expr = Resolve (rc);
1432 this.expr = ErrorExpression.Instance;
1438 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsGeneratedStructConstructor))) {
1439 if (!(expr is ErrorExpression)) {
1440 rc.Report.Error (1736, Location,
1441 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1448 var parameter_type = p.Type;
1449 if (type == parameter_type)
1452 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1454 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1455 Nullable.Wrap wrap = (Nullable.Wrap) res;
1457 if (!(res is Constant)) {
1458 rc.Report.Error (1770, Location,
1459 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1465 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1466 rc.Report.Error (1763, Location,
1467 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1468 p.Name, parameter_type.GetSignatureForError ());
1477 rc.Report.Error (1750, Location,
1478 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1479 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1481 this.expr = ErrorExpression.Instance;
1484 public override object Accept (StructuralVisitor visitor)
1486 return visitor.Visit (this);