X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fparameter.cs;h=a6c5c63da7c0b41811e27bc1af73a1f09de97f86;hb=0c2bb8157f43826a57c39b863a1d67e3aef1b7b2;hp=fb9e69b54b2af7accc04c731ca6d7a6b2269b789;hpb=ff228e1c801bda9666b6edab3ee962e05edcf480;p=mono.git
diff --git a/mcs/mcs/parameter.cs b/mcs/mcs/parameter.cs
index fb9e69b54b2..a6c5c63da7c 100644
--- a/mcs/mcs/parameter.cs
+++ b/mcs/mcs/parameter.cs
@@ -2,17 +2,19 @@
// parameter.cs: Parameter definition.
//
// Author: Miguel de Icaza (miguel@gnu.org)
+// Marek Safar (marek.safar@seznam.cz)
//
-// Licensed under the terms of the GNU GPL
-//
-// (C) 2001 Ximian, Inc (http://www.ximian.com)
+// Dual licensed under the terms of the MIT X11 or GNU GPL
//
+// Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+// Copyright 2003-2008 Novell, Inc.
//
//
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
+using System.Text;
namespace Mono.CSharp {
@@ -23,22 +25,23 @@ namespace Mono.CSharp {
protected ParameterBuilder builder;
- public ParameterBase (Attributes attrs)
+ protected ParameterBase (Attributes attrs)
: base (attrs)
{
}
- public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
{
- if (a.Type == TypeManager.marshal_as_attr_type) {
+#if !NET_2_0
+ if (a.Type == pa.MarshalAs) {
UnmanagedMarshal marshal = a.GetMarshal (this);
if (marshal != null) {
builder.SetMarshal (marshal);
}
return;
}
-
- if (a.Type.IsSubclassOf (TypeManager.security_attr_type)) {
+#endif
+ if (a.HasSecurityAttribute) {
a.Error_InvalidSecurityParent ();
return;
}
@@ -46,7 +49,7 @@ namespace Mono.CSharp {
builder.SetCustomAttribute (cb);
}
- public override bool IsClsCompliaceRequired(DeclSpace ds)
+ public override bool IsClsComplianceRequired()
{
return false;
}
@@ -55,7 +58,7 @@ namespace Mono.CSharp {
///
/// Class for applying custom attributes on the return type
///
- public class ReturnParameter: ParameterBase {
+ public class ReturnParameter : ParameterBase {
public ReturnParameter (MethodBuilder mb, Location location):
base (null)
{
@@ -63,13 +66,13 @@ namespace Mono.CSharp {
builder = mb.DefineParameter (0, ParameterAttributes.None, "");
}
catch (ArgumentOutOfRangeException) {
- Report.Warning (-24, location, "The Microsoft .NET Runtime 1.x does not permit setting custom attributes on the return type");
+ Report.RuntimeMissingSupport (location, "custom attributes on the return type");
}
}
- public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
{
- if (a.Type == TypeManager.cls_compliant_attribute_type) {
+ if (a.Type == pa.CLSCompliant) {
Report.Warning (3023, 1, a.Location, "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead");
}
@@ -77,7 +80,7 @@ namespace Mono.CSharp {
if (builder == null)
return;
- base.ApplyAttributeBuilder (a, cb);
+ base.ApplyAttributeBuilder (a, cb, pa);
}
public override AttributeTargets AttributeTargets {
@@ -86,6 +89,12 @@ namespace Mono.CSharp {
}
}
+ public override IResolveContext ResolveContext {
+ get {
+ throw new NotSupportedException ();
+ }
+ }
+
///
/// Is never called
///
@@ -100,11 +109,13 @@ namespace Mono.CSharp {
/// Class for applying custom attributes on the implicit parameter type
/// of the 'set' method in properties, and the 'add' and 'remove' methods in events.
///
- public class ImplicitParameter: ParameterBase {
+ ///
+ // TODO: should use more code from Parameter.ApplyAttributeBuilder
+ public class ImplicitParameter : ParameterBase {
public ImplicitParameter (MethodBuilder mb):
base (null)
{
- builder = mb.DefineParameter (1, ParameterAttributes.None, "");
+ builder = mb.DefineParameter (1, ParameterAttributes.None, "value");
}
public override AttributeTargets AttributeTargets {
@@ -113,6 +124,12 @@ namespace Mono.CSharp {
}
}
+ public override IResolveContext ResolveContext {
+ get {
+ throw new NotSupportedException ();
+ }
+ }
+
///
/// Is never called
///
@@ -123,185 +140,386 @@ namespace Mono.CSharp {
}
}
- ///
- /// Represents a single method parameter
- ///
+ public class ImplicitLambdaParameter : Parameter
+ {
+ public ImplicitLambdaParameter (string name, Location loc)
+ : base (null, name, Modifier.NONE, null, loc)
+ {
+ }
+
+ public override Type Resolve (IResolveContext ec)
+ {
+ if (parameter_type == null)
+ throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set",
+ Name);
+
+ return parameter_type;
+ }
+
+ public Type Type {
+ set { parameter_type = value; }
+ }
+ }
+
+ public class ParamsParameter : Parameter {
+ public ParamsParameter (FullNamedExpression type, string name, Attributes attrs, Location loc):
+ base (type, name, Parameter.Modifier.PARAMS, attrs, loc)
+ {
+ }
+
+ public override Type Resolve (IResolveContext ec)
+ {
+ if (base.Resolve (ec) == null)
+ return null;
+
+ if (!parameter_type.IsArray || parameter_type.GetArrayRank () != 1) {
+ Report.Error (225, Location, "The params parameter must be a single dimensional array");
+ return null;
+ }
+
+ return parameter_type;
+ }
+
+ public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
+ {
+ base.ApplyAttributes (mb, cb, index);
+ PredefinedAttributes.Get.ParamArray.EmitAttribute (builder, Location);
+ }
+ }
+
+ public class ArglistParameter : Parameter {
+ // Doesn't have proper type because it's never chosen for better conversion
+ public ArglistParameter (Location loc) :
+ base (null, String.Empty, Parameter.Modifier.ARGLIST, null, loc)
+ {
+ }
+
+ public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
+ {
+ // Nothing to do
+ }
+
+ public override bool CheckAccessibility (InterfaceMemberBase member)
+ {
+ return true;
+ }
+
+ public override Type Resolve (IResolveContext ec)
+ {
+ return typeof (ArglistParameter);
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return "__arglist";
+ }
+ }
+
+ public interface IParameterData
+ {
+ Expression DefaultValue { get; }
+ bool HasExtensionMethodModifier { get; }
+ bool HasDefaultValue { get; }
+ Parameter.Modifier ModFlags { get; }
+ string Name { get; }
+ }
- //TODO: Add location member to this or base class for better error location and all methods simplification.
- public class Parameter : ParameterBase {
+ //
+ // Parameter information created by parser
+ //
+ public class Parameter : ParameterBase, IParameterData, ILocalVariable {
[Flags]
public enum Modifier : byte {
NONE = 0,
- REF = 1,
- OUT = 2,
+ REF = REFMASK | ISBYREF,
+ OUT = OUTMASK | ISBYREF,
PARAMS = 4,
// This is a flag which says that it's either REF or OUT.
ISBYREF = 8,
- ARGLIST = 16
+ ARGLIST = 16,
+ REFMASK = 32,
+ OUTMASK = 64,
+ This = 128
}
static string[] attribute_targets = new string [] { "param" };
- public Expression TypeName;
- public readonly Modifier ModFlags;
- public readonly string Name;
- Type parameter_type;
+ protected FullNamedExpression TypeName;
+ readonly Modifier modFlags;
+ string name;
+ Expression default_expr;
+ protected Type parameter_type;
+ public readonly Location Location;
+ int idx;
+ public bool HasAddressTaken;
- EmitContext ec; // because ApplyAtrribute doesn't have ec
-
- public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
+ IResolveContext resolve_context;
+ LocalVariableReference expr_tree_variable;
+ static TypeExpr parameter_expr_tree_type;
+
+ public HoistedVariable HoistedVariableReference;
+
+ public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc)
: base (attrs)
{
- Name = name;
- ModFlags = mod;
+ if (type == TypeManager.system_void_expr)
+ Report.Error (1536, loc, "Invalid parameter type `void'");
+
+ this.name = name;
+ modFlags = mod;
+ Location = loc;
TypeName = type;
}
- public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
{
- if (a.Type == TypeManager.in_attribute_type && Attributes == ParameterAttributes.Out) {
- Report.Error (36, a.Location, "Can not use [In] attribute on out parameter");
+ if (a.Type == pa.In && ModFlags == Modifier.OUT) {
+ Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
return;
}
- if (a.Type == TypeManager.param_array_type) {
- Report.Error (674, a.Location, "Do not use 'System.ParamArrayAttribute'. Use the 'params' keyword instead");
+ if (a.Type == pa.ParamArray) {
+ Report.Error (674, a.Location, "Do not use `System.ParamArrayAttribute'. Use the `params' keyword instead");
return;
}
- if (a.Type == TypeManager.out_attribute_type && (ModFlags & Modifier.REF) != 0 &&
- !OptAttributes.Contains (TypeManager.in_attribute_type, ec)) {
+ if (a.Type == PredefinedAttributes.Get.Out && (ModFlags & Modifier.REF) == Modifier.REF &&
+ !OptAttributes.Contains (pa.In)) {
Report.Error (662, a.Location,
- "'{0}' cannot specify only Out attribute on a ref parameter. Use both In and Out attributes, or neither", GetSignatureForError ());
+ "Cannot specify only `Out' attribute on a ref parameter. Use both `In' and `Out' attributes or neither");
return;
}
- if (a.Type == TypeManager.cls_compliant_attribute_type) {
+ if (a.Type == pa.CLSCompliant) {
Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead");
}
- base.ApplyAttributeBuilder (a, cb);
+ if (HasDefaultValue && (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter)) {
+ Report.Error (1745, a.Location,
+ "Cannot specify `{0}' attribute on optional parameter `{1}'",
+ TypeManager.CSharpName (a.Type).Replace ("Attribute", ""), Name);
+ return;
+ }
+
+ if (a.Type == pa.DefaultParameterValue) {
+ object val = a.GetParameterDefaultValue ();
+ if (val != null) {
+ Type t = val.GetType ();
+ if (t.IsArray || TypeManager.IsSubclassOf (t, TypeManager.type_type)) {
+ if (parameter_type == TypeManager.object_type) {
+ if (!t.IsArray)
+ t = TypeManager.type_type;
+
+ Report.Error (1910, a.Location, "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute",
+ TypeManager.CSharpName (t));
+ } else {
+ Report.Error (1909, a.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
+ TypeManager.CSharpName (parameter_type)); ;
+ }
+ return;
+ }
+ }
+
+ if (parameter_type == TypeManager.object_type ||
+ (val == null && !TypeManager.IsGenericParameter (parameter_type) && TypeManager.IsReferenceType (parameter_type)) ||
+ (val != null && TypeManager.TypeToCoreType (val.GetType ()) == parameter_type))
+ builder.SetConstant (val);
+ else
+ Report.Error (1908, a.Location, "The type of the default value should match the type of the parameter");
+ return;
+ }
+
+ base.ApplyAttributeBuilder (a, cb, pa);
+ }
+
+ public virtual bool CheckAccessibility (InterfaceMemberBase member)
+ {
+ if (parameter_type == null || TypeManager.IsGenericParameter (parameter_type))
+ return true;
+
+ return member.IsAccessibleAs (parameter_type);
+ }
+
+ public override IResolveContext ResolveContext {
+ get {
+ return resolve_context;
+ }
}
//
// Resolve is used in method definitions
//
- public bool Resolve (EmitContext ec, Location l)
+ public virtual Type Resolve (IResolveContext rc)
{
- this.ec = ec;
+ // HACK: to resolve attributes correctly
+ this.resolve_context = rc;
- TypeExpr texpr = TypeName.ResolveAsTypeTerminal (ec, false);
+ if (parameter_type != null)
+ return parameter_type;
+
+ TypeExpr texpr = TypeName.ResolveAsTypeTerminal (rc, false);
if (texpr == null)
- return false;
+ return null;
- parameter_type = texpr.ResolveType (ec);
-
- if (parameter_type.IsAbstract && parameter_type.IsSealed) {
- Report.Error (721, l, "'{0}': static types cannot be used as parameters", GetSignatureForError ());
- return false;
+ parameter_type = texpr.Type;
+
+ // Ignore all checks for dummy members
+ AbstractPropertyEventMethod pem = rc as AbstractPropertyEventMethod;
+ if (pem != null && pem.IsDummy)
+ return parameter_type;
+
+ if (default_expr != null) {
+ EmitContext ec = new EmitContext (rc, rc.GenericDeclContainer, Location, null, parameter_type, 0);
+ default_expr = default_expr.Resolve (ec);
+ if (default_expr != null) {
+ Constant value = default_expr as Constant;
+ if (value == null) {
+ if (default_expr != null && !(default_expr is DefaultValueExpression)) {
+ Report.Error (1736, default_expr.Location, "The expression being assigned to optional parameter `{0}' must be constant",
+ Name);
+ default_expr = null;
+ }
+ } else {
+ Constant c = value.ConvertImplicitly (parameter_type);
+ if (c == null) {
+ if (parameter_type == TypeManager.object_type) {
+ Report.Error (1763, Location,
+ "Optional parameter `{0}' of type `{1}' can only be initialized with `null'",
+ Name, GetSignatureForError ());
+ } else {
+ Report.Error (1750, Location,
+ "Optional parameter value `{0}' cannot be converted to parameter type `{1}'",
+ value.GetValue (), GetSignatureForError ());
+ }
+ default_expr = null;
+ }
+ }
+ }
}
- if (parameter_type == TypeManager.void_type){
- Report.Error (1536, l, "Invalid parameter type 'void'");
- return false;
+ if ((modFlags & Parameter.Modifier.ISBYREF) != 0 &&
+ TypeManager.IsSpecialType (parameter_type)) {
+ Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
+ GetSignatureForError ());
+ return null;
}
- if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
- if (parameter_type == TypeManager.typed_reference_type ||
- parameter_type == TypeManager.arg_iterator_type){
- Report.Error (1601, l,
- "out or ref parameter can not be of type TypedReference or ArgIterator");
- return false;
- }
+ TypeManager.CheckTypeVariance (parameter_type,
+ (modFlags & Parameter.Modifier.ISBYREF) != 0 ? Variance.None : Variance.Contravariant,
+ rc as MemberCore);
+
+ if (texpr is TypeParameterExpr)
+ return parameter_type;
+
+ if ((parameter_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
+ Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
+ texpr.GetSignatureForError ());
+ return parameter_type;
}
-
- return parameter_type != null;
+
+ if ((modFlags & Modifier.This) != 0 && parameter_type.IsPointer) {
+ Report.Error (1103, Location, "The type of extension method cannot be `{0}'",
+ TypeManager.CSharpName (parameter_type));
+ }
+
+ return parameter_type;
}
- public Type ExternalType ()
+ public void ResolveVariable (int idx)
{
- if ((ModFlags & Parameter.Modifier.ISBYREF) != 0)
- return TypeManager.GetReferenceType (parameter_type);
-
- return parameter_type;
+ this.idx = idx;
}
- public Type ParameterType {
- get {
- return parameter_type;
- }
+ public bool HasDefaultValue {
+ get { return default_expr != null; }
}
-
- public ParameterAttributes Attributes {
- get {
- int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF);
- switch ((Modifier) flags) {
- case Modifier.NONE:
- return ParameterAttributes.None;
- case Modifier.REF:
- return ParameterAttributes.None;
- case Modifier.OUT:
- return ParameterAttributes.Out;
- case Modifier.PARAMS:
- return 0;
- }
-
- return ParameterAttributes.None;
- }
+
+ public bool HasExtensionMethodModifier {
+ get { return (modFlags & Modifier.This) != 0; }
}
-
+
+ public Modifier ModFlags {
+ get { return modFlags & ~Modifier.This; }
+ }
+
+ public string Name {
+ get { return name; }
+ set { name = value; }
+ }
+
+ ParameterAttributes Attributes {
+ get { return ParametersCompiled.GetParameterAttribute (modFlags) |
+ (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); }
+ }
+
public override AttributeTargets AttributeTargets {
get {
return AttributeTargets.Parameter;
}
}
- ///
- /// Returns the signature for this parameter evaluating it on the
- /// @tc context
- ///
- public string GetSignature (EmitContext ec, Location loc)
- {
- if (parameter_type == null){
- if (!Resolve (ec, loc))
- return null;
- }
-
- return ExternalType ().FullName;
- }
-
- public string GetSignatureForError ()
+ public virtual string GetSignatureForError ()
{
string type_name;
if (parameter_type != null)
type_name = TypeManager.CSharpName (parameter_type);
- else if (TypeName.Type != null)
- type_name = TypeManager.CSharpName (TypeName.Type);
else
- type_name = TypeName.ToString ();
+ type_name = TypeName.GetSignatureForError ();
+
+ string mod = GetModifierSignature (modFlags);
+ if (mod.Length > 0)
+ return String.Concat (mod, " ", type_name);
- switch (ModFlags & unchecked (~Modifier.ISBYREF)) {
- case Modifier.OUT:
- return "out " + type_name;
- case Modifier.PARAMS:
- return "params " + type_name;
- case Modifier.REF:
- return "ref " + type_name;
- }
return type_name;
}
- public void DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
+ public static string GetModifierSignature (Modifier mod)
+ {
+ switch (mod) {
+ case Modifier.OUT:
+ return "out";
+ case Modifier.PARAMS:
+ return "params";
+ case Modifier.REF:
+ return "ref";
+ case Modifier.This:
+ return "this";
+ default:
+ return "";
+ }
+ }
+
+ public void IsClsCompliant ()
+ {
+ if (AttributeTester.IsClsCompliant (parameter_type))
+ return;
+
+ Report.Warning (3001, 1, Location, "Argument type `{0}' is not CLS-compliant", GetSignatureForError ());
+ }
+
+ public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
{
- ParameterAttributes par_attr = Attributes;
-
if (mb == null)
- builder = cb.DefineParameter (index, par_attr, Name);
- else
- builder = mb.DefineParameter (index, par_attr, Name);
-
- if (OptAttributes != null) {
- OptAttributes.Emit (ec, this);
+ builder = cb.DefineParameter (index, Attributes, Name);
+ else
+ builder = mb.DefineParameter (index, Attributes, Name);
+
+ if (OptAttributes != null)
+ OptAttributes.Emit ();
+
+ if (HasDefaultValue) {
+ //
+ // Emit constant values for true constants only, the other
+ // constant-like expressions will rely on default value expression
+ //
+ Constant c = default_expr as Constant;
+ if (c != null) {
+ if (default_expr.Type == TypeManager.decimal_type) {
+ builder.SetCustomAttribute (Const.CreateDecimalConstantAttribute (c));
+ } else {
+ builder.SetConstant (c.GetValue ());
+ }
+ }
}
}
@@ -310,316 +528,669 @@ namespace Mono.CSharp {
return attribute_targets;
}
}
+
+ public Parameter Clone ()
+ {
+ Parameter p = (Parameter) MemberwiseClone ();
+ if (attributes != null) {
+ p.attributes = attributes.Clone ();
+ p.attributes.AttachTo (p);
+ }
+
+ return p;
+ }
+
+ public ExpressionStatement CreateExpressionTreeVariable (EmitContext ec)
+ {
+ //
+ // A parameter is not hoisted when used directly as ET
+ //
+ HoistedVariableReference = null;
+
+ if ((modFlags & Modifier.ISBYREF) != 0)
+ Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
+
+ LocalInfo variable = ec.CurrentBlock.AddTemporaryVariable (
+ ResolveParameterExpressionType (ec, Location), Location);
+ variable.Resolve (ec);
+
+ expr_tree_variable = new LocalVariableReference (
+ ec.CurrentBlock, variable.Name, Location, variable, false);
+
+ ArrayList arguments = new ArrayList (2);
+ arguments.Add (new Argument (new TypeOf (
+ new TypeExpression (parameter_type, Location), Location)));
+ arguments.Add (new Argument (new StringConstant (Name, Location)));
+ return new SimpleAssign (ExpressionTreeVariableReference (),
+ Expression.CreateExpressionFactoryCall ("Parameter", null, arguments, Location));
+ }
+
+ public Expression DefaultValue {
+ get { return default_expr; }
+ set { default_expr = value; }
+ }
+
+ public void Emit (EmitContext ec)
+ {
+ int arg_idx = idx;
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ ParameterReference.EmitLdArg (ec.ig, arg_idx);
+ }
+
+ public void EmitAssign (EmitContext ec)
+ {
+ int arg_idx = idx;
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ if (arg_idx <= 255)
+ ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
+ else
+ ec.ig.Emit (OpCodes.Starg, arg_idx);
+ }
+
+ public void EmitAddressOf (EmitContext ec)
+ {
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
+ if (is_ref) {
+ ParameterReference.EmitLdArg (ec.ig, arg_idx);
+ } else {
+ if (arg_idx <= 255)
+ ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
+ else
+ ec.ig.Emit (OpCodes.Ldarga, arg_idx);
+ }
+ }
+
+ public Expression ExpressionTreeVariableReference ()
+ {
+ return expr_tree_variable;
+ }
+
+ //
+ // System.Linq.Expressions.ParameterExpression type
+ //
+ public static TypeExpr ResolveParameterExpressionType (EmitContext ec, Location location)
+ {
+ if (parameter_expr_tree_type != null)
+ return parameter_expr_tree_type;
+
+ Type p_type = TypeManager.parameter_expression_type;
+ if (p_type == null) {
+ p_type = TypeManager.CoreLookupType ("System.Linq.Expressions", "ParameterExpression", Kind.Class, true);
+ TypeManager.parameter_expression_type = p_type;
+ }
+
+ parameter_expr_tree_type = new TypeExpression (p_type, location).
+ ResolveAsTypeTerminal (ec, false);
+
+ return parameter_expr_tree_type;
+ }
+
+ public void Warning_UselessOptionalParameter ()
+ {
+ Report.Warning (1066, 1, Location,
+ "The default value specified for optional parameter `{0}' will never be used",
+ Name);
+ }
}
- ///
- /// Represents the methods parameters
- ///
- public class Parameters {
- public Parameter [] FixedParameters;
- public readonly Parameter ArrayParameter;
- public readonly bool HasArglist;
- string signature;
- Type [] types;
- Location loc;
-
- static Parameters empty_parameters;
-
- public Parameters (Parameter [] fixed_parameters, Parameter array_parameter, Location l)
+ //
+ // Imported or resolved parameter information
+ //
+ public class ParameterData : IParameterData
+ {
+ readonly string name;
+ readonly Parameter.Modifier modifiers;
+ readonly Expression default_value;
+
+ public ParameterData (string name, Parameter.Modifier modifiers)
{
- FixedParameters = fixed_parameters;
- ArrayParameter = array_parameter;
- loc = l;
+ this.name = name;
+ this.modifiers = modifiers;
}
- public Parameters (Parameter [] fixed_parameters, bool has_arglist, Location l)
+ public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
+ : this (name, modifiers)
{
- FixedParameters = fixed_parameters;
- HasArglist = has_arglist;
- loc = l;
+ this.default_value = defaultValue;
}
- ///
- /// This is used to reuse a set of empty parameters, because they
- /// are common
- ///
- public static Parameters EmptyReadOnlyParameters {
+ #region IParameterData Members
+
+ public Expression DefaultValue {
+ get { return default_value; }
+ }
+
+ public bool HasExtensionMethodModifier {
+ get { return (modifiers & Parameter.Modifier.This) != 0; }
+ }
+
+ public bool HasDefaultValue {
+ get { return default_value != null; }
+ }
+
+ public Parameter.Modifier ModFlags {
+ get { return modifiers & ~Parameter.Modifier.This; }
+ }
+
+ public string Name {
+ get { return name; }
+ }
+
+ #endregion
+ }
+
+ public abstract class AParametersCollection
+ {
+ protected bool has_arglist;
+ protected bool has_params;
+
+ // Null object pattern
+ protected IParameterData [] parameters;
+ protected Type [] types;
+
+ public int Count {
+ get { return parameters.Length; }
+ }
+
+ public Type ExtensionMethodType {
get {
- if (empty_parameters == null)
- empty_parameters = new Parameters (null, null, Location.Null);
-
- return empty_parameters;
+ if (Count == 0)
+ return null;
+
+ return FixedParameters [0].HasExtensionMethodModifier ?
+ types [0] : null;
}
}
-
- public bool Empty {
+
+ public IParameterData [] FixedParameters {
get {
- return (FixedParameters == null) && (ArrayParameter == null);
+ return parameters;
}
}
- public Location Location {
- get { return loc; }
+ public static ParameterAttributes GetParameterAttribute (Parameter.Modifier modFlags)
+ {
+ return (modFlags & Parameter.Modifier.OUT) == Parameter.Modifier.OUT ?
+ ParameterAttributes.Out : ParameterAttributes.None;
}
-
- public void ComputeSignature (EmitContext ec)
- {
- signature = "";
- if (FixedParameters != null){
- for (int i = 0; i < FixedParameters.Length; i++){
- Parameter par = FixedParameters [i];
-
- signature += par.GetSignature (ec, loc);
- }
+
+ public Type [] GetEmitTypes ()
+ {
+ Type [] types = null;
+ if (has_arglist) {
+ if (Count == 1)
+ return Type.EmptyTypes;
+
+ types = new Type [Count - 1];
+ Array.Copy (Types, types, types.Length);
}
- //
- // Note: as per the spec, the `params' arguments (ArrayParameter)
- // are not used in the signature computation for a method
- //
+
+ for (int i = 0; i < Count; ++i) {
+ if ((FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) == 0)
+ continue;
+
+ if (types == null)
+ types = (Type []) Types.Clone ();
+
+ types [i] = TypeManager.GetReferenceType (types [i]);
+ }
+
+ if (types == null)
+ types = Types;
+
+ return types;
}
- void Error_DuplicateParameterName (string name)
+ public string GetSignatureForError ()
{
- Report.Error (
- 100, loc, "The parameter name `" + name + "' is a duplicate");
+ StringBuilder sb = new StringBuilder ("(");
+ for (int i = 0; i < Count; ++i) {
+ if (i != 0)
+ sb.Append (", ");
+ sb.Append (ParameterDesc (i));
+ }
+ sb.Append (')');
+ return sb.ToString ();
}
-
- public bool VerifyArgs ()
- {
- int count;
- int i, j;
- if (FixedParameters == null)
- return true;
-
- count = FixedParameters.Length;
- string array_par_name = ArrayParameter != null ? ArrayParameter.Name : null;
+ public bool HasArglist {
+ get { return has_arglist; }
+ }
- for (i = 0; i < count; i++){
- string base_name = FixedParameters [i].Name;
- for (j = i + 1; j < count; j++){
- if (base_name != FixedParameters [j].Name)
- continue;
- Error_DuplicateParameterName (base_name);
+ public bool HasExtensionMethodType {
+ get {
+ if (Count == 0)
return false;
+
+ return FixedParameters [0].HasExtensionMethodModifier;
+ }
+ }
+
+ public bool HasParams {
+ get { return has_params; }
+ }
+
+ public bool IsEmpty {
+ get { return parameters.Length == 0; }
+ }
+
+ public string ParameterDesc (int pos)
+ {
+ if (types == null || types [pos] == null)
+ return ((Parameter)FixedParameters [pos]).GetSignatureForError ();
+
+ string type = TypeManager.CSharpName (types [pos]);
+ if (FixedParameters [pos].HasExtensionMethodModifier)
+ return "this " + type;
+
+ Parameter.Modifier mod = FixedParameters [pos].ModFlags & ~Parameter.Modifier.ARGLIST;
+ if (mod == 0)
+ return type;
+
+ return Parameter.GetModifierSignature (mod) + " " + type;
+ }
+
+ public Type[] Types {
+ get { return types; }
+ set { types = value; }
+ }
+
+#if MS_COMPATIBLE
+ public AParametersCollection InflateTypes (Type[] genArguments, Type[] argTypes)
+ {
+ AParametersCollection p = (AParametersCollection) MemberwiseClone (); // Clone ();
+
+ for (int i = 0; i < Count; ++i) {
+ if (types[i].IsGenericType) {
+ Type[] gen_arguments_open = new Type[types[i].GetGenericTypeDefinition ().GetGenericArguments ().Length];
+ Type[] gen_arguments = types[i].GetGenericArguments ();
+ for (int ii = 0; ii < gen_arguments_open.Length; ++ii) {
+ if (gen_arguments[ii].IsGenericParameter) {
+ Type t = argTypes[gen_arguments[ii].GenericParameterPosition];
+ gen_arguments_open[ii] = t;
+ } else
+ gen_arguments_open[ii] = gen_arguments[ii];
+ }
+
+ p.types[i] = types[i].GetGenericTypeDefinition ().MakeGenericType (gen_arguments_open);
+ continue;
}
- if (base_name == array_par_name){
- Error_DuplicateParameterName (base_name);
- return false;
+ if (types[i].IsGenericParameter) {
+ Type gen_argument = argTypes[types[i].GenericParameterPosition];
+ p.types[i] = gen_argument;
+ continue;
}
}
- return true;
+
+ return p;
}
-
- ///
- /// Returns the signature of the Parameters evaluated in
- /// the @ec EmitContext
- ///
- public string GetSignature (EmitContext ec)
+#endif
+ }
+
+ //
+ // A collection of imported or resolved parameters
+ //
+ public class ParametersImported : AParametersCollection
+ {
+ ParametersImported (AParametersCollection param, Type[] types)
+ {
+ this.parameters = param.FixedParameters;
+ this.types = types;
+ has_arglist = param.HasArglist;
+ has_params = param.HasParams;
+ }
+
+ ParametersImported (IParameterData [] parameters, Type [] types, MethodBase method, bool hasParams)
{
- if (signature == null){
- VerifyArgs ();
- ComputeSignature (ec);
+ this.parameters = parameters;
+ this.types = types;
+ has_arglist = (method.CallingConvention & CallingConventions.VarArgs) != 0;
+ if (has_arglist) {
+ this.parameters = new IParameterData [parameters.Length + 1];
+ parameters.CopyTo (this.parameters, 0);
+ this.parameters [parameters.Length] = new ArglistParameter (Location.Null);
+ this.types = new Type [types.Length + 1];
+ types.CopyTo (this.types, 0);
+ this.types [types.Length] = TypeManager.arg_iterator_type;
}
-
- return signature;
+ has_params = hasParams;
}
-
- ///
- /// Returns the paramenter information based on the name
- ///
- public Parameter GetParameterByName (string name, out int idx)
+
+ public ParametersImported (IParameterData [] param, Type[] types)
{
- idx = 0;
- int i = 0;
+ this.parameters = param;
+ this.types = types;
+ }
- if (FixedParameters != null){
- foreach (Parameter par in FixedParameters){
- if (par.Name == name){
- idx = i;
- return par;
- }
- i++;
- }
+ public static AParametersCollection Create (MethodBase method)
+ {
+ return Create (method.GetParameters (), method);
+ }
+
+ //
+ // Generic method parameters importer, param is shared between all instances
+ //
+ public static AParametersCollection Create (AParametersCollection param, MethodBase method)
+ {
+ if (param.IsEmpty)
+ return param;
+
+ ParameterInfo [] pi = method.GetParameters ();
+ Type [] types = new Type [pi.Length];
+ for (int i = 0; i < types.Length; i++) {
+ Type t = pi [i].ParameterType;
+ if (t.IsByRef)
+ t = TypeManager.GetElementType (t);
+
+ types [i] = TypeManager.TypeToCoreType (t);
+ }
+
+ return new ParametersImported (param, types);
+ }
+
+ //
+ // Imports SRE parameters
+ //
+ public static AParametersCollection Create (ParameterInfo [] pi, MethodBase method)
+ {
+ if (pi.Length == 0) {
+ if (method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0)
+ return new ParametersImported (new IParameterData [0], Type.EmptyTypes, method, false);
+
+ return ParametersCompiled.EmptyReadOnlyParameters;
}
- if (ArrayParameter != null){
- if (name == ArrayParameter.Name){
- idx = i;
- return ArrayParameter;
+ Type [] types = new Type [pi.Length];
+ IParameterData [] par = new IParameterData [pi.Length];
+ bool is_params = false;
+ PredefinedAttribute extension_attr = PredefinedAttributes.Get.Extension;
+ PredefinedAttribute param_attr = PredefinedAttributes.Get.ParamArray;
+ for (int i = 0; i < types.Length; i++) {
+ types [i] = TypeManager.TypeToCoreType (pi [i].ParameterType);
+
+ ParameterInfo p = pi [i];
+ Parameter.Modifier mod = 0;
+ Expression default_value = null;
+ if (types [i].IsByRef) {
+ if ((p.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
+ mod = Parameter.Modifier.OUT;
+ else
+ mod = Parameter.Modifier.REF;
+
+ //
+ // Strip reference wrapping
+ //
+ types [i] = TypeManager.GetElementType (types [i]);
+ } else if (i == 0 && extension_attr.IsDefined && method != null && method.IsStatic &&
+ (method.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
+ method.IsDefined (extension_attr.Type, false)) {
+ mod = Parameter.Modifier.This;
+ } else {
+ if (i >= pi.Length - 2) {
+ if (types[i].IsArray) {
+ if (p.IsDefined (param_attr.Type, false)) {
+ mod = Parameter.Modifier.PARAMS;
+ is_params = true;
+ }
+ } else if (types[i] == TypeManager.runtime_argument_handle_type) {
+ par[i] = new ArglistParameter (Location.Null);
+ continue;
+ }
+ }
+
+ if (!is_params && p.IsOptional) {
+ if (p.DefaultValue == Missing.Value)
+ default_value = EmptyExpression.Null;
+ else
+ default_value = Constant.CreateConstant (types[i], p.DefaultValue, Location.Null);
+ }
}
+
+ par [i] = new ParameterData (p.Name, mod, default_value);
}
-
- return null;
+
+ return method != null ?
+ new ParametersImported (par, types, method, is_params) :
+ new ParametersImported (par, types);
}
+ }
+
+ ///
+ /// Represents the methods parameters
+ ///
+ public class ParametersCompiled : AParametersCollection
+ {
+ public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
+
+ // Used by C# 2.0 delegates
+ public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
- public Parameter GetParameterByName (string name)
+ private ParametersCompiled ()
{
- int idx;
+ parameters = new Parameter [0];
+ types = Type.EmptyTypes;
+ }
- return GetParameterByName (name, out idx);
+ private ParametersCompiled (Parameter [] parameters, Type [] types)
+ {
+ this.parameters = parameters;
+ this.types = types;
}
- bool ComputeParameterTypes (EmitContext ec)
+ public ParametersCompiled (params Parameter[] parameters)
{
- int extra = (ArrayParameter != null) ? 1 : 0;
- int i = 0;
- int pc;
+ if (parameters == null)
+ throw new ArgumentException ("Use EmptyReadOnlyParameters");
- if (FixedParameters == null)
- pc = extra;
- else
- pc = extra + FixedParameters.Length;
+ this.parameters = parameters;
+ int count = parameters.Length;
- types = new Type [pc];
-
- if (!VerifyArgs ()){
- FixedParameters = null;
- return false;
- }
-
- bool failed = false;
- if (FixedParameters != null){
- foreach (Parameter p in FixedParameters){
- Type t = null;
-
- if (p.Resolve (ec, loc))
- t = p.ExternalType ();
- else
- failed = true;
+ if (count == 0)
+ return;
- types [i] = t;
- i++;
- }
- }
-
- if (extra > 0){
- if (ArrayParameter.Resolve (ec, loc))
- types [i] = ArrayParameter.ExternalType ();
- else
- failed = true;
+ if (count == 1) {
+ has_params = (parameters [0].ModFlags & Parameter.Modifier.PARAMS) != 0;
+ return;
}
- if (failed){
- types = null;
- return false;
+ for (int i = 0; i < count; i++){
+ string base_name = parameters [i].Name;
+ has_params |= (parameters [i].ModFlags & Parameter.Modifier.PARAMS) != 0;
+
+ for (int j = i + 1; j < count; j++){
+ if (base_name != parameters [j].Name)
+ continue;
+
+ ErrorDuplicateName (parameters [i]);
+ i = j;
+ }
}
+ }
- return true;
+ public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
+ this (parameters)
+ {
+ this.has_arglist = has_arglist;
}
- ///
- /// Returns the argument types as an array
- ///
- static Type [] no_types = new Type [0];
+ public static ParametersCompiled CreateFullyResolved (Parameter p, Type type)
+ {
+ return new ParametersCompiled (new Parameter [] { p }, new Type [] { type });
+ }
- public Type [] GetParameterInfo (EmitContext ec)
+ public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, Type[] types)
{
- if (types != null)
- return types;
-
- if (FixedParameters == null && ArrayParameter == null)
- return no_types;
+ return new ParametersCompiled (parameters, types);
+ }
- if (ComputeParameterTypes (ec) == false){
- types = null;
- return null;
+ public static ParametersCompiled MergeGenerated (ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, Type compilerTypes)
+ {
+ return MergeGenerated (userParams, checkConflicts,
+ new Parameter [] { compilerParams },
+ new Type [] { compilerTypes });
+ }
+
+ //
+ // Use this method when you merge compiler generated parameters with user parameters
+ //
+ public static ParametersCompiled MergeGenerated (ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, Type[] compilerTypes)
+ {
+ Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length];
+ userParams.FixedParameters.CopyTo(all_params, 0);
+
+ Type [] all_types;
+ if (userParams.types != null) {
+ all_types = new Type [all_params.Length];
+ userParams.Types.CopyTo (all_types, 0);
+ } else {
+ all_types = null;
}
- return types;
+ int last_filled = userParams.Count;
+ int index = 0;
+ foreach (Parameter p in compilerParams) {
+ for (int i = 0; i < last_filled; ++i) {
+ while (p.Name == all_params [i].Name) {
+ if (checkConflicts && i < userParams.Count) {
+ Report.Error (316, userParams [i].Location,
+ "The parameter name `{0}' conflicts with a compiler generated name", p.Name);
+ }
+ p.Name = '_' + p.Name;
+ }
+ }
+ all_params [last_filled] = p;
+ if (all_types != null)
+ all_types [last_filled] = compilerTypes [index++];
+ ++last_filled;
+ }
+
+ ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
+ parameters.has_params = userParams.has_params;
+ return parameters;
+ }
+
+ protected virtual void ErrorDuplicateName (Parameter p)
+ {
+ Report.Error (100, p.Location, "The parameter name `{0}' is a duplicate", p.Name);
}
///
- /// Returns the type of a given parameter, and stores in the `is_out'
- /// boolean whether this is an out or ref parameter.
- ///
- /// Note that the returned type will not contain any dereference in this
- /// case (ie, you get "int" for a ref int instead of "int&"
+ /// Returns the parameter information based on the name
///
- public Type GetParameterInfo (EmitContext ec, int idx, out Parameter.Modifier mod)
+ public int GetParameterIndexByName (string name)
{
- mod = Parameter.Modifier.NONE;
-
- if (!VerifyArgs ()){
- FixedParameters = null;
- return null;
+ for (int idx = 0; idx < Count; ++idx) {
+ if (parameters [idx].Name == name)
+ return idx;
}
- if (FixedParameters == null && ArrayParameter == null)
- return null;
-
- if (types == null)
- if (ComputeParameterTypes (ec) == false)
- return null;
+ return -1;
+ }
- //
- // If this is a request for the variable lenght arg.
- //
- int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
- if (idx == array_idx)
- return types [idx];
+ public bool Resolve (IResolveContext ec)
+ {
+ if (types != null)
+ return true;
+
+ types = new Type [Count];
+
+ bool ok = true;
+ Parameter p;
+ for (int i = 0; i < FixedParameters.Length; ++i) {
+ p = this [i];
+ Type t = p.Resolve (ec);
+ if (t == null) {
+ ok = false;
+ continue;
+ }
- //
- // Otherwise, it is a fixed parameter
- //
- Parameter p = FixedParameters [idx];
- mod = p.ModFlags;
+ types [i] = t;
+ }
- if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
- mod |= Parameter.Modifier.ISBYREF;
+ return ok;
+ }
- return p.ParameterType;
+ public void ResolveVariable ()
+ {
+ for (int i = 0; i < FixedParameters.Length; ++i) {
+ this [i].ResolveVariable (i);
+ }
}
- public CallingConventions GetCallingConvention ()
+ public CallingConventions CallingConvention
{
- if (HasArglist)
- return CallingConventions.VarArgs;
- else
- return CallingConventions.Standard;
+ get {
+ if (HasArglist)
+ return CallingConventions.VarArgs;
+ else
+ return CallingConventions.Standard;
+ }
}
- //
- // The method's attributes are passed in because we need to extract
- // the "return:" attribute from there to apply on the return type
- //
- public void LabelParameters (EmitContext ec,
- MethodBase builder,
- Location loc) {
- //
- // Define each type attribute (in/out/ref) and
- // the argument names.
- //
- int i = 0;
-
+ // Define each type attribute (in/out/ref) and
+ // the argument names.
+ public void ApplyAttributes (MethodBase builder)
+ {
+ if (Count == 0)
+ return;
+
MethodBuilder mb = builder as MethodBuilder;
ConstructorBuilder cb = builder as ConstructorBuilder;
- if (FixedParameters != null) {
- for (i = 0; i < FixedParameters.Length; i++) {
- FixedParameters [i].DefineParameter (ec, mb, cb, i + 1, loc);
- }
+ for (int i = 0; i < Count; i++) {
+ this [i].ApplyAttributes (mb, cb, i + 1);
}
+ }
- if (ArrayParameter != null){
- ParameterBuilder pb;
- Parameter array_param = ArrayParameter;
+ public void VerifyClsCompliance ()
+ {
+ foreach (Parameter p in FixedParameters)
+ p.IsClsCompliant ();
+ }
- if (mb == null)
- pb = cb.DefineParameter (
- i + 1, array_param.Attributes,
- array_param.Name);
- else
- pb = mb.DefineParameter (
- i + 1, array_param.Attributes,
- array_param.Name);
-
- CustomAttributeBuilder a = new CustomAttributeBuilder (
- TypeManager.cons_param_array_attribute, new object [0]);
+ public Parameter this [int pos] {
+ get { return (Parameter) parameters [pos]; }
+ }
+
+ public Expression CreateExpressionTree (EmitContext ec, Location loc)
+ {
+ ArrayList initializers = new ArrayList (Count);
+ foreach (Parameter p in FixedParameters) {
+ //
+ // Each parameter expression is stored to local variable
+ // to save some memory when referenced later.
+ //
+ StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec));
+ if (se.Resolve (ec))
+ ec.CurrentBlock.AddScopeStatement (se);
- pb.SetCustomAttribute (a);
+ initializers.Add (p.ExpressionTreeVariableReference ());
}
+
+ return new ArrayCreation (
+ Parameter.ResolveParameterExpressionType (ec, loc),
+ "[]", initializers, loc);
+ }
+
+ public ParametersCompiled Clone ()
+ {
+ ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
+
+ p.parameters = new IParameterData [parameters.Length];
+ for (int i = 0; i < Count; ++i)
+ p.parameters [i] = this [i].Clone ();
+
+ return p;
}
}
}