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; } } }