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
TypeManager.CSharpName (a.Type).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
TypeManager.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
TypeManager.CSharpName (parameter_type));
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 = TypeManager.CSharpName (parameter_type);
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) {
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
if (expr is DefaultValueExpression)
976
expr = new DefaultValueExpression (new TypeExpression (inflated_types[i], expr.Location), expr.Location);
977
else if (expr is Constant)
978
expr = Constant.CreateConstantFromValue (inflated_types[i], ((Constant) expr).GetValue (), expr.Location);
980
clone.FixedParameters[i] = new ParameterData (fp.Name, fp.ModFlags, expr);
987
public string ParameterDesc (int pos)
989
if (types == null || types [pos] == null)
990
return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
992
string type = TypeManager.CSharpName (types [pos]);
993
if (FixedParameters [pos].HasExtensionMethodModifier)
994
return "this " + type;
996
var mod = FixedParameters[pos].ModFlags & Parameter.Modifier.ModifierMask;
1000
return Parameter.GetModifierSignature (mod) + " " + type;
1003
public TypeSpec[] Types {
1004
get { return types; }
1005
set { types = value; }
1010
// A collection of imported or resolved parameters
1012
public class ParametersImported : AParametersCollection
1014
public ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams)
1016
this.parameters = parameters;
1018
this.has_arglist = hasArglist;
1019
this.has_params = hasParams;
1022
public ParametersImported (IParameterData[] param, TypeSpec[] types, bool hasParams)
1024
this.parameters = param;
1026
this.has_params = hasParams;
1031
/// Represents the methods parameters
1033
public class ParametersCompiled : AParametersCollection
1035
public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
1037
// Used by C# 2.0 delegates
1038
public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
1040
private ParametersCompiled ()
1042
parameters = new Parameter [0];
1043
types = TypeSpec.EmptyTypes;
1046
private ParametersCompiled (IParameterData[] parameters, TypeSpec[] types)
1048
this.parameters = parameters;
1052
public ParametersCompiled (params Parameter[] parameters)
1054
if (parameters == null || parameters.Length == 0)
1055
throw new ArgumentException ("Use EmptyReadOnlyParameters");
1057
this.parameters = parameters;
1058
int count = parameters.Length;
1060
for (int i = 0; i < count; i++){
1061
has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
1065
public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
1068
this.has_arglist = has_arglist;
1071
public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type)
1073
return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type });
1076
public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, TypeSpec[] types)
1078
return new ParametersCompiled (parameters, types);
1082
// TODO: This does not fit here, it should go to different version of AParametersCollection
1083
// as the underlying type is not Parameter and some methods will fail to cast
1085
public static AParametersCollection CreateFullyResolved (params TypeSpec[] types)
1087
var pd = new ParameterData [types.Length];
1088
for (int i = 0; i < pd.Length; ++i)
1089
pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null);
1091
return new ParametersCompiled (pd, types);
1094
public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc)
1096
return new ParametersCompiled (
1097
new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) },
1101
public void CheckConstraints (IMemberContext mc)
1103
foreach (Parameter p in parameters) {
1105
// It's null for compiler generated types or special types like __arglist
1107
if (p.TypeExpression != null)
1108
ConstraintChecker.Check (mc, p.Type, p.TypeExpression.Location);
1113
// Returns non-zero value for equal CLS parameter signatures
1115
public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b)
1119
for (int i = 0; i < a.Count; ++i) {
1120
var a_type = a.Types[i];
1121
var b_type = b.Types[i];
1122
if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) {
1123
if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1129
var ac_a = a_type as ArrayContainer;
1133
var ac_b = b_type as ArrayContainer;
1137
if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) {
1142
if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) {
1153
public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes)
1155
return MergeGenerated (ctx, userParams, checkConflicts,
1156
new Parameter [] { compilerParams },
1157
new TypeSpec [] { compilerTypes });
1161
// Use this method when you merge compiler generated parameters with user parameters
1163
public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes)
1165
Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
1166
userParams.FixedParameters.CopyTo(all_params, 0);
1168
TypeSpec [] all_types;
1169
if (userParams.types != null) {
1170
all_types = new TypeSpec [all_params.Length];
1171
userParams.Types.CopyTo (all_types, 0);
1176
int last_filled = userParams.Count;
1178
foreach (Parameter p in compilerParams) {
1179
for (int i = 0; i < last_filled; ++i) {
1180
while (p.Name == all_params [i].Name) {
1181
if (checkConflicts && i < userParams.Count) {
1182
ctx.Report.Error (316, userParams[i].Location,
1183
"The parameter name `{0}' conflicts with a compiler generated name", p.Name);
1185
p.Name = '_' + p.Name;
1188
all_params [last_filled] = p;
1189
if (all_types != null)
1190
all_types [last_filled] = compilerTypes [index++];
1194
ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
1195
parameters.has_params = userParams.has_params;
1200
// Parameters checks for members which don't have a block
1202
public void CheckParameters (MemberCore member)
1204
for (int i = 0; i < parameters.Length; ++i) {
1205
var name = parameters[i].Name;
1206
for (int ii = i + 1; ii < parameters.Length; ++ii) {
1207
if (parameters[ii].Name == name)
1208
this[ii].Error_DuplicateName (member.Compiler.Report);
1213
public bool Resolve (IMemberContext ec)
1218
types = new TypeSpec [Count];
1222
for (int i = 0; i < FixedParameters.Length; ++i) {
1224
TypeSpec t = p.Resolve (ec, i);
1236
public void ResolveDefaultValues (MemberCore m)
1238
ResolveContext rc = null;
1239
for (int i = 0; i < parameters.Length; ++i) {
1240
Parameter p = (Parameter) parameters [i];
1243
// Try not to enter default values resolution if there are is not any default value possible
1245
if (p.HasDefaultValue || p.OptAttributes != null) {
1247
rc = new ResolveContext (m);
1249
p.ResolveDefaultValue (rc);
1254
// Define each type attribute (in/out/ref) and
1255
// the argument names.
1256
public void ApplyAttributes (IMemberContext mc, MethodBase builder)
1261
MethodBuilder mb = builder as MethodBuilder;
1262
ConstructorBuilder cb = builder as ConstructorBuilder;
1263
var pa = mc.Module.PredefinedAttributes;
1265
for (int i = 0; i < Count; i++) {
1266
this [i].ApplyAttributes (mb, cb, i + 1, pa);
1270
public void VerifyClsCompliance (IMemberContext ctx)
1272
foreach (Parameter p in FixedParameters)
1273
p.IsClsCompliant (ctx);
1276
public Parameter this [int pos] {
1277
get { return (Parameter) parameters [pos]; }
1280
public Expression CreateExpressionTree (BlockContext ec, Location loc)
1282
var initializers = new ArrayInitializer (Count, loc);
1283
foreach (Parameter p in FixedParameters) {
1285
// Each parameter expression is stored to local variable
1286
// to save some memory when referenced later.
1288
StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec), Location.Null);
1289
if (se.Resolve (ec)) {
1290
ec.CurrentBlock.AddScopeStatement (new TemporaryVariableReference.Declarator (p.ExpressionTreeVariableReference ()));
1291
ec.CurrentBlock.AddScopeStatement (se);
1294
initializers.Add (p.ExpressionTreeVariableReference ());
1297
return new ArrayCreation (
1298
Parameter.ResolveParameterExpressionType (ec, loc),
1302
public ParametersCompiled Clone ()
1304
ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
1306
p.parameters = new IParameterData [parameters.Length];
1307
for (int i = 0; i < Count; ++i)
1308
p.parameters [i] = this [i].Clone ();
1315
// Default parameter value expression. We need this wrapper to handle
1316
// default parameter values of folded constants (e.g. indexer parameters).
1317
// The expression is resolved only once but applied to two methods which
1318
// both share reference to this expression and we ensure that resolving
1319
// this expression always returns same instance
1321
public class DefaultParameterValueExpression : CompositeExpression
1323
public DefaultParameterValueExpression (Expression expr)
1328
protected override Expression DoResolve (ResolveContext rc)
1330
return base.DoResolve (rc);
1333
public void Resolve (ResolveContext rc, Parameter p)
1335
var expr = Resolve (rc);
1341
if (!(expr is Constant || expr is DefaultValueExpression || (expr is New && ((New) expr).IsDefaultStruct))) {
1342
rc.Report.Error (1736, Location,
1343
"The expression being assigned to optional parameter `{0}' must be a constant or default value",
1349
var parameter_type = p.Type;
1350
if (type == parameter_type)
1353
var res = Convert.ImplicitConversionStandard (rc, expr, parameter_type, Location);
1355
if (parameter_type.IsNullableType && res is Nullable.Wrap) {
1356
Nullable.Wrap wrap = (Nullable.Wrap) res;
1358
if (!(res is Constant)) {
1359
rc.Report.Error (1770, Location,
1360
"The expression being assigned to nullable optional parameter `{0}' must be default value",
1366
if (!expr.IsNull && TypeSpec.IsReferenceType (parameter_type) && parameter_type.BuiltinType != BuiltinTypeSpec.Type.String) {
1367
rc.Report.Error (1763, Location,
1368
"Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
1369
p.Name, parameter_type.GetSignatureForError ());
1378
rc.Report.Error (1750, Location,
1379
"Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'",
1380
type.GetSignatureForError (), parameter_type.GetSignatureForError ());
1383
public override object Accept (StructuralVisitor visitor)
1385
return visitor.Visit (this);