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" };
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);
375 // Resolve is used in method definitions
377 public virtual TypeSpec Resolve (IMemberContext rc, int index)
379 if (parameter_type != null)
380 return parameter_type;
382 if (attributes != null)
383 attributes.AttachTo (this, rc);
385 parameter_type = texpr.ResolveAsType (rc);
386 if (parameter_type == null)
391 if ((modFlags & Parameter.Modifier.RefOutMask) != 0 && parameter_type.IsSpecialRuntimeType) {
392 rc.Module.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
393 GetSignatureForError ());
397 VarianceDecl.CheckTypeVariance (parameter_type,
398 (modFlags & Parameter.Modifier.RefOutMask) != 0 ? Variance.None : Variance.Contravariant,
401 if (parameter_type.IsStatic) {
402 rc.Module.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
403 texpr.GetSignatureForError ());
404 return parameter_type;
407 if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
408 rc.Module.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'",
409 parameter_type.GetSignatureForError ());
412 return parameter_type;
415 void ResolveCallerAttributes (ResolveContext rc)
417 var pa = rc.Module.PredefinedAttributes;
418 TypeSpec caller_type;
420 foreach (var attr in attributes.Attrs) {
421 var atype = attr.ResolveTypeForComparison ();
425 if (atype == pa.CallerMemberNameAttribute) {
426 caller_type = rc.BuiltinTypes.String;
427 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
428 rc.Report.Error (4019, attr.Location,
429 "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
430 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
433 modFlags |= Modifier.CallerMemberName;
437 if (atype == pa.CallerLineNumberAttribute) {
438 caller_type = rc.BuiltinTypes.Int;
439 if (caller_type != parameter_type && !Convert.ImplicitNumericConversionExists (caller_type, parameter_type)) {
440 rc.Report.Error (4017, attr.Location,
441 "The CallerMemberName attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
442 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
445 modFlags |= Modifier.CallerLineNumber;
449 if (atype == pa.CallerFilePathAttribute) {
450 caller_type = rc.BuiltinTypes.String;
451 if (caller_type != parameter_type && !Convert.ImplicitReferenceConversionExists (caller_type, parameter_type)) {
452 rc.Report.Error (4018, attr.Location,
453 "The CallerFilePath attribute cannot be applied because there is no standard conversion from `{0}' to `{1}'",
454 caller_type.GetSignatureForError (), parameter_type.GetSignatureForError ());
457 modFlags |= Modifier.CallerFilePath;
463 public void ResolveDefaultValue (ResolveContext rc)
466 // Default value was specified using an expression
468 if (default_expr != null) {
469 ((DefaultParameterValueExpression)default_expr).Resolve (rc, this);
470 if (attributes != null)
471 ResolveCallerAttributes (rc);
476 if (attributes == null)
479 var pa = rc.Module.PredefinedAttributes;
480 var def_attr = attributes.Search (pa.DefaultParameterValue);
481 if (def_attr != null) {
482 if (def_attr.Resolve () == null)
485 var default_expr_attr = def_attr.GetParameterDefaultValue ();
486 if (default_expr_attr == null)
489 var dpa_rc = def_attr.CreateResolveContext ();
490 default_expr = default_expr_attr.Resolve (dpa_rc);
492 if (default_expr is BoxedCast)
493 default_expr = ((BoxedCast) default_expr).Child;
495 Constant c = default_expr as Constant;
497 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
498 rc.Report.Error (1910, default_expr.Location,
499 "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
500 default_expr.Type.GetSignatureForError ());
502 rc.Report.Error (1909, default_expr.Location,
503 "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
504 default_expr.Type.GetSignatureForError ());
511 if (TypeSpecComparer.IsEqual (default_expr.Type, parameter_type) ||
512 (default_expr is NullConstant && TypeSpec.IsReferenceType (parameter_type) && !parameter_type.IsGenericParameter) ||
513 parameter_type.BuiltinType == BuiltinTypeSpec.Type.Object) {
518 // LAMESPEC: Some really weird csc behaviour which we have to mimic
519 // User operators returning same type as parameter type are considered
520 // valid for this attribute only
522 // struct S { public static implicit operator S (int i) {} }
524 // void M ([DefaultParameterValue (3)]S s)
526 var expr = Convert.ImplicitUserConversion (dpa_rc, default_expr, parameter_type, loc);
527 if (expr != null && TypeSpecComparer.IsEqual (expr.Type, parameter_type)) {
531 rc.Report.Error (1908, default_expr.Location, "The type of the default value should match the type of the parameter");
535 var opt_attr = attributes.Search (pa.OptionalParameter);
536 if (opt_attr != null) {
537 default_expr = EmptyExpression.MissingValue;
541 public bool HasDefaultValue {
542 get { return default_expr != null; }
545 public bool HasExtensionMethodModifier {
546 get { return (modFlags & Modifier.This) != 0; }
550 // Hoisted parameter variant
552 public HoistedParameter HoistedVariant {
554 return hoisted_variant;
557 hoisted_variant = value;
561 public Modifier ModFlags {
562 get { return modFlags & ~Modifier.This; }
567 set { name = value; }
570 public override AttributeTargets AttributeTargets {
572 return AttributeTargets.Parameter;
576 public void Error_DuplicateName (Report r)
578 r.Error (100, Location, "The parameter name `{0}' is a duplicate", Name);
581 public virtual string GetSignatureForError ()
584 if (parameter_type != null)
585 type_name = parameter_type.GetSignatureForError ();
587 type_name = texpr.GetSignatureForError ();
589 string mod = GetModifierSignature (modFlags);
591 return String.Concat (mod, " ", type_name);
596 public static string GetModifierSignature (Modifier mod)
601 case Modifier.PARAMS:
612 public void IsClsCompliant (IMemberContext ctx)
614 if (parameter_type.IsCLSCompliant ())
617 ctx.Module.Compiler.Report.Warning (3001, 1, Location,
618 "Argument type `{0}' is not CLS-compliant", parameter_type.GetSignatureForError ());
621 public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index, PredefinedAttributes pa)
624 throw new InternalErrorException ("builder already exists");
626 var pattrs = ParametersCompiled.GetParameterAttribute (modFlags);
627 if (HasOptionalExpression)
628 pattrs |= ParameterAttributes.Optional;
631 builder = cb.DefineParameter (index, pattrs, Name);
633 builder = mb.DefineParameter (index, pattrs, Name);
635 if (OptAttributes != null)
636 OptAttributes.Emit ();
638 if (HasDefaultValue && default_expr.Type != null) {
640 // Emit constant values for true constants only, the other
641 // constant-like expressions will rely on default value expression
643 var def_value = DefaultValue;
644 Constant c = def_value != null ? def_value.Child as Constant : default_expr as Constant;
646 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
647 pa.DecimalConstant.EmitAttribute (builder, (decimal) c.GetValue (), c.Location);
649 builder.SetConstant (c.GetValue ());
651 } else if (default_expr.Type.IsStruct) {
653 // Handles special case where default expression is used with value-type
655 // void Foo (S s = default (S)) {}
657 builder.SetConstant (null);
661 if (parameter_type != null) {
662 if (parameter_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
663 pa.Dynamic.EmitAttribute (builder);
664 } else if (parameter_type.HasDynamicElement) {
665 pa.Dynamic.EmitAttribute (builder, parameter_type, Location);
670 public Parameter Clone ()
672 Parameter p = (Parameter) MemberwiseClone ();
673 if (attributes != null)
674 p.attributes = attributes.Clone ();
679 public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec)
681 if ((modFlags & Modifier.RefOutMask) != 0)
682 ec.Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
684 expr_tree_variable = TemporaryVariableReference.Create (ResolveParameterExpressionType (ec, Location).Type, ec.CurrentBlock.ParametersBlock, Location);
685 expr_tree_variable = (TemporaryVariableReference) expr_tree_variable.Resolve (ec);
687 Arguments arguments = new Arguments (2);
688 arguments.Add (new Argument (new TypeOf (parameter_type, Location)));
689 arguments.Add (new Argument (new StringConstant (ec.BuiltinTypes, Name, Location)));
690 return new SimpleAssign (ExpressionTreeVariableReference (),
691 Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location));
694 public void Emit (EmitContext ec)
696 ec.EmitArgumentLoad (idx);
699 public void EmitAssign (EmitContext ec)
701 ec.EmitArgumentStore (idx);
704 public void EmitAddressOf (EmitContext ec)
706 if ((ModFlags & Modifier.RefOutMask) != 0) {
707 ec.EmitArgumentLoad (idx);
709 ec.EmitArgumentAddress (idx);
713 public TemporaryVariableReference ExpressionTreeVariableReference ()
715 return expr_tree_variable;
719 // System.Linq.Expressions.ParameterExpression type
721 public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location)
723 TypeSpec p_type = ec.Module.PredefinedTypes.ParameterExpression.Resolve ();
724 return new TypeExpression (p_type, location);
727 public void Warning_UselessOptionalParameter (Report Report)
729 Report.Warning (1066, 1, Location,
730 "The default value specified for optional parameter `{0}' will never be used",
736 // Imported or resolved parameter information
738 public class ParameterData : IParameterData
740 readonly string name;
741 readonly Parameter.Modifier modifiers;
742 readonly Expression default_value;
744 public ParameterData (string name, Parameter.Modifier modifiers)
747 this.modifiers = modifiers;
750 public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
751 : this (name, modifiers)
753 this.default_value = defaultValue;
756 #region IParameterData Members
758 public Expression DefaultValue {
759 get { return default_value; }
762 public bool HasExtensionMethodModifier {
763 get { return (modifiers & Parameter.Modifier.This) != 0; }
766 public bool HasDefaultValue {
767 get { return default_value != null; }
770 public Parameter.Modifier ModFlags {
771 get { return modifiers; }
781 public abstract class AParametersCollection
783 protected bool has_arglist;
784 protected bool has_params;
786 // Null object pattern
787 protected IParameterData [] parameters;
788 protected TypeSpec [] types;
790 public CallingConventions CallingConvention {
793 CallingConventions.VarArgs :
794 CallingConventions.Standard;
799 get { return parameters.Length; }
802 public TypeSpec ExtensionMethodType {
807 return FixedParameters [0].HasExtensionMethodModifier ?
812 public IParameterData [] FixedParameters {
818 public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
820 return (modFlags & Parameter.Modifier.OUT) != 0 ?
821 ParameterAttributes.Out : ParameterAttributes.None;
824 // Very expensive operation
825 public MetaType[] GetMetaInfo ()
830 return MetaType.EmptyTypes;
832 types = new MetaType[Count - 1];
835 return MetaType.EmptyTypes;
837 types = new MetaType[Count];
840 for (int i = 0; i < types.Length; ++i) {
841 types[i] = Types[i].GetMetaInfo ();
843 if ((FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == 0)
846 // TODO MemberCache: Should go to MetaInfo getter
847 types [i] = types [i].MakeByRefType ();
854 // Returns the parameter information based on the name
856 public int GetParameterIndexByName (string name)
858 for (int idx = 0; idx < Count; ++idx) {
859 if (parameters [idx].Name == name)
866 public string GetSignatureForDocumentation ()
871 StringBuilder sb = new StringBuilder ("(");
872 for (int i = 0; i < Count; ++i) {
876 sb.Append (types [i].GetSignatureForDocumentation ());
878 if ((parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != 0)
883 return sb.ToString ();
886 public string GetSignatureForError ()
888 return GetSignatureForError ("(", ")", Count);
891 public string GetSignatureForError (string start, string end, int count)
893 StringBuilder sb = new StringBuilder (start);
894 for (int i = 0; i < count; ++i) {
897 sb.Append (ParameterDesc (i));
900 return sb.ToString ();
903 public bool HasArglist {
904 get { return has_arglist; }
907 public bool HasExtensionMethodType {
912 return FixedParameters [0].HasExtensionMethodModifier;
916 public bool HasParams {
917 get { return has_params; }
920 public bool IsEmpty {
921 get { return parameters.Length == 0; }
924 public AParametersCollection Inflate (TypeParameterInflator inflator)
926 TypeSpec[] inflated_types = null;
927 bool default_value = false;
929 for (int i = 0; i < Count; ++i) {
930 var inflated_param = inflator.Inflate (types[i]);
931 if (inflated_types == null) {
932 if (inflated_param == types[i])
935 default_value |= FixedParameters[i].HasDefaultValue;
936 inflated_types = new TypeSpec[types.Length];
937 Array.Copy (types, inflated_types, types.Length);
939 if (inflated_param == types[i])
942 default_value |= FixedParameters[i].HasDefaultValue;
945 inflated_types[i] = inflated_param;
948 if (inflated_types == null)
951 var clone = (AParametersCollection) MemberwiseClone ();
952 clone.types = inflated_types;
955 // Default expression is original expression from the parameter
956 // declaration context which can be of nested enum in generic class type.
957 // In such case we end up with expression type of G<T>.E and e.g. parameter
958 // type of G<int>.E and conversion would fail without inflate in this
962 clone.parameters = new IParameterData[Count];
963 for (int i = 0; i < Count; ++i) {
964 var fp = FixedParameters[i];
965 clone.FixedParameters[i] = fp;
967 if (!fp.HasDefaultValue)
970 var expr = fp.DefaultValue;
972 if (inflated_types[i] == expr.Type)
975 var c = expr as Constant;
978 // It may fail we are inflating before type validation is done
980 c = Constant.ExtractConstantFromValue (inflated_types[i], c.GetValue (), expr.Location);
982 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
985 } else if (expr is DefaultValueExpression)
986 expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
988 clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
995 public string ParameterDesc (int pos)
997 if (types == null || types [pos] == null)
998 return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
1000 string type = types [pos].GetSignatureForError ();
1001 if (FixedParameters [pos].HasExtensionMethodModifier)
1002 return "this " + type;
1004 var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1008 return Parameter.GetModifierSignature (mod) + " " + type;
1011 public TypeSpec[] Types {
1012 get { return types; }
1013 set { types = value; }
1018 // A collection of imported or resolved parameters
1020 public class ParametersImported : AParametersCollection
1022 public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1024 this.parameters = parameters;
1026 this.has_arglist = hasArglist;
1027 this.has_params = hasParams;
1030 public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1032 this.parameters = param;
1034 this.has_params = hasParams;
1039 /// Represents the methods parameters
1041 public class ParametersCompiled : AParametersCollection
1043 public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1045 // Used by C# 2.0 delegates
1046 public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1048 private ParametersCompiled ()
1050 parameters = new Parameter [0];
1051 types = TypeSpec.EmptyTypes;
1054 private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1056 this.parameters = parameters;
1060 public ParametersCompiled (params Parameter[] parameters)
1062 if (parameters == null || parameters.Length == 0)
1063 throw new ArgumentException ("Use EmptyReadOnlyParameters");
1065 this.parameters = parameters;
1066 int count = parameters.Length;
1068 for (int i = 0; i < count; i++){
1069 has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1073 public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1076 this.has_arglist = has_arglist;
1079 public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1081 return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1084 public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1086 return new ParametersCompiled (parameters, types);
1090 // TODO: This does not fit here, it should go to different version of AParametersCollection
1091 // as the underlying type is not Parameter and some methods will fail to cast
1093 public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1095 var pd = new ParameterData [types.Length];
1096 for (int i = 0; i < pd.Length; ++i)
1097 pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1099 return new ParametersCompiled (pd, types);
1102 public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1104 return new ParametersCompiled (
1105 new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1109 public void CheckConstraints (IMemberContext mc)
1111 foreach (Parameter p in parameters) {
1113 // It's null for compiler generated types or special types like __arglist
1115 if (p.TypeExpression != null)
1116 ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1121 // Returns non-zero value for equal CLS parameter signatures
1123 public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1127 for (int i = 0; i < a.Count; ++i) {
1128 var a_type = a.Types[i];
1129 var b_type = b.Types[i];
1130 if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1131 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1137 var ac_a = a_type as ArrayContainer;
1141 var ac_b = b_type as ArrayContainer;
1145 if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1150 if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1161 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1163 return MergeGenerated (ctx, userParams, checkConflicts,
1164 new Parameter [] { compilerParams },
1165 new TypeSpec [] { compilerTypes });
1169 // Use this method when you merge compiler generated parameters with user parameters
1171 public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1173 Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1174 userParams.FixedParameters.CopyTo(all_params, 0);
1176 TypeSpec [] all_types;
1177 if (userParams.types != null) {
1178 all_types = new TypeSpec [all_params.Length];
1179 userParams.Types.CopyTo (all_types, 0);
1184 int last_filled = userParams.Count;
1186 foreach (Parameter p in compilerParams) {
1187 for (int i = 0; i < last_filled; ++i) {
1188 while (p.Name == all_params [i].Name) {
1189 if (checkConflicts && i < userParams.Count) {
1190 ctx.Report.Error (316, userParams[i].Location,
1191 "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1193 p.Name = '_' + p.Name;
1196 all_params [last_filled] = p;
1197 if (all_types != null)
1198 all_types [last_filled] = compilerTypes [index++];
1202 ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1203 parameters.has_params = userParams.has_params;
1208 // Parameters checks for members which don't have a block
1210 public void CheckParameters (MemberCore member)
1212 for (int i = 0; i < parameters.Length; ++i) {
1213 var name = parameters[i].Name;
1214 for (int ii = i + 1; ii < parameters.Length; ++ii) {
1215 if (parameters[ii].Name == name)
1216 this[ii].Error_DuplicateName (member.Compiler.Report);
1221 public bool Resolve (IMemberContext ec)
1226 types = new TypeSpec [Count];
1230 for (int i = 0; i < FixedParameters.Length; ++i) {
1232 TypeSpec t = p.Resolve (ec, i);
1244 public void ResolveDefaultValues (MemberCore m)
1246 ResolveContext rc = null;
1247 for (int i = 0; i < parameters.Length; ++i) {
1248 Parameter p = (Parameter) parameters [i];
1251 // Try not to enter default values resolution if there are is not any default value possible
1253 if (p.HasDefaultValue || p.OptAttributes != null) {
1255 rc = new ResolveContext (m);
1257 p.ResolveDefaultValue (rc);
1262 // Define each type attribute (in/out/ref) and
1263 // the argument names.
1264 public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1269 MethodBuilder mb = builder as MethodBuilder;
1270 ConstructorBuilder cb = builder as ConstructorBuilder;
1271 var pa = mc.Module.PredefinedAttributes;
1273 for (int i = 0; i < Count; i++) {
1274 this [i].ApplyAttributes (mb, cb, i + 1, pa);
1278 public void VerifyClsCompliance (IMemberContext ctx)
1280 foreach (Parameter p in FixedParameters)
1281 p.IsClsCompliant (ctx);
1284 public Parameter this [int pos] {
1285 get { return (Parameter) parameters [pos]; }
1288 public Expression CreateExpressionTree (BlockContext ec, Location loc)
1290 var initializers = new ArrayInitializer (Count, loc);
1291 foreach (Parameter p in FixedParameters) {
1293 // Each parameter expression is stored to local variable
1294 // to save some memory when referenced later.
1296 StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1297 if (se.Resolve (ec)) {
1298 ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1299 ec.CurrentBlock.AddScopeStatement (se);
1302 initializers.Add (p.ExpressionTreeVariableReference ());
1305 return new ArrayCreation (
1306 Parameter.ResolveParameterExpressionType (ec, loc),
1310 public ParametersCompiled Clone ()
1312 ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1314 p.parameters = new IParameterData [parameters.Length];
1315 for (int i = 0; i < Count; ++i)
1316 p.parameters [i] = this [i].Clone ();
1323 // Default parameter value expression. We need this wrapper to handle
1324 // default parameter values of folded constants (e.g. indexer parameters).
1325 // The expression is resolved only once but applied to two methods which
1326 // both share reference to this expression and we ensure that resolving
1327 // this expression always returns same instance
1329 public class DefaultParameterValueExpression : CompositeExpression
1331 public DefaultParameterValueExpression (Expression expr)
1336 public void Resolve (ResolveContext rc, Parameter p)
1338 var expr = Resolve (rc);
1340 this.expr = ErrorExpression.Instance;
1346 if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) {
1347 rc.Report.Error (1736, Location,
1348 "The expression being assigned to optional parameter `{0}' must be a constant or default value",
1354 var parameter_type = p.Type;
1355 if (type == parameter_type)
1358 var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1360 if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1361 Nullable.Wrap wrap = (Nullable.Wrap) res;
1363 if (!(res is Constant)) {
1364 rc.Report.Error (1770, Location,
1365 "The expression being assigned to nullable optional parameter `{0}' must be default value",
1371 if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1372 rc.Report.Error (1763, Location,
1373 "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1374 p.Name, parameter_type.GetSignatureForError ());
1383 rc.Report.Error (1750, Location,
1384 "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1385 type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1387 this.expr = ErrorExpression.Instance;
1390 public override object Accept (StructuralVisitor visitor)
1392 return visitor.Visit (this);