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) {
571 // LAMESPEC: Some really weird csc behaviour which we have to mimic
572 // User operators returning same type as parameter type are considered
573 // valid for this attribute only
575 // struct S { public static implicit operator S (int i) {} }
577 // void M ([DefaultParameterValue (3)]S s)
579 var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
580 if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
584 rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
588 var opt_attr = attributes.Search (pa.OptionalParameter);
589 if (opt_attr != null) {
590 default_expr = EmptyExpression.MissingValue;
594 public bool HasDefaultValue {
595 get { return default_expr != null; }
598 public bool HasExtensionMethodModifier {
599 get { return (modFlags & Modifier.This) != 0; }
603 // Hoisted parameter variant
605 public HoistedParameter HoistedVariant {
607 return hoisted_variant;
610 hoisted_variant = value;
614 public Modifier ModFlags {
615 get { return modFlags & ~Modifier.This; }
620 set { name = value; }
623 public override AttributeTargets AttributeTargets {
625 return AttributeTargets.Parameter;
629 public void Error_DuplicateName (Report r)
631 r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
634 public virtual string GetSignatureForError ()
637 if (parameter_type != null)
638 type_name = parameter_type.GetSignatureForError ();
640 type_name = texpr.GetSignatureForError ();
642 string mod = GetModifierSignature (modFlags);
644 return String.Concat (mod, " ", type_name);
649 public static string GetModifierSignature (Modifier mod)
654 case Modifier.PARAMS:
665 public void IsClsCompliant (IMemberContext ctx)
667 if (parameter_type.IsCLSCompliant ())
670 ctx.Module.Compiler.Report.Warning (3001, 1, Location,
671 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
674 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
677 throw new InternalErrorException ("builder already exists");
679 var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
680 if (HasOptionalExpression)
681 pattrs |= ParameterAttributes.Optional;
684 builder = cb.DefineParameter (index, pattrs, Name);
686 builder = mb.DefineParameter (index, pattrs, Name);
688 if (OptAttributes != null)
689 OptAttributes.Emit ();
691 if (HasDefaultValue && default_expr.Type != null) {
693 // Emit constant values for true constants only, the other
694 // constant-like expressions will rely on default value expression
696 var def_value = DefaultValue;
697 Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
699 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
700 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
702 builder.SetConstant (c.GetValue ());
704 } else if (default_expr.Type.IsStruct || default_expr.Type.IsGenericParameter) {
706 // Handles special case where default expression is used with value-type or type parameter
708 // void Foo (S s = default (S)) {}
710 builder.SetConstant (null);
714 if (parameter_type != null) {
715 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
716 pa.Dynamic.EmitAttribute (builder);
717 } else if (parameter_type.HasDynamicElement) {
718 pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
723 public Parameter Clone ()
725 Parameter p = (Parameter) MemberwiseClone ();
726 if (attributes != null)
727 p.attributes = attributes.Clone ();
732 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
734 if ((modFlags & Modifier.RefOutMask) != 0)
735 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
737 expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
738 expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
740 Arguments arguments = new Arguments (2);
741 arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
742 arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
743 return new SimpleAssign (ExpressionTreeVariableReference (),
744 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
747 public void Emit (EmitContext ec)
749 ec.EmitArgumentLoad (idx);
752 public void EmitAssign (EmitContext ec)
754 ec.EmitArgumentStore (idx);
757 public void EmitAddressOf (EmitContext ec)
759 if ((ModFlags & Modifier.RefOutMask) != 0) {
760 ec.EmitArgumentLoad (idx);
762 ec.EmitArgumentAddress (idx);
766 public TemporaryVariableReference ExpressionTreeVariableReference ()
768 return expr_tree_variable;
772 // System.Linq.Expressions.ParameterExpression type
774 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
776 TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
777 return new TypeExpression (p_type, location);
780 public void SetIndex (int index)
785 public void Warning_UselessOptionalParameter (Report Report)
787 Report.Warning (1066, 1, Location,
788 "The default value specified for optional parameter `{0}' will never be used",
794 // Imported or resolved parameter information
796 public class ParameterData : IParameterData
798 readonly string name;
799 readonly Parameter.Modifier modifiers;
800 readonly Expression default_value;
802 public ParameterData (string name, Parameter.Modifier modifiers)
805 this.modifiers = modifiers;
808 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
809 : this (name, modifiers)
811 this.default_value = defaultValue;
814 #region IParameterData Members
816 public Expression DefaultValue {
817 get { return default_value; }
820 public bool HasExtensionMethodModifier {
821 get { return (modifiers & Parameter.Modifier.This) != 0; }
824 public bool HasDefaultValue {
825 get { return default_value != null; }
828 public Parameter.Modifier ModFlags {
829 get { return modifiers; }
839 public abstract class AParametersCollection
841 protected bool has_arglist;
842 protected bool has_params;
844 // Null object pattern
845 protected IParameterData [] parameters;
846 protected TypeSpec [] types;
848 public CallingConventions CallingConvention {
851 CallingConventions.VarArgs :
852 CallingConventions.Standard;
857 get { return parameters.Length; }
860 public TypeSpec ExtensionMethodType {
865 return FixedParameters [0].HasExtensionMethodModifier ?
870 public IParameterData [] FixedParameters {
876 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
878 return (modFlags & Parameter.Modifier.OUT) != 0 ?
879 ParameterAttributes.Out : ParameterAttributes.None;
882 // Very expensive operation
883 public MetaType[] GetMetaInfo ()
888 return MetaType.EmptyTypes;
890 types = new MetaType[Count - 1];
893 return MetaType.EmptyTypes;
895 types = new MetaType[Count];
898 for (int i = 0; i < types.Length; ++i) {
899 types[i] = Types[i].GetMetaInfo ();
901 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
904 // TODO MemberCache: Should go to MetaInfo getter
905 types [i] = types [i].MakeByRefType ();
912 // Returns the parameter information based on the name
914 public int GetParameterIndexByName (string name)
916 for (int idx = 0; idx < Count; ++idx) {
917 if (parameters [idx].Name == name)
924 public string GetSignatureForDocumentation ()
929 StringBuilder sb = new StringBuilder ("(");
930 for (int i = 0; i < Count; ++i) {
934 sb.Append (types [i].GetSignatureForDocumentation ());
936 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
941 return sb.ToString ();
944 public string GetSignatureForError ()
946 return GetSignatureForError ("(", ")", Count);
949 public string GetSignatureForError (string start, string end, int count)
951 StringBuilder sb = new StringBuilder (start);
952 for (int i = 0; i < count; ++i) {
955 sb.Append (ParameterDesc (i));
958 return sb.ToString ();
961 public bool HasArglist {
962 get { return has_arglist; }
965 public bool HasExtensionMethodType {
970 return FixedParameters [0].HasExtensionMethodModifier;
974 public bool HasParams {
975 get { return has_params; }
978 public bool IsEmpty {
979 get { return parameters.Length == 0; }
982 public AParametersCollection Inflate (TypeParameterInflator inflator)
984 TypeSpec[] inflated_types = null;
985 bool default_value = false;
987 for (int i = 0; i < Count; ++i) {
988 var inflated_param = inflator.Inflate (types[i]);
989 if (inflated_types == null) {
990 if (inflated_param == types[i])
993 default_value |= FixedParameters[i].HasDefaultValue;
994 inflated_types = new TypeSpec[types.Length];
995 Array.Copy (types, inflated_types, types.Length);
997 if (inflated_param == types[i])
1000 default_value |= FixedParameters[i].HasDefaultValue;
1003 inflated_types[i] = inflated_param;
1006 if (inflated_types == null)
1009 var clone = (AParametersCollection) MemberwiseClone ();
1010 clone.types = inflated_types;
1013 // Default expression is original expression from the parameter
1014 // declaration context which can be of nested enum in generic class type.
1015 // In such case we end up with expression type of G<T>.E and e.g. parameter
1016 // type of G<int>.E and conversion would fail without inflate in this
1019 if (default_value) {
1020 clone.parameters = new IParameterData[Count];
1021 for (int i = 0; i < Count; ++i) {
1022 var fp = FixedParameters[i];
1023 clone.FixedParameters[i] = fp;
1025 if (!fp.HasDefaultValue)
1028 var expr = fp.DefaultValue;
1030 if (inflated_types[i] == expr.Type)
1033 var c = expr as Constant;
1036 // It may fail we are inflating before type validation is done
1038 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
1040 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1043 } else if (expr is DefaultValueExpression)
1044 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
1046 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
1053 public string ParameterDesc (int pos)
1055 if (types == null || types [pos] == null)
1056 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1058 string type = types [pos].GetSignatureForError ();
1059 if (FixedParameters [pos].HasExtensionMethodModifier)
1060 return "this " + type;
1062 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1066 return Parameter.GetModifierSignature (mod) + " " + type;
1069 public TypeSpec[] Types {
1070 get { return types; }
1071 set { types = value; }
1076 // A collection of imported or resolved parameters
1078 public class ParametersImported : AParametersCollection
1080 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1082 this.parameters = parameters;
1084 this.has_arglist = hasArglist;
1085 this.has_params = hasParams;
1088 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1090 this.parameters = param;
1092 this.has_params = hasParams;
1097 /// Represents the methods parameters
1099 public class ParametersCompiled : AParametersCollection
1101 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1103 // Used by C# 2.0 delegates
1104 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1106 private ParametersCompiled ()
1108 parameters = new Parameter [0];
1109 types = TypeSpec.EmptyTypes;
1112 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1114 this.parameters = parameters;
1118 public ParametersCompiled (params Parameter[] parameters)
1120 if (parameters == null || parameters.Length == 0)
1121 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1123 this.parameters = parameters;
1124 int count = parameters.Length;
1126 for (int i = 0; i < count; i++){
1127 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1131 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1134 this.has_arglist = has_arglist;
1137 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1139 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1142 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1144 return new ParametersCompiled (parameters, types);
1147 public static ParametersCompiled Prefix (ParametersCompiled parameters, Parameter p, TypeSpec type)
1149 var ptypes = new TypeSpec [parameters.Count + 1];
1151 Array.Copy (parameters.Types, 0, ptypes, 1, parameters.Count);
1153 var param = new Parameter [ptypes.Length];
1155 for (int i = 0; i < parameters.Count; ++i) {
1156 var pi = parameters [i];
1158 pi.SetIndex (i + 1);
1161 return ParametersCompiled.CreateFullyResolved (param, ptypes);
1165 // TODO: This does not fit here, it should go to different version of AParametersCollection
1166 // as the underlying type is not Parameter and some methods will fail to cast
1168 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1170 var pd = new ParameterData [types.Length];
1171 for (int i = 0; i < pd.Length; ++i)
1172 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1174 return new ParametersCompiled (pd, types);
1177 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1179 return new ParametersCompiled (
1180 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1184 public void CheckConstraints (IMemberContext mc)
1186 foreach (Parameter p in parameters) {
1188 // It's null for compiler generated types or special types like __arglist
1190 if (p.TypeExpression != null)
1191 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1196 // Returns non-zero value for equal CLS parameter signatures
1198 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1202 for (int i = 0; i < a.Count; ++i) {
1203 var a_type = a.Types[i];
1204 var b_type = b.Types[i];
1205 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1206 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1212 var ac_a = a_type as ArrayContainer;
1216 var ac_b = b_type as ArrayContainer;
1220 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1225 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1236 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1238 return MergeGenerated (ctx, userParams, checkConflicts,
1239 new Parameter [] { compilerParams },
1240 new TypeSpec [] { compilerTypes });
1244 // Use this method when you merge compiler generated parameters with user parameters
1246 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1248 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1249 userParams.FixedParameters.CopyTo(all_params, 0);
1251 TypeSpec [] all_types;
1252 if (userParams.types != null) {
1253 all_types = new TypeSpec [all_params.Length];
1254 userParams.Types.CopyTo (all_types, 0);
1259 int last_filled = userParams.Count;
1261 foreach (Parameter p in compilerParams) {
1262 for (int i = 0; i < last_filled; ++i) {
1263 while (p.Name == all_params [i].Name) {
1264 if (checkConflicts && i < userParams.Count) {
1265 ctx.Report.Error (316, userParams[i].Location,
1266 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1268 p.Name = '_' + p.Name;
1271 all_params [last_filled] = p;
1272 if (all_types != null)
1273 all_types [last_filled] = compilerTypes [index++];
1277 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1278 parameters.has_params = userParams.has_params;
1283 // Parameters checks for members which don't have a block
1285 public void CheckParameters (MemberCore member)
1287 for (int i = 0; i < parameters.Length; ++i) {
1288 var name = parameters[i].Name;
1289 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1290 if (parameters[ii].Name == name)
1291 this[ii].Error_DuplicateName (member.Compiler.Report);
1296 public bool Resolve (IMemberContext ec)
1301 types = new TypeSpec [Count];
1305 for (int i = 0; i < FixedParameters.Length; ++i) {
1307 TypeSpec t = p.Resolve (ec, i);
1319 public void ResolveDefaultValues (MemberCore m)
1321 ResolveContext rc = null;
1322 for (int i = 0; i < parameters.Length; ++i) {
1323 Parameter p = (Parameter) parameters [i];
1326 // Try not to enter default values resolution if there are is not any default value possible
1328 if (p.HasDefaultValue || p.OptAttributes != null) {
1330 rc = new ResolveContext (m);
1332 p.ResolveDefaultValue (rc);
1337 // Define each type attribute (in/out/ref) and
1338 // the argument names.
1339 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1344 MethodBuilder mb = builder as MethodBuilder;
1345 ConstructorBuilder cb = builder as ConstructorBuilder;
1346 var pa = mc.Module.PredefinedAttributes;
1348 for (int i = 0; i < Count; i++) {
1349 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1353 public void VerifyClsCompliance (IMemberContext ctx)
1355 foreach (Parameter p in FixedParameters)
1356 p.IsClsCompliant (ctx);
1359 public Parameter this [int pos] {
1360 get { return (Parameter) parameters [pos]; }
1363 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1365 var initializers = new ArrayInitializer (Count, loc);
1366 foreach (Parameter p in FixedParameters) {
1368 // Each parameter expression is stored to local variable
1369 // to save some memory when referenced later.
1371 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1372 if (se.Resolve (ec)) {
1373 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1374 ec.CurrentBlock.AddScopeStatement (se);
1377 initializers.Add (p.ExpressionTreeVariableReference ());
1380 return new ArrayCreation (
1381 Parameter.ResolveParameterExpressionType (ec, loc),
1385 public ParametersCompiled Clone ()
1387 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1389 p.parameters = new IParameterData [parameters.Length];
1390 for (int i = 0; i < Count; ++i)
1391 p.parameters [i] = this [i].Clone ();
1398 // Default parameter value expression. We need this wrapper to handle
1399 // default parameter values of folded constants (e.g. indexer parameters).
1400 // The expression is resolved only once but applied to two methods which
1401 // both share reference to this expression and we ensure that resolving
1402 // this expression always returns same instance
1404 public class DefaultParameterValueExpression : CompositeExpression
1406 public DefaultParameterValueExpression (Expression expr)
1411 public void Resolve (ResolveContext rc, Parameter p)
1413 var expr = Resolve (rc);
1415 this.expr = ErrorExpression.Instance;
1421 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsGeneratedStructConstructor))) {
1422 if (!(expr is ErrorExpression)) {
1423 rc.Report.Error (1736, Location,
1424 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1431 var parameter_type = p.Type;
1432 if (type == parameter_type)
1435 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1437 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1438 Nullable.Wrap wrap = (Nullable.Wrap) res;
1440 if (!(res is Constant)) {
1441 rc.Report.Error (1770, Location,
1442 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1448 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1449 rc.Report.Error (1763, Location,
1450 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1451 p.Name, parameter_type.GetSignatureForError ());
1460 rc.Report.Error (1750, Location,
1461 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1462 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1464 this.expr = ErrorExpression.Instance;
1467 public override object Accept (StructuralVisitor visitor)
1469 return visitor.Visit (this);