X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fmcs%2Fparameter.cs;h=226d7b6e31a1b530bab62eab6179ff6e59f547e8;hb=ab39e8acac105fa0db88514f259341c9f0201b22;hp=392e98d42365ae2b94cdf8e2c91a973ba6d5a8b7;hpb=d8c407c0cbcb4b36ad527b209ba70701d7b12ded;p=mono.git diff --git a/mcs/mcs/parameter.cs b/mcs/mcs/parameter.cs index 392e98d4236..226d7b6e31a 100644 --- a/mcs/mcs/parameter.cs +++ b/mcs/mcs/parameter.cs @@ -13,27 +13,22 @@ using System; using System.Reflection; using System.Reflection.Emit; -using System.Collections; using System.Text; +using System.Linq; namespace Mono.CSharp { /// /// Abstract Base class for parameters of a method. /// - public abstract class ParameterBase : Attributable { - + public abstract class ParameterBase : Attributable + { protected ParameterBuilder builder; - protected ParameterBase (Attributes attrs) - : base (attrs) - { - } - - public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { -#if !NET_2_0 - if (a.Type == TypeManager.marshal_as_attr_type) { +#if false + if (a.Type == pa.MarshalAs) { UnmanagedMarshal marshal = a.GetMarshal (this); if (marshal != null) { builder.SetMarshal (marshal); @@ -46,7 +41,18 @@ namespace Mono.CSharp { return; } - builder.SetCustomAttribute (cb); + if (a.Type == pa.Dynamic) { + a.Error_MisusedDynamicAttribute (); + return; + } + + builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata); + } + + public ParameterBuilder Builder { + get { + return builder; + } } public override bool IsClsComplianceRequired() @@ -58,29 +64,34 @@ namespace Mono.CSharp { /// /// Class for applying custom attributes on the return type /// - public class ReturnParameter : ParameterBase { - public ReturnParameter (MethodBuilder mb, Location location): - base (null) + public class ReturnParameter : ParameterBase + { + MemberCore method; + + // TODO: merge method and mb + public ReturnParameter (MemberCore method, MethodBuilder mb, Location location) { + this.method = method; try { builder = mb.DefineParameter (0, ParameterAttributes.None, ""); } catch (ArgumentOutOfRangeException) { - Report.RuntimeMissingSupport (location, "custom attributes on the return type"); + method.Compiler.Report.RuntimeMissingSupport (location, "custom attributes on the return type"); } } - public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb) + public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { - if (a.Type == TypeManager.cls_compliant_attribute_type) { - Report.Warning (3023, 1, a.Location, "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead"); + if (a.Type == pa.CLSCompliant) { + method.Compiler.Report.Warning (3023, 1, a.Location, + "CLSCompliant attribute has no meaning when applied to return types. Try putting it on the method instead"); } // This occurs after Warning -28 if (builder == null) return; - base.ApplyAttributeBuilder (a, cb); + base.ApplyAttributeBuilder (a, ctor, cdata, pa); } public override AttributeTargets AttributeTargets { @@ -89,12 +100,6 @@ namespace Mono.CSharp { } } - public override IResolveContext ResolveContext { - get { - throw new NotSupportedException (); - } - } - /// /// Is never called /// @@ -112,10 +117,9 @@ namespace Mono.CSharp { /// // TODO: should use more code from Parameter.ApplyAttributeBuilder public class ImplicitParameter : ParameterBase { - public ImplicitParameter (MethodBuilder mb): - base (null) + public ImplicitParameter (MethodBuilder mb) { - builder = mb.DefineParameter (1, ParameterAttributes.None, ""); + builder = mb.DefineParameter (1, ParameterAttributes.None, "value"); } public override AttributeTargets AttributeTargets { @@ -124,12 +128,6 @@ namespace Mono.CSharp { } } - public override IResolveContext ResolveContext { - get { - throw new NotSupportedException (); - } - } - /// /// Is never called /// @@ -147,16 +145,17 @@ namespace Mono.CSharp { { } - public override Type Resolve (IResolveContext ec) + public override TypeSpec Resolve (IMemberContext ec, int index) { if (parameter_type == null) throw new InternalErrorException ("A type of implicit lambda parameter `{0}' is not set", Name); + base.idx = index; return parameter_type; } - public Type Type { + public TypeSpec Type { set { parameter_type = value; } } } @@ -167,13 +166,14 @@ namespace Mono.CSharp { { } - public override Type Resolve (IResolveContext ec) + public override TypeSpec Resolve (IMemberContext ec, int index) { - if (base.Resolve (ec) == null) + if (base.Resolve (ec, index) == null) return null; - if (!parameter_type.IsArray || parameter_type.GetArrayRank () != 1) { - Report.Error (225, Location, "The params parameter must be a single dimensional array"); + var ac = parameter_type as ArrayContainer; + if (ac == null || ac.Rank != 1) { + ec.Compiler.Report.Error (225, Location, "The params parameter must be a single dimensional array"); return null; } @@ -183,29 +183,16 @@ 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); } } 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) + base (null, String.Empty, Parameter.Modifier.NONE, null, loc) { + parameter_type = InternalType.Arglist; } public override void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index) @@ -218,20 +205,17 @@ namespace Mono.CSharp { return true; } - public override Type Resolve (IResolveContext ec) - { - return typeof (ArglistParameter); - } - - public override string GetSignatureForError () + public override TypeSpec Resolve (IMemberContext ec, int index) { - return "__arglist"; + return parameter_type; } } public interface IParameterData { + Expression DefaultValue { get; } bool HasExtensionMethodModifier { get; } + bool HasDefaultValue { get; } Parameter.Modifier ModFlags { get; } string Name { get; } } @@ -248,7 +232,6 @@ namespace Mono.CSharp { PARAMS = 4, // This is a flag which says that it's either REF or OUT. ISBYREF = 8, - ARGLIST = 16, REFMASK = 32, OUTMASK = 64, This = 128 @@ -256,85 +239,94 @@ namespace Mono.CSharp { static string[] attribute_targets = new string [] { "param" }; - protected FullNamedExpression TypeName; + FullNamedExpression texpr; readonly Modifier modFlags; string name; - protected Type parameter_type; + Expression default_expr; + protected TypeSpec parameter_type; public readonly Location Location; - int idx; + protected int idx; public bool HasAddressTaken; - IResolveContext resolve_context; - LocalVariableReference expr_tree_variable; + Expression expr_tree_variable; static TypeExpr parameter_expr_tree_type; - public HoistedVariable HoistedVariableReference; + HoistedVariable hoisted_variant; public Parameter (FullNamedExpression type, string name, Modifier mod, Attributes attrs, Location loc) - : base (attrs) { - if (type == TypeManager.system_void_expr) - Report.Error (1536, loc, "Invalid parameter type `void'"); - this.name = name; modFlags = mod; Location = loc; - TypeName = type; + texpr = type; + + // Only assign, attributes will be attached during resolve + base.attributes = attrs; + } + +#region Properties + public FullNamedExpression TypeExpression { + get { + return texpr; + } } +#endregion - public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { - if (a.Type == TypeManager.in_attribute_type && ModFlags == Modifier.OUT) { - Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute"); + if (a.Type == pa.In && ModFlags == Modifier.OUT) { + a.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) { + a.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)) { - Report.Error (662, a.Location, + if (a.Type == PredefinedAttributes.Get.Out && (ModFlags & Modifier.REF) == Modifier.REF && + !OptAttributes.Contains (pa.In)) { + a.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) { - Report.Warning (3022, 1, a.Location, "CLSCompliant attribute has no meaning when applied to parameters. Try putting it on the method instead"); + if (a.Type == pa.CLSCompliant) { + a.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) { - 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 DefaultValue attribute", - TypeManager.CSharpName (t)); - } else { - Report.Error (1909, a.Location, "The DefaultValue attribute is not applicable on parameters of type `{0}'", - TypeManager.CSharpName (parameter_type)); ; - } - return; + if (HasDefaultValue && (a.Type == pa.DefaultParameterValue || a.Type == pa.OptionalParameter)) { + a.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) { + TypeSpec arg_type; + var c = a.GetParameterDefaultValue (out arg_type); + if (c == null) { + if (parameter_type == TypeManager.object_type) { + a.Report.Error (1910, a.Location, "Argument of type `{0}' is not applicable for the DefaultParameterValue attribute", + arg_type.GetSignatureForError ()); + } else { + a.Report.Error (1909, a.Location, "The DefaultParameterValue attribute is not applicable on parameters of type `{0}'", + parameter_type.GetSignatureForError ()); ; } + + 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); + if (arg_type == parameter_type || parameter_type == TypeManager.object_type || + (c.IsNull && TypeManager.IsReferenceType (parameter_type) && !TypeManager.IsGenericParameter (parameter_type))) + builder.SetConstant (c.GetValue ()); else - Report.Error (1908, a.Location, "The type of the default value should match the type of the parameter"); + a.Report.Error (1908, a.Location, "The type of the default value should match the type of the parameter"); + return; } - base.ApplyAttributeBuilder (a, cb); + base.ApplyAttributeBuilder (a, ctor, cdata, pa); } public virtual bool CheckAccessibility (InterfaceMemberBase member) @@ -345,76 +337,129 @@ namespace Mono.CSharp { return member.IsAccessibleAs (parameter_type); } - public override IResolveContext ResolveContext { - get { - return resolve_context; - } + public static void Reset () + { + parameter_expr_tree_type = null; } // // Resolve is used in method definitions // - public virtual Type Resolve (IResolveContext ec) + public virtual TypeSpec Resolve (IMemberContext rc, int index) { - // HACK: to resolve attributes correctly - this.resolve_context = ec; - if (parameter_type != null) return parameter_type; - TypeExpr texpr = TypeName.ResolveAsTypeTerminal (ec, false); - if (texpr == null) + if (attributes != null) + attributes.AttachTo (this, rc); + + var expr = texpr.ResolveAsTypeTerminal (rc, false); + if (expr == null) return null; + this.idx = index; + texpr = expr; parameter_type = texpr.Type; - + if ((modFlags & Parameter.Modifier.ISBYREF) != 0 && TypeManager.IsSpecialType (parameter_type)) { - Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'", + rc.Compiler.Report.Error (1601, Location, "Method or delegate parameter cannot be of type `{0}'", GetSignatureForError ()); return null; } -#if GMCS_SOURCE - if (parameter_type.IsGenericParameter) { - AbstractPropertyEventMethod accessor = ec as AbstractPropertyEventMethod; - if (accessor == null || !accessor.IsDummy) { - if ((parameter_type.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0) { - Report.Error (-38, Location, "Covariant type parameters cannot be used as method parameters"); - return null; - } else if ((ModFlags & Modifier.ISBYREF) != 0 && - (parameter_type.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0) { - Report.Error (-37, Location, "Contravariant type parameters cannot be used in output positions"); - return null; - } - } - return parameter_type; - } -#endif + TypeManager.CheckTypeVariance (parameter_type, + (modFlags & Parameter.Modifier.ISBYREF) != 0 ? Variance.None : Variance.Contravariant, + rc); - if ((parameter_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) { - Report.Error (721, Location, "`{0}': static types cannot be used as parameters", + if (parameter_type.IsStatic) { + rc.Compiler.Report.Error (721, Location, "`{0}': static types cannot be used as parameters", texpr.GetSignatureForError ()); return parameter_type; } - if ((modFlags & Modifier.This) != 0 && parameter_type.IsPointer) { - Report.Error (1103, Location, "The type of extension method cannot be `{0}'", + if ((modFlags & Modifier.This) != 0 && (parameter_type.IsPointer || parameter_type == InternalType.Dynamic)) { + rc.Compiler.Report.Error (1103, Location, "The extension method cannot be of type `{0}'", TypeManager.CSharpName (parameter_type)); } return parameter_type; } - public void ResolveVariable (int idx) + public void ResolveDefaultValue (ResolveContext rc) { - this.idx = idx; + if (default_expr != null) + default_expr = ResolveDefaultExpression (rc); + } + + Expression ResolveDefaultExpression (ResolveContext rc) + { + default_expr = default_expr.Resolve (rc); + if (default_expr == null) + return null; + + if (!(default_expr is Constant || default_expr is DefaultValueExpression)) { + if (TypeManager.IsNullableType (parameter_type)) { + rc.Compiler.Report.Error (1770, default_expr.Location, + "The expression being assigned to nullable optional parameter `{0}' must be default value", + Name); + } else { + rc.Compiler.Report.Error (1736, default_expr.Location, + "The expression being assigned to optional parameter `{0}' must be a constant or default value", + Name); + } + + return null; + } + + if (TypeManager.IsEqual (default_expr.Type, parameter_type)) + return default_expr; + + if (TypeManager.IsNullableType (parameter_type)) { + if (Convert.ImplicitNulableConversion (rc, default_expr, parameter_type) != null) + return default_expr; + } else { + var res = Convert.ImplicitConversionStandard (rc, default_expr, parameter_type, default_expr.Location); + if (res != null) { + if (!default_expr.IsNull && TypeManager.IsReferenceType (parameter_type) && parameter_type != TypeManager.string_type) { + rc.Compiler.Report.Error (1763, default_expr.Location, + "Optional parameter `{0}' of type `{1}' can only be initialized with `null'", + Name, GetSignatureForError ()); + + return null; + } + + return res; + } + } + + rc.Compiler.Report.Error (1750, Location, + "Optional parameter expression of type `{0}' cannot be converted to parameter type `{1}'", + TypeManager.CSharpName (default_expr.Type), GetSignatureForError ()); + + return null; + } + + public bool HasDefaultValue { + get { return default_expr != null; } } public bool HasExtensionMethodModifier { get { return (modFlags & Modifier.This) != 0; } } + // + // Hoisted parameter variant + // + public HoistedVariable HoistedVariant { + get { + return hoisted_variant; + } + set { + hoisted_variant = value; + } + } + public Modifier ModFlags { get { return modFlags & ~Modifier.This; } } @@ -425,7 +470,8 @@ namespace Mono.CSharp { } ParameterAttributes Attributes { - get { return ParametersCompiled.GetParameterAttribute (modFlags); } + get { return ParametersCompiled.GetParameterAttribute (modFlags) | + (HasDefaultValue ? ParameterAttributes.Optional : ParameterAttributes.None); } } public override AttributeTargets AttributeTargets { @@ -440,7 +486,7 @@ namespace Mono.CSharp { if (parameter_type != null) type_name = TypeManager.CSharpName (parameter_type); else - type_name = TypeName.GetSignatureForError (); + type_name = texpr.GetSignatureForError (); string mod = GetModifierSignature (modFlags); if (mod.Length > 0) @@ -465,12 +511,13 @@ namespace Mono.CSharp { } } - public void IsClsCompliant () + public void IsClsCompliant (IMemberContext ctx) { - if (AttributeTester.IsClsCompliant (parameter_type)) + if (parameter_type.IsCLSCompliant ()) return; - Report.Warning (3001, 1, Location, "Argument type `{0}' is not CLS-compliant", GetSignatureForError ()); + ctx.Compiler.Report.Warning (3001, 1, Location, + "Argument type `{0}' is not CLS-compliant", GetSignatureForError ()); } public virtual void ApplyAttributes (MethodBuilder mb, ConstructorBuilder cb, int index) @@ -482,6 +529,34 @@ 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.GetTypedValue ()); + } + } + } + + if (parameter_type == InternalType.Dynamic) { + PredefinedAttributes.Get.Dynamic.EmitAttribute (builder); + } else { + var trans_flags = TypeManager.HasDynamicTypeUsed (parameter_type); + if (trans_flags != null) { + var pa = PredefinedAttributes.Get.DynamicTransform; + if (pa.Constructor != null || pa.ResolveConstructor (Location, ArrayContainer.MakeType (TypeManager.bool_type))) { + builder.SetCustomAttribute ( + new CustomAttributeBuilder (pa.Constructor, new object [] { trans_flags })); + } + } + } } public override string[] ValidAttributeTargets { @@ -493,32 +568,31 @@ namespace Mono.CSharp { public Parameter Clone () { Parameter p = (Parameter) MemberwiseClone (); - if (attributes != null) { + if (attributes != null) p.attributes = attributes.Clone (); - p.attributes.AttachTo (p); - } return p; } - public ExpressionStatement CreateExpressionTreeVariable (EmitContext ec) + public ExpressionStatement CreateExpressionTreeVariable (BlockContext ec) { if ((modFlags & Modifier.ISBYREF) != 0) - Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier"); + ec.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 TemporaryVariable (ResolveParameterExpressionType (ec, Location).Type, Location); + expr_tree_variable = expr_tree_variable.Resolve (ec); - expr_tree_variable = new LocalVariableReference ( - ec.CurrentBlock, variable.Name, Location, variable, false); - - ArrayList arguments = new ArrayList (2); + Arguments arguments = new Arguments (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)); + Expression.CreateExpressionFactoryCall (ec, "Parameter", null, arguments, Location)); + } + + public Expression DefaultValue { + get { return default_expr; } + set { default_expr = value; } } public void Emit (EmitContext ec) @@ -527,7 +601,7 @@ namespace Mono.CSharp { if (!ec.IsStatic) arg_idx++; - ParameterReference.EmitLdArg (ec.ig, arg_idx); + ParameterReference.EmitLdArg (ec, arg_idx); } public void EmitAssign (EmitContext ec) @@ -537,9 +611,9 @@ namespace Mono.CSharp { arg_idx++; if (arg_idx <= 255) - ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx); + ec.Emit (OpCodes.Starg_S, (byte) arg_idx); else - ec.ig.Emit (OpCodes.Starg, arg_idx); + ec.Emit (OpCodes.Starg, arg_idx); } public void EmitAddressOf (EmitContext ec) @@ -551,12 +625,12 @@ namespace Mono.CSharp { bool is_ref = (ModFlags & Modifier.ISBYREF) != 0; if (is_ref) { - ParameterReference.EmitLdArg (ec.ig, arg_idx); + ParameterReference.EmitLdArg (ec, arg_idx); } else { if (arg_idx <= 255) - ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx); + ec.Emit (OpCodes.Ldarga_S, (byte) arg_idx); else - ec.ig.Emit (OpCodes.Ldarga, arg_idx); + ec.Emit (OpCodes.Ldarga, arg_idx); } } @@ -568,14 +642,14 @@ namespace Mono.CSharp { // // System.Linq.Expressions.ParameterExpression type // - public static TypeExpr ResolveParameterExpressionType (EmitContext ec, Location location) + public static TypeExpr ResolveParameterExpressionType (IMemberContext ec, Location location) { if (parameter_expr_tree_type != null) return parameter_expr_tree_type; - Type p_type = TypeManager.parameter_expression_type; + TypeSpec p_type = TypeManager.parameter_expression_type; if (p_type == null) { - p_type = TypeManager.CoreLookupType ("System.Linq.Expressions", "ParameterExpression", Kind.Class, true); + p_type = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "ParameterExpression", MemberKind.Class, true); TypeManager.parameter_expression_type = p_type; } @@ -584,6 +658,13 @@ namespace Mono.CSharp { return parameter_expr_tree_type; } + + public void Warning_UselessOptionalParameter (Report Report) + { + Report.Warning (1066, 1, Location, + "The default value specified for optional parameter `{0}' will never be used", + Name); + } } // @@ -593,6 +674,7 @@ namespace Mono.CSharp { { readonly string name; readonly Parameter.Modifier modifiers; + readonly Expression default_value; public ParameterData (string name, Parameter.Modifier modifiers) { @@ -600,12 +682,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; } } @@ -624,13 +720,21 @@ namespace Mono.CSharp { // Null object pattern protected IParameterData [] parameters; - protected Type [] types; + protected TypeSpec [] types; + + public CallingConventions CallingConvention { + get { + return has_arglist ? + CallingConventions.VarArgs : + CallingConventions.Standard; + } + } public int Count { get { return parameters.Length; } } - public Type ExtensionMethodType { + public TypeSpec ExtensionMethodType { get { if (Count == 0) return null; @@ -652,42 +756,62 @@ namespace Mono.CSharp { ParameterAttributes.Out : ParameterAttributes.None; } - public Type [] GetEmitTypes () + // Very expensive operation + public Type[] GetMetaInfo () { - Type [] types = null; + Type[] types; if (has_arglist) { if (Count == 1) return Type.EmptyTypes; types = new Type [Count - 1]; - Array.Copy (Types, types, types.Length); + } else { + if (Count == 0) + return Type.EmptyTypes; + + types = new Type [Count]; } - for (int i = 0; i < Count; ++i) { + for (int i = 0; i < types.Length; ++i) { + types[i] = Types[i].GetMetaInfo (); + if ((FixedParameters [i].ModFlags & Parameter.Modifier.ISBYREF) == 0) continue; - if (types == null) - types = (Type []) Types.Clone (); - - types [i] = TypeManager.GetReferenceType (types [i]); + // TODO MemberCache: Should go to MetaInfo getter + types [i] = types [i].MakeByRefType (); } - if (types == null) - types = Types; - return types; } + // + // Returns the parameter information based on the name + // + public int GetParameterIndexByName (string name) + { + for (int idx = 0; idx < Count; ++idx) { + if (parameters [idx].Name == name) + return idx; + } + + return -1; + } + public string GetSignatureForError () { - StringBuilder sb = new StringBuilder ("("); - for (int i = 0; i < Count; ++i) { + return GetSignatureForError ("(", ")", Count); + } + + public string GetSignatureForError (string start, string end, int count) + { + StringBuilder sb = new StringBuilder (start); + for (int i = 0; i < count; ++i) { if (i != 0) sb.Append (", "); sb.Append (ParameterDesc (i)); } - sb.Append (')'); + sb.Append (end); return sb.ToString (); } @@ -712,6 +836,43 @@ namespace Mono.CSharp { get { return parameters.Length == 0; } } + public AParametersCollection Inflate (TypeParameterInflator inflator) + { + TypeSpec[] inflated_types = null; + bool default_value = false; + + for (int i = 0; i < Count; ++i) { + var inflated_param = inflator.Inflate (types[i]); + if (inflated_types == null) { + if (inflated_param == types[i]) + continue; + + default_value |= FixedParameters[i] is DefaultValueExpression; + inflated_types = new TypeSpec[types.Length]; + Array.Copy (types, inflated_types, types.Length); + } + + inflated_types[i] = inflated_param; + } + + if (inflated_types == null) + return this; + + var clone = (AParametersCollection) MemberwiseClone (); + clone.types = inflated_types; + if (default_value) { + for (int i = 0; i < Count; ++i) { + var dve = clone.FixedParameters[i] as DefaultValueExpression; + if (dve != null) { + throw new NotImplementedException ("net"); + // clone.FixedParameters [i].DefaultValue = new DefaultValueExpression (); + } + } + } + + return clone; + } + public string ParameterDesc (int pos) { if (types == null || types [pos] == null) @@ -721,49 +882,17 @@ namespace Mono.CSharp { if (FixedParameters [pos].HasExtensionMethodModifier) return "this " + type; - Parameter.Modifier mod = FixedParameters [pos].ModFlags & ~Parameter.Modifier.ARGLIST; + Parameter.Modifier mod = FixedParameters [pos].ModFlags; if (mod == 0) return type; return Parameter.GetModifierSignature (mod) + " " + type; } - public Type[] Types { + public TypeSpec[] 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 (types[i].IsGenericParameter) { - Type gen_argument = argTypes[types[i].GenericParameterPosition]; - p.types[i] = gen_argument; - continue; - } - } - - return p; - } -#endif } // @@ -771,7 +900,7 @@ namespace Mono.CSharp { // public class ParametersImported : AParametersCollection { - ParametersImported (AParametersCollection param, Type[] types) + ParametersImported (AParametersCollection param, TypeSpec[] types) { this.parameters = param.FixedParameters; this.types = types; @@ -779,75 +908,43 @@ namespace Mono.CSharp { has_params = param.HasParams; } - ParametersImported (IParameterData [] parameters, Type [] types, MethodBase method, bool hasParams) + ParametersImported (IParameterData [] parameters, TypeSpec [] types, bool hasArglist, bool hasParams) { 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; - } - has_params = hasParams; + this.has_arglist = hasArglist; + this.has_params = hasParams; } - public ParametersImported (IParameterData [] param, Type[] types) + public ParametersImported (IParameterData [] param, TypeSpec[] types) { this.parameters = param; this.types = types; } - public static AParametersCollection Create (MethodBase method) + public static AParametersCollection Create (TypeSpec parent, 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); + return Create (parent, method.GetParameters (), method); } // - // Imports SRE parameters + // Imports System.Reflection parameters // - public static AParametersCollection Create (ParameterInfo [] pi, MethodBase method) + public static AParametersCollection Create (TypeSpec parent, 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); + int varargs = method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0 ? 1 : 0; + if (pi.Length == 0 && varargs == 0) return ParametersCompiled.EmptyReadOnlyParameters; - } - Type [] types = new Type [pi.Length]; - IParameterData [] par = new IParameterData [pi.Length]; + TypeSpec [] types = new TypeSpec [pi.Length + varargs]; + IParameterData [] par = new IParameterData [pi.Length + varargs]; bool is_params = false; - for (int i = 0; i < types.Length; i++) { - types [i] = TypeManager.TypeToCoreType (pi [i].ParameterType); - + for (int i = 0; i < pi.Length; i++) { ParameterInfo p = pi [i]; Parameter.Modifier mod = 0; - if (types [i].IsByRef) { + Expression default_value = null; + if (p.ParameterType.IsByRef) { if ((p.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out) mod = Parameter.Modifier.OUT; else @@ -856,25 +953,59 @@ 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 && - (method.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute && - method.IsDefined (TypeManager.extension_attribute_type, false)) { + types [i] = Import.ImportType (p.ParameterType.GetElementType ()); + } else if (i == 0 && method.IsStatic && parent.IsStatic && // TODO: parent.Assembly.IsExtension && + HasExtensionAttribute (method)) { 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; + types[i] = Import.ImportType (p.ParameterType); + } else { + types[i] = Import.ImportType (p.ParameterType); + + if (i >= pi.Length - 2 && types[i] is ArrayContainer) { + var cattrs = CustomAttributeData.GetCustomAttributes (p); + if (cattrs != null && cattrs.Any (l => l.Constructor.DeclaringType == typeof (ParamArrayAttribute))) { + mod = Parameter.Modifier.PARAMS; + is_params = true; + } + } + + if (!is_params && p.IsOptional) { + object value = p.DefaultValue; + if (value == Missing.Value) { + default_value = EmptyExpression.Null; + } else if (value == null) { + default_value = new NullLiteral (Location.Null); + } else { + default_value = Constant.CreateConstant (null, Import.ImportType (value.GetType ()), value, Location.Null); + } } } - par [i] = new ParameterData (p.Name, mod); + par [i] = new ParameterData (p.Name, mod, default_value); + } + + if (varargs != 0) { + par [par.Length - 1] = new ArglistParameter (Location.Null); + types [types.Length - 1] = InternalType.Arglist; } return method != null ? - new ParametersImported (par, types, method, is_params) : + new ParametersImported (par, types, varargs != 0, is_params) : new ParametersImported (par, types); } + + static bool HasExtensionAttribute (MethodBase mb) + { + var all_attributes = CustomAttributeData.GetCustomAttributes (mb); + foreach (var attr in all_attributes) { + var dt = attr.Constructor.DeclaringType; + if (dt.Name == "ExtensionAttribute" && dt.Namespace == "System.Runtime.CompilerServices") { + return true; + } + } + + return false; + } } /// @@ -890,16 +1021,16 @@ namespace Mono.CSharp { private ParametersCompiled () { parameters = new Parameter [0]; - types = Type.EmptyTypes; + types = TypeSpec.EmptyTypes; } - private ParametersCompiled (Parameter [] parameters, Type [] types) + private ParametersCompiled (IParameterData [] parameters, TypeSpec [] types) { this.parameters = parameters; this.types = types; } - public ParametersCompiled (params Parameter[] parameters) + public ParametersCompiled (CompilerContext ctx, params Parameter[] parameters) { if (parameters == null) throw new ArgumentException ("Use EmptyReadOnlyParameters"); @@ -923,46 +1054,104 @@ namespace Mono.CSharp { if (base_name != parameters [j].Name) continue; - ErrorDuplicateName (parameters [i]); + ErrorDuplicateName (parameters[i], ctx.Report); i = j; } } } - public ParametersCompiled (Parameter [] parameters, bool has_arglist) : - this (parameters) + public ParametersCompiled (CompilerContext ctx, Parameter [] parameters, bool has_arglist) : + this (ctx, parameters) { this.has_arglist = has_arglist; } - public static ParametersCompiled CreateFullyResolved (Parameter p, Type type) + public static ParametersCompiled CreateFullyResolved (Parameter p, TypeSpec type) { - return new ParametersCompiled (new Parameter [] { p }, new Type [] { type }); + return new ParametersCompiled (new Parameter [] { p }, new TypeSpec [] { type }); } - public static ParametersCompiled CreateFullyResolved (Parameter[] parameters, Type[] types) + public static ParametersCompiled CreateFullyResolved (IParameterData[] parameters, TypeSpec[] types) { return new ParametersCompiled (parameters, types); } - public static ParametersCompiled MergeGenerated (ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, Type compilerTypes) + public static AParametersCollection CreateFullyResolved (TypeSpec[] types) { - return MergeGenerated (userParams, checkConflicts, + var pd = new ParameterData [types.Length]; + for (int i = 0; i < pd.Length; ++i) + pd[i] = new ParameterData (null, Parameter.Modifier.NONE, null); + + return new ParametersCompiled (pd, types); + } + + public static ParametersCompiled CreateImplicitParameter (FullNamedExpression texpr, Location loc) + { + return new ParametersCompiled ( + new[] { new Parameter (texpr, "value", Parameter.Modifier.NONE, null, loc) }, + null); + } + + // + // Returns non-zero value for equal CLS parameter signatures + // + public static int IsSameClsSignature (AParametersCollection a, AParametersCollection b) + { + int res = 0; + + for (int i = 0; i < a.Count; ++i) { + var a_type = a.Types[i]; + var b_type = b.Types[i]; + if (TypeSpecComparer.Override.IsEqual (a_type, b_type)) { + const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT; + if ((a.FixedParameters[i].ModFlags & ref_out) != (b.FixedParameters[i].ModFlags & ref_out)) + res |= 1; + + continue; + } + + var ac_a = a_type as ArrayContainer; + if (ac_a == null) + return 0; + + var ac_b = b_type as ArrayContainer; + if (ac_b == null) + return 0; + + if (ac_a.Element is ArrayContainer || ac_b.Element is ArrayContainer) { + res |= 2; + continue; + } + + if (ac_a.Rank != ac_b.Rank && TypeSpecComparer.Override.IsEqual (ac_a.Element, ac_b.Element)) { + res |= 1; + continue; + } + + return 0; + } + + return res; + } + + public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter compilerParams, TypeSpec compilerTypes) + { + return MergeGenerated (ctx, userParams, checkConflicts, new Parameter [] { compilerParams }, - new Type [] { compilerTypes }); + new TypeSpec [] { 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) + public static ParametersCompiled MergeGenerated (CompilerContext ctx, ParametersCompiled userParams, bool checkConflicts, Parameter[] compilerParams, TypeSpec[] compilerTypes) { Parameter[] all_params = new Parameter [userParams.Count + compilerParams.Length]; userParams.FixedParameters.CopyTo(all_params, 0); - Type [] all_types; + TypeSpec [] all_types; if (userParams.types != null) { - all_types = new Type [all_params.Length]; + all_types = new TypeSpec [all_params.Length]; userParams.Types.CopyTo (all_types, 0); } else { all_types = null; @@ -974,7 +1163,7 @@ namespace Mono.CSharp { 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, + ctx.Report.Error (316, userParams[i].Location, "The parameter name `{0}' conflicts with a compiler generated name", p.Name); } p.Name = '_' + p.Name; @@ -991,36 +1180,23 @@ namespace Mono.CSharp { return parameters; } - protected virtual void ErrorDuplicateName (Parameter p) + protected virtual void ErrorDuplicateName (Parameter p, Report Report) { Report.Error (100, p.Location, "The parameter name `{0}' is a duplicate", p.Name); } - /// - /// Returns the parameter information based on the name - /// - public int GetParameterIndexByName (string name) - { - for (int idx = 0; idx < Count; ++idx) { - if (parameters [idx].Name == name) - return idx; - } - - return -1; - } - - public bool Resolve (IResolveContext ec) + public bool Resolve (IMemberContext ec) { if (types != null) return true; - types = new Type [Count]; + types = new TypeSpec [Count]; bool ok = true; Parameter p; for (int i = 0; i < FixedParameters.Length; ++i) { p = this [i]; - Type t = p.Resolve (ec); + TypeSpec t = p.Resolve (ec, i); if (t == null) { ok = false; continue; @@ -1032,20 +1208,10 @@ namespace Mono.CSharp { return ok; } - public void ResolveVariable () + public void ResolveDefaultValues (ResolveContext rc) { for (int i = 0; i < FixedParameters.Length; ++i) { - this [i].ResolveVariable (i); - } - } - - public CallingConventions CallingConvention - { - get { - if (HasArglist) - return CallingConventions.VarArgs; - else - return CallingConventions.Standard; + this [i].ResolveDefaultValue (rc); } } @@ -1064,19 +1230,19 @@ namespace Mono.CSharp { } } - public void VerifyClsCompliance () + public void VerifyClsCompliance (IMemberContext ctx) { foreach (Parameter p in FixedParameters) - p.IsClsCompliant (); + p.IsClsCompliant (ctx); } public Parameter this [int pos] { get { return (Parameter) parameters [pos]; } } - public Expression CreateExpressionTree (EmitContext ec, Location loc) + public Expression CreateExpressionTree (BlockContext ec, Location loc) { - ArrayList initializers = new ArrayList (Count); + var initializers = new ArrayInitializer (Count, loc); foreach (Parameter p in FixedParameters) { // // Each parameter expression is stored to local variable @@ -1091,7 +1257,7 @@ namespace Mono.CSharp { return new ArrayCreation ( Parameter.ResolveParameterExpressionType (ec, loc), - "[]", initializers, loc); + initializers, loc); } public ParametersCompiled Clone ()