2009-06-17 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / parameter.cs
index 1630f78b4b6cdc01ef646694841d8a386592facd..a6c5c63da7c0b41811e27bc1af73a1f09de97f86 100644 (file)
@@ -30,10 +30,10 @@ namespace Mono.CSharp {
                {
                }
 
-               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
+               public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
                {
 #if !NET_2_0
-                       if (a.Type == TypeManager.marshal_as_attr_type) {
+                       if (a.Type == pa.MarshalAs) {
                                UnmanagedMarshal marshal = a.GetMarshal (this);
                                if (marshal != null) {
                                        builder.SetMarshal (marshal);
@@ -70,9 +70,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               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");
                        }
 
@@ -80,7 +80,7 @@ namespace Mono.CSharp {
                        if (builder == null)
                                return;
 
-                       base.ApplyAttributeBuilder (a, cb);
+                       base.ApplyAttributeBuilder (a, cb, pa);
                }
 
                public override AttributeTargets AttributeTargets {
@@ -115,7 +115,7 @@ namespace Mono.CSharp {
                public ImplicitParameter (MethodBuilder mb):
                        base (null)
                {
-                       builder = mb.DefineParameter (1, ParameterAttributes.None, "");                 
+                       builder = mb.DefineParameter (1, ParameterAttributes.None, "value");                    
                }
 
                public override AttributeTargets AttributeTargets {
@@ -183,21 +183,7 @@ namespace Mono.CSharp {
                public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index)
                {
                        base.ApplyAttributes (mb, cb, index);
-
-                       CustomAttributeBuilder ca = TypeManager.param_array_attr;
-                       if (ca == null) {
-                               ConstructorInfo ci = TypeManager.GetPredefinedConstructor (TypeManager.param_array_type, Location, Type.EmptyTypes);
-                               if (ci == null)
-                                       return;
-
-                               ca = new CustomAttributeBuilder (ci, new object [0]);
-                               if (ca == null)
-                                       return;
-
-                               TypeManager.param_array_attr = ca;
-                       }
-                               
-                       builder.SetCustomAttribute (ca);
+                       PredefinedAttributes.Get.ParamArray.EmitAttribute (builder, Location);
                }
        }
 
@@ -231,7 +217,9 @@ namespace Mono.CSharp {
 
        public interface IParameterData
        {
+               Expression DefaultValue { get; }
                bool HasExtensionMethodModifier { get; }
+               bool HasDefaultValue { get; }
                Parameter.Modifier ModFlags { get; }
                string Name { get; }
        }
@@ -259,6 +247,7 @@ namespace Mono.CSharp {
                protected FullNamedExpression TypeName;
                readonly Modifier modFlags;
                string name;
+               Expression default_expr;
                protected Type parameter_type;
                public readonly Location Location;
                int idx;
@@ -282,31 +271,37 @@ namespace Mono.CSharp {
                        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 && ModFlags == Modifier.OUT) {
+                       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) {
+                       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) == Modifier.REF &&
-                           TypeManager.in_attribute_type != null && !OptAttributes.Contains (TypeManager.in_attribute_type)) {
+                       if (a.Type == PredefinedAttributes.Get.Out && (ModFlags & Modifier.REF) == Modifier.REF &&
+                           !OptAttributes.Contains (pa.In)) {
                                Report.Error (662, a.Location,
                                        "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");
                        }
 
-                       // TypeManager.default_parameter_value_attribute_type is null if !NET_2_0, or if System.dll is not referenced
-                       if (a.Type == TypeManager.default_parameter_value_attribute_type) {
+                       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 ();
@@ -315,10 +310,10 @@ namespace Mono.CSharp {
                                                        if (!t.IsArray)
                                                                t = TypeManager.type_type;
 
-                                                       Report.Error (1910, a.Location, "Argument of type `{0}' is not applicable for the DefaultValue attribute",
+                                                       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 DefaultValue attribute is not applicable on parameters of type `{0}'",
+                                                       Report.Error (1909, a.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'",
                                                                TypeManager.CSharpName (parameter_type)); ;
                                                }
                                                return;
@@ -334,7 +329,7 @@ namespace Mono.CSharp {
                                return;
                        }
 
-                       base.ApplyAttributeBuilder (a, cb);
+                       base.ApplyAttributeBuilder (a, cb, pa);
                }
                
                public virtual bool CheckAccessibility (InterfaceMemberBase member)
@@ -354,20 +349,54 @@ namespace Mono.CSharp {
                // <summary>
                //   Resolve is used in method definitions
                // </summary>
-               public virtual Type Resolve (IResolveContext ec)
+               public virtual Type Resolve (IResolveContext rc)
                {
                        // HACK: to resolve attributes correctly
-                       this.resolve_context = ec;
+                       this.resolve_context = rc;
 
                        if (parameter_type != null)
                                return parameter_type;
 
-                       TypeExpr texpr = TypeName.ResolveAsTypeTerminal (ec, false);
+                       TypeExpr texpr = TypeName.ResolveAsTypeTerminal (rc, false);
                        if (texpr == null)
                                return null;
 
                        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 ((modFlags & Parameter.Modifier.ISBYREF) != 0 &&
                                TypeManager.IsSpecialType (parameter_type)) {
                                Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'",
@@ -375,12 +404,12 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-#if GMCS_SOURCE
-                       TypeParameterExpr tparam = texpr as TypeParameterExpr;
-                       if (tparam != null) {
+                       TypeManager.CheckTypeVariance (parameter_type,
+                               (modFlags & Parameter.Modifier.ISBYREF) != 0 ? Variance.None : Variance.Contravariant,
+                               rc as MemberCore);
+
+                       if (texpr is TypeParameterExpr)
                                return parameter_type;
-                       }
-#endif
 
                        if ((parameter_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
                                Report.Error (721, Location, "`{0}': static types cannot be used as parameters",
@@ -401,6 +430,10 @@ namespace Mono.CSharp {
                        this.idx = idx;
                }
 
+               public bool HasDefaultValue {
+                       get { return default_expr != null; }
+               }
+
                public bool HasExtensionMethodModifier {
                        get { return (modFlags & Modifier.This) != 0; }
                }
@@ -415,7 +448,8 @@ namespace Mono.CSharp {
                }
 
                ParameterAttributes Attributes {
-                       get { return Parameters.GetParameterAttribute (modFlags); }
+                       get { return ParametersCompiled.GetParameterAttribute (modFlags) |
+                               (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); }
                }
 
                public override AttributeTargets AttributeTargets {
@@ -472,6 +506,21 @@ namespace Mono.CSharp {
 
                        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 ());
+                                       }
+                               }
+                       }
                }
 
                public override string[] ValidAttributeTargets {
@@ -493,6 +542,11 @@ namespace Mono.CSharp {
 
                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");
 
@@ -511,6 +565,11 @@ namespace Mono.CSharp {
                                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;
@@ -541,10 +600,7 @@ namespace Mono.CSharp {
 
                        bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
                        if (is_ref) {
-                               if (arg_idx <= 255)
-                                       ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
-                               else
-                                       ec.ig.Emit (OpCodes.Ldarg, arg_idx);
+                               ParameterReference.EmitLdArg (ec.ig, arg_idx);
                        } else {
                                if (arg_idx <= 255)
                                        ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
@@ -577,6 +633,13 @@ namespace Mono.CSharp {
 
                        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);
+               }
        }
 
        //
@@ -586,6 +649,7 @@ namespace Mono.CSharp {
        {
                readonly string name;
                readonly Parameter.Modifier modifiers;
+               readonly Expression default_value;
 
                public ParameterData (string name, Parameter.Modifier modifiers)
                {
@@ -593,12 +657,26 @@ namespace Mono.CSharp {
                        this.modifiers = modifiers;
                }
 
+               public ParameterData (string name, Parameter.Modifier modifiers, Expression defaultValue)
+                       : this (name, modifiers)
+               {
+                       this.default_value = defaultValue;
+               }
+
                #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; }
                }
@@ -762,9 +840,9 @@ namespace Mono.CSharp {
        //
        // A collection of imported or resolved parameters
        //
-       public class ParametersCollection : AParametersCollection
+       public class ParametersImported : AParametersCollection
        {
-               ParametersCollection (AParametersCollection param, Type[] types)
+               ParametersImported (AParametersCollection param, Type[] types)
                {
                        this.parameters = param.FixedParameters;
                        this.types = types;
@@ -772,7 +850,7 @@ namespace Mono.CSharp {
                        has_params = param.HasParams;
                }
 
-               ParametersCollection (IParameterData [] parameters, Type [] types, MethodBase method, bool hasParams)
+               ParametersImported (IParameterData [] parameters, Type [] types, MethodBase method, bool hasParams)
                {
                        this.parameters = parameters;
                        this.types = types;
@@ -788,7 +866,7 @@ namespace Mono.CSharp {
                        has_params = hasParams;
                }
 
-               public ParametersCollection (IParameterData [] param, Type[] types)
+               public ParametersImported (IParameterData [] param, Type[] types)
                {
                        this.parameters = param;
                        this.types = types;
@@ -817,7 +895,7 @@ namespace Mono.CSharp {
                                types [i] = TypeManager.TypeToCoreType (t);
                        }
 
-                       return new ParametersCollection (param, types);
+                       return new ParametersImported (param, types);
                }
 
                //
@@ -827,19 +905,22 @@ namespace Mono.CSharp {
                {
                        if (pi.Length == 0) {
                                if (method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0)
-                                       return new ParametersCollection (new IParameterData [0], Type.EmptyTypes, method, false);
+                                       return new ParametersImported (new IParameterData [0], Type.EmptyTypes, method, false);
 
-                               return Parameters.EmptyReadOnlyParameters;
+                               return ParametersCompiled.EmptyReadOnlyParameters;
                        }
 
                        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;
@@ -850,48 +931,63 @@ namespace Mono.CSharp {
                                        // Strip reference wrapping
                                        //
                                        types [i] = TypeManager.GetElementType (types [i]);
-                               } else if (i == 0 && TypeManager.extension_attribute_type != null && method != null && method.IsStatic &&
+                               } else if (i == 0 && extension_attr.IsDefined && method != null && method.IsStatic &&
                                (method.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
-                               method.IsDefined (TypeManager.extension_attribute_type, false)) {
+                                       method.IsDefined (extension_attr.Type, false)) {
                                        mod = Parameter.Modifier.This;
-                               } else if (i >= pi.Length - 2 && types [i].IsArray) {
-                                       if (p.IsDefined (TypeManager.param_array_type, false)) {
-                                               mod = Parameter.Modifier.PARAMS;
-                                               is_params = true;
+                               } 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);
+                               par [i] = new ParameterData (p.Name, mod, default_value);
                        }
 
                        return method != null ?
-                               new ParametersCollection (par, types, method, is_params) :
-                               new ParametersCollection (par, types);
+                               new ParametersImported (par, types, method, is_params) :
+                               new ParametersImported (par, types);
                }
        }
 
        /// <summary>
        ///   Represents the methods parameters
        /// </summary>
-       public class Parameters : AParametersCollection {
-               public static readonly Parameters EmptyReadOnlyParameters = new Parameters ();
+       public class ParametersCompiled : AParametersCollection
+       {
+               public static readonly ParametersCompiled EmptyReadOnlyParameters = new ParametersCompiled ();
                
                // Used by C# 2.0 delegates
-               public static readonly Parameters Undefined = new Parameters ();
+               public static readonly ParametersCompiled Undefined = new ParametersCompiled ();
 
-               private Parameters ()
+               private ParametersCompiled ()
                {
                        parameters = new Parameter [0];
                        types = Type.EmptyTypes;
                }
 
-               private Parameters (Parameter [] parameters, Type [] types)
+               private ParametersCompiled (Parameter [] parameters, Type [] types)
                {
                        this.parameters = parameters;
                    this.types = types;
                }
                
-               public Parameters (params Parameter[] parameters)
+               public ParametersCompiled (params Parameter[] parameters)
                {
                        if (parameters == null)
                                throw new ArgumentException ("Use EmptyReadOnlyParameters");
@@ -921,23 +1017,23 @@ namespace Mono.CSharp {
                        }
                }
 
-               public Parameters (Parameter [] parameters, bool has_arglist) :
+               public ParametersCompiled (Parameter [] parameters, bool has_arglist) :
                        this (parameters)
                {
                        this.has_arglist = has_arglist;
                }
                
-               public static Parameters CreateFullyResolved (Parameter p, Type type)
+               public static ParametersCompiled CreateFullyResolved (Parameter p, Type type)
                {
-                       return new Parameters (new Parameter [] { p }, new Type [] { type });
+                       return new ParametersCompiled (new Parameter [] { p }, new Type [] { type });
                }
                
-               public static Parameters CreateFullyResolved (Parameter[] parameters, Type[] types)
+               public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, Type[] types)
                {
-                       return new Parameters (parameters, types);
+                       return new ParametersCompiled (parameters, types);
                }
 
-               public static Parameters MergeGenerated (Parameters userParams, bool checkConflicts, Parameter compilerParams, Type compilerTypes)
+               public static ParametersCompiled MergeGenerated (ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, Type compilerTypes)
                {
                        return MergeGenerated (userParams, checkConflicts,
                                new Parameter [] { compilerParams },
@@ -947,7 +1043,7 @@ namespace Mono.CSharp {
                //
                // Use this method when you merge compiler generated parameters with user parameters
                //
-               public static Parameters MergeGenerated (Parameters userParams, bool checkConflicts, Parameter[] compilerParams, Type[] compilerTypes)
+               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);
@@ -978,7 +1074,7 @@ namespace Mono.CSharp {
                                ++last_filled;
                        }
                        
-                       Parameters parameters = new Parameters (all_params, all_types);
+                       ParametersCompiled parameters = new ParametersCompiled (all_params, all_types);
                        parameters.has_params = userParams.has_params;
                        return parameters;
                }
@@ -1005,7 +1101,7 @@ namespace Mono.CSharp {
                {
                        if (types != null)
                                return true;
-
+                       
                        types = new Type [Count];
                        
                        bool ok = true;
@@ -1086,9 +1182,9 @@ namespace Mono.CSharp {
                                "[]", initializers, loc);
                }
 
-               public Parameters Clone ()
+               public ParametersCompiled Clone ()
                {
-                       Parameters p = (Parameters) MemberwiseClone ();
+                       ParametersCompiled p = (ParametersCompiled) MemberwiseClone ();
 
                        p.parameters = new IParameterData [parameters.Length];
                        for (int i = 0; i < Count; ++i)