X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fecore.cs;h=6beb5fab57d9b4711adb2684915f30f65b17a96f;hb=2f9913815e4eff4fbe15ce6f4532a27d7ace49e1;hp=ded4c22bad6c2b39afe7096874868e5225012194;hpb=4d1178f14ee5a5892c951b27e232b203d38fce40;p=mono.git diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index ded4c22bad6..6beb5fab57d 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -133,11 +133,11 @@ namespace Mono.CSharp { } // Not nice but we have broken hierarchy. - public virtual void CheckMarshalByRefAccess () + public virtual void CheckMarshalByRefAccess (EmitContext ec) { } - public virtual bool GetAttributableValue (Type valueType, out object value) + public virtual bool GetAttributableValue (Type value_type, out object value) { Attribute.Error_AttributeArgumentNotValid (loc); value = null; @@ -165,8 +165,7 @@ namespace Mono.CSharp { return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) || TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType); - if (mi.DeclaringType.Assembly == invocation_type.Assembly || - TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) { + if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) { if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem) return true; } else { @@ -185,6 +184,12 @@ namespace Mono.CSharp { return true; } + public virtual bool IsNull { + get { + return false; + } + } + /// /// Performs semantic analysis on the Expression /// @@ -335,12 +340,28 @@ namespace Mono.CSharp { public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl) { - if (Type.FullName == target.FullName){ + // The error was already reported as CS1660 + if (type == TypeManager.anonymous_method_type) + return; + + if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) { +#if GMCS_SOURCE + string sig1 = type.DeclaringMethod == null ? + TypeManager.CSharpName (type.DeclaringType) : + TypeManager.CSharpSignature (type.DeclaringMethod); + string sig2 = target.DeclaringMethod == null ? + TypeManager.CSharpName (target.DeclaringType) : + TypeManager.CSharpSignature (target.DeclaringMethod); Report.ExtraInformation (loc, String.Format ( - "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}", + "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ", + Type.Name, sig1, sig2)); +#endif + } else if (Type.FullName == target.FullName){ + Report.ExtraInformation (loc, + String.Format ( + "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ", Type.FullName, Type.Assembly.FullName, target.Assembly.FullName)); - } if (expl) { @@ -369,9 +390,8 @@ namespace Mono.CSharp { return; } - Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'", - Type == TypeManager.anonymous_method_type ? - "anonymous method" : "`" + GetSignatureForError () + "'", + Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'", + TypeManager.CSharpName (type), TypeManager.CSharpName (target)); } @@ -381,6 +401,11 @@ namespace Mono.CSharp { name); } + protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name) + { + Error_TypeDoesNotContainDefinition (loc, type, name); + } + public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name) { Report.SymbolRelatedToPreviousError (type); @@ -551,10 +576,10 @@ namespace Mono.CSharp { /// public abstract void Emit (EmitContext ec); - public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue) + public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true) { Emit (ec); - ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target); + ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target); } /// @@ -572,22 +597,25 @@ namespace Mono.CSharp { /// Returns a fully formed expression after a MemberLookup /// /// - public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc) + public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc) { if (mi is EventInfo) return new EventExpr ((EventInfo) mi, loc); - else if (mi is FieldInfo) - return new FieldExpr ((FieldInfo) mi, loc); - else if (mi is PropertyInfo) - return new PropertyExpr (containerType, (PropertyInfo) mi, loc); - else if (mi is Type){ + else if (mi is FieldInfo) { + FieldInfo fi = (FieldInfo) mi; + if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type)) + return new ConstantExpr (fi, loc); + return new FieldExpr (fi, loc); + } else if (mi is PropertyInfo) + return new PropertyExpr (container_type, (PropertyInfo) mi, loc); + else if (mi is Type) { return new TypeExpression ((System.Type) mi, loc); } return null; } - protected static ArrayList almostMatchedMembers = new ArrayList (4); + protected static ArrayList almost_matched_members = new ArrayList (4); // // FIXME: Probably implement a cache for (t,name,current_access_set)? @@ -633,10 +661,10 @@ namespace Mono.CSharp { string name, MemberTypes mt, BindingFlags bf, Location loc) { - almostMatchedMembers.Clear (); + almost_matched_members.Clear (); MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type, - queried_type, mt, bf, name, almostMatchedMembers); + queried_type, mt, bf, name, almost_matched_members); if (mi == null) return null; @@ -761,15 +789,15 @@ namespace Mono.CSharp { name, null, mt, bf); } - protected Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type, + protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type, Type queried_type, string name, string class_name, MemberTypes mt, BindingFlags bf) { - if (almostMatchedMembers.Count != 0) { - for (int i = 0; i < almostMatchedMembers.Count; ++i) { - MemberInfo m = (MemberInfo) almostMatchedMembers [i]; + if (almost_matched_members.Count != 0) { + for (int i = 0; i < almost_matched_members.Count; ++i) { + MemberInfo m = (MemberInfo) almost_matched_members [i]; for (int j = 0; j < i; ++j) { - if (m == almostMatchedMembers [j]) { + if (m == almost_matched_members [j]) { m = null; break; } @@ -797,7 +825,7 @@ namespace Mono.CSharp { ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m)); } } - almostMatchedMembers.Clear (); + almost_matched_members.Clear (); return null; } @@ -825,7 +853,7 @@ namespace Mono.CSharp { Report.Error (103, loc, "The name `{0}' does not exist in the current context", name); } else { - Error_TypeDoesNotContainDefinition (loc, queried_type, name); + Error_TypeDoesNotContainDefinition (queried_type, name); } return null; } @@ -859,6 +887,11 @@ namespace Mono.CSharp { return new MethodGroupExpr (members, type, loc); } + protected virtual void Error_NegativeArrayIndex (Location loc) + { + throw new NotImplementedException (); + } + /// /// Returns an expression that can be used to invoke operator true /// on the expression if it exists. @@ -880,12 +913,6 @@ namespace Mono.CSharp { static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc) { MethodGroupExpr operator_group; - -#if GMCS_SOURCE - if (TypeManager.IsNullableType (e.Type)) - return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec); -#endif - operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr; if (operator_group == null) return null; @@ -893,12 +920,12 @@ namespace Mono.CSharp { ArrayList arguments = new ArrayList (1); arguments.Add (new Argument (e, Argument.AType.Expression)); operator_group = operator_group.OverloadResolve ( - ec, arguments, false, loc); + ec, ref arguments, false, loc); if (operator_group == null) return null; - return new StaticCallExpr ((MethodInfo) operator_group, arguments, loc); + return new UserOperatorCall (operator_group, arguments, null, loc); } /// @@ -1050,7 +1077,7 @@ namespace Mono.CSharp { if (t == TypeManager.enum_type) ig.Emit (OpCodes.Ldind_Ref); else - LoadFromPtr (ig, TypeManager.EnumToUnderlying (t)); + LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t)); } else if (t.IsValueType || TypeManager.IsGenericParameter (t)) ig.Emit (OpCodes.Ldobj, t); else if (t.IsPointer) @@ -1065,7 +1092,7 @@ namespace Mono.CSharp { public static void StoreFromPtr (ILGenerator ig, Type type) { if (TypeManager.IsEnumType (type)) - type = TypeManager.EnumToUnderlying (type); + type = TypeManager.GetEnumUnderlyingType (type); if (type == TypeManager.int32_type || type == TypeManager.uint32_type) ig.Emit (OpCodes.Stind_I4); else if (type == TypeManager.int64_type || type == TypeManager.uint64_type) @@ -1116,34 +1143,41 @@ namespace Mono.CSharp { return 0; } - public static void Error_NegativeArrayIndex (Location loc) - { - Report.Error (248, loc, "Cannot create an array with a negative size"); - } - protected void Error_CannotCallAbstractBase (string name) { Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name); } + protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec) + { + Report.SymbolRelatedToPreviousError (type); + if (ec.CurrentInitializerVariable != null) { + Report.Error (1918, loc, "Members of a value type property `{0}' cannot be assigned with an object initializer", + GetSignatureForError ()); + } else { + Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable", + GetSignatureForError ()); + } + } + // // Converts `source' to an int, uint, long or ulong. // - public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc) + public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source) { - Expression target; + Expression converted; using (ec.With (EmitContext.Flags.CheckState, true)) { - target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc); - if (target == null) - target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc); - if (target == null) - target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc); - if (target == null) - target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc); - - if (target == null) { - source.Error_ValueCannotBeConverted (ec, loc, TypeManager.int32_type, false); + converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc); + if (converted == null) + converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc); + if (converted == null) + converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc); + if (converted == null) + converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc); + + if (converted == null) { + source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false); return null; } } @@ -1151,24 +1185,15 @@ namespace Mono.CSharp { // // Only positive constants are allowed at compile time // - if (target is Constant){ - if (target is IntConstant){ - if (((IntConstant) target).Value < 0){ - Error_NegativeArrayIndex (loc); - return null; - } - } - - if (target is LongConstant){ - if (((LongConstant) target).Value < 0){ - Error_NegativeArrayIndex (loc); - return null; - } + Constant c = converted as Constant; + if (c != null) { + if (c.IsNegative) { + Error_NegativeArrayIndex (source.loc); } - + return c; } - return target; + return new ArrayIndexCast (converted).Resolve (ec); } // @@ -1203,6 +1228,36 @@ namespace Mono.CSharp { return cloned; } + + public virtual Expression CreateExpressionTree (EmitContext ec) + { + throw new NotImplementedException ( + "Expression tree conversion not implemented for " + GetType ()); + } + + protected Expression CreateExpressionFactoryCall (string name, ArrayList args) + { + return CreateExpressionFactoryCall (name, null, args, loc); + } + + protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args) + { + return CreateExpressionFactoryCall (name, typeArguments, args, loc); + } + + public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc) + { + TypeExpr texpr = TypeManager.expression_type_expr; + if (texpr == null) { + Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true); + if (t == null) + return null; + + TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null); + } + + return new Invocation (new MemberAccess (texpr, name, typeArguments, loc), args); + } } /// @@ -1266,8 +1321,31 @@ namespace Mono.CSharp { if (c != null) return new EmptyConstantCast (c, type); + // + // No double conversion required when wrapping nullable types + // + if (TypeManager.IsNullableType (type)) { + EmptyCast empty_cast = child as EmptyCast; + if (empty_cast != null) { + if (TypeManager.IsNullableTypeOf (empty_cast.type, type)) + throw new InternalErrorException ("Missing nullable underlying type conversion {0} != {1}", + TypeManager.CSharpName (empty_cast.type), TypeManager.CSharpName (type)); + + empty_cast.type = type; + return empty_cast; + } + } + return new EmptyCast (child, type); - } + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + ArrayList args = new ArrayList (2); + args.Add (new Argument (child.CreateExpressionTree (ec))); + args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc))); + return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args); + } public override Expression DoResolve (EmitContext ec) { @@ -1282,9 +1360,9 @@ namespace Mono.CSharp { child.Emit (ec); } - public override bool GetAttributableValue (Type valueType, out object value) + public override bool GetAttributableValue (Type value_type, out object value) { - return child.GetAttributableValue (valueType, out value); + return child.GetAttributableValue (value_type, out value); } protected override void CloneTo (CloneContext clonectx, Expression t) @@ -1329,7 +1407,7 @@ namespace Mono.CSharp { foreach (MethodInfo oper in mi) { ParameterData pd = TypeManager.GetParameterData (oper); - if (pd.ParameterType (0) == child.Type && oper.ReturnType == type) + if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type) return oper; } @@ -1384,7 +1462,7 @@ namespace Mono.CSharp { foreach (MethodInfo oper in mi) { ParameterData pd = TypeManager.GetParameterData (oper); - if (pd.ParameterType (0) == child.Type && oper.ReturnType == type) + if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type) return oper; } @@ -1427,7 +1505,7 @@ namespace Mono.CSharp { foreach (MethodInfo oper in all_oper) { ParameterData pd = TypeManager.GetParameterData (oper); if (pd.ParameterType (0) == TypeManager.decimal_type) - operators.Add (oper.ReturnType, oper); + operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper); } } @@ -1471,10 +1549,10 @@ namespace Mono.CSharp { return child.GetValue (); } - public override Constant ConvertExplicitly (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { // FIXME: check that 'type' can be converted to 'target_type' first - return child.ConvertExplicitly (inCheckedContext, target_type); + return child.ConvertExplicitly (in_checked_context, target_type); } public override Constant Increment () @@ -1490,6 +1568,10 @@ namespace Mono.CSharp { get { return child.IsNegative; } } + public override bool IsNull { + get { return child.IsNull; } + } + public override bool IsZeroInteger { get { return child.IsZeroInteger; } } @@ -1536,7 +1618,7 @@ namespace Mono.CSharp { Child.Emit (ec); } - public override bool GetAttributableValue (Type valueType, out object value) + public override bool GetAttributableValue (Type value_type, out object value) { value = GetTypedValue (); return true; @@ -1588,12 +1670,12 @@ namespace Mono.CSharp { } } - public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly(bool in_checked_context, Type target_type) { if (Child.Type == target_type) return Child; - return Child.ConvertExplicitly (inCheckedContext, target_type); + return Child.ConvertExplicitly (in_checked_context, target_type); } public override Constant ConvertImplicitly (Type type) @@ -1927,6 +2009,12 @@ namespace Mono.CSharp { second_valid = true; } + public override Expression CreateExpressionTree (EmitContext ec) + { + // A cast has no expresion tree representation + return child.CreateExpressionTree (ec); + } + public override Expression DoResolve (EmitContext ec) { // This should never be invoked, we are born in fully @@ -1942,7 +2030,11 @@ namespace Mono.CSharp { if (second_valid) ec.ig.Emit (op2); - } + } + + public Type UnderlyingType { + get { return child.Type; } + } } /// @@ -1979,6 +2071,114 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Castclass, type); } } + + // + // Used when resolved expression has different representations for + // expression trees and emit phase + // + public class ReducedExpression : Expression + { + class ReducedConstantExpression : Constant + { + readonly Constant expr; + readonly Expression orig_expr; + + public ReducedConstantExpression (Constant expr, Expression orig_expr) + : base (expr.Location) + { + this.expr = expr; + this.orig_expr = orig_expr; + } + + public override string AsString () + { + return expr.AsString (); + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + return orig_expr.CreateExpressionTree (ec); + } + + public override object GetValue () + { + return expr.GetValue (); + } + + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) + { + throw new NotImplementedException (); + } + + public override Expression DoResolve (EmitContext ec) + { + eclass = expr.eclass; + type = expr.Type; + return this; + } + + public override Constant Increment () + { + throw new NotImplementedException (); + } + + public override bool IsDefaultValue { + get { + return expr.IsDefaultValue; + } + } + + public override bool IsNegative { + get { + return expr.IsNegative; + } + } + + public override void Emit (EmitContext ec) + { + expr.Emit (ec); + } + } + + readonly Expression expr, orig_expr; + + private ReducedExpression (Expression expr, Expression orig_expr) + { + this.expr = expr; + this.orig_expr = orig_expr; + } + + public static Expression Create (Constant expr, Expression original_expr) + { + return new ReducedConstantExpression (expr, original_expr); + } + + public static Expression Create (Expression expr, Expression original_expr) + { + Constant c = expr as Constant; + if (c != null) + return Create (c, original_expr); + + return new ReducedExpression (expr, original_expr); + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + return orig_expr.CreateExpressionTree (ec); + } + + public override Expression DoResolve (EmitContext ec) + { + eclass = expr.eclass; + type = expr.Type; + return this; + } + + public override void Emit (EmitContext ec) + { + expr.Emit (ec); + } + } /// /// SimpleName expressions are formed of a single word and only happen at the beginning @@ -2047,7 +2247,7 @@ namespace Mono.CSharp { public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name) { - if (ec.IsFieldInitializer) + if (ec.IsInFieldInitializer) Report.Error (236, l, "A field initializer cannot reference the nonstatic field, method, or property `{0}'", name); @@ -2080,14 +2280,10 @@ namespace Mono.CSharp { return SimpleNameResolve (ec, null, intermediate); } - private bool IsNestedChild (Type t, Type parent) + static bool IsNestedChild (Type t, Type parent) { - if (parent == null) - return false; - while (parent != null) { - parent = TypeManager.DropGenericTypeArguments (parent); - if (TypeManager.IsNestedChildOf (t, parent)) + if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent))) return true; parent = parent.BaseType; @@ -2102,12 +2298,8 @@ namespace Mono.CSharp { return null; DeclSpace ds = ec.DeclContainer; - while (ds != null) { - if (IsNestedChild (t, ds.TypeBuilder)) - break; - + while (ds != null && !IsNestedChild (t, ds.TypeBuilder)) ds = ds.Parent; - } if (ds == null) return null; @@ -2192,7 +2384,7 @@ namespace Mono.CSharp { if (Arguments != null) { FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true); if (retval != null) { - Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc, "type"); + Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc); return; } } @@ -2311,32 +2503,39 @@ namespace Mono.CSharp { // Stage 2: Lookup members // - DeclSpace lookup_ds = ec.DeclContainer; Type almost_matched_type = null; ArrayList almost_matched = null; - do { + for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) { + // either RootDeclSpace or GenericMethod if (lookup_ds.TypeBuilder == null) - break; + continue; e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc); - if (e != null) - break; + if (e != null) { + if (e is PropertyExpr) { + // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not, + // it doesn't know which accessor to check permissions against + if (((PropertyExpr) e).IsAccessibleFrom (ec.ContainerType, right_side != null)) + break; + } else if (e is EventExpr) { + if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType)) + break; + } else { + break; + } + e = null; + } - if (almost_matched == null && almostMatchedMembers.Count > 0) { + if (almost_matched == null && almost_matched_members.Count > 0) { almost_matched_type = lookup_ds.TypeBuilder; - almost_matched = (ArrayList) almostMatchedMembers.Clone (); + almost_matched = (ArrayList) almost_matched_members.Clone (); } - - lookup_ds =lookup_ds.Parent; - } while (lookup_ds != null); - - if (e == null && ec.ContainerType != null) - e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc); + } if (e == null) { - if (almost_matched == null && almostMatchedMembers.Count > 0) { + if (almost_matched == null && almost_matched_members.Count > 0) { almost_matched_type = ec.ContainerType; - almost_matched = (ArrayList) almostMatchedMembers.Clone (); + almost_matched = (ArrayList) almost_matched_members.Clone (); } e = ResolveAsTypeStep (ec, true); } @@ -2356,7 +2555,7 @@ namespace Mono.CSharp { } if (almost_matched != null) - almostMatchedMembers = almost_matched; + almost_matched_members = almost_matched; if (almost_matched_type == null) almost_matched_type = ec.ContainerType; Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name, @@ -2378,7 +2577,7 @@ namespace Mono.CSharp { Expression left; if (me.IsInstance) { - if (ec.IsStatic || ec.IsFieldInitializer) { + if (ec.IsStatic || ec.IsInFieldInitializer) { // // Note that an MemberExpr can be both IsInstance and IsStatic. // An unresolved MethodGroupExpr can contain both kinds of methods @@ -2389,7 +2588,7 @@ namespace Mono.CSharp { if (!me.IsStatic && (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) { Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ()); - return EmptyExpression.Null; + return null; } // @@ -2403,20 +2602,13 @@ namespace Mono.CSharp { left = new TypeExpression (ec.ContainerType, loc); } - e = me.ResolveMemberAccess (ec, left, loc, null); - if (e == null) - return null; - - me = e as MemberExpr; + me = me.ResolveMemberAccess (ec, left, loc, null); if (me == null) - return e; + return null; if (Arguments != null) { - MethodGroupExpr mg = me as MethodGroupExpr; - if (mg == null) - return null; - - return mg.ResolveGeneric (ec, Arguments); + Arguments.Resolve (ec); + me.SetTypeArguments (Arguments); } if (!me.IsStatic && (me.InstanceExpression != null) && @@ -2507,9 +2699,9 @@ namespace Mono.CSharp { return ds.CheckAccessLevel (Type); } - public virtual bool AsAccessible (DeclSpace ds, int flags) + public virtual bool AsAccessible (DeclSpace ds) { - return ds.AsAccessible (Type, flags); + return ds.IsAccessibleAs (Type); } public virtual bool IsClass { @@ -2853,9 +3045,9 @@ namespace Mono.CSharp { return texpr.CheckAccessLevel (ds); } - public override bool AsAccessible (DeclSpace ds, int flags) + public override bool AsAccessible (DeclSpace ds) { - return texpr.AsAccessible (ds, flags); + return texpr.AsAccessible (ds); } public override bool IsClass { @@ -2881,6 +3073,8 @@ namespace Mono.CSharp { /// public abstract class MemberExpr : Expression { + protected bool is_base; + /// /// The name of this member. /// @@ -2888,6 +3082,14 @@ namespace Mono.CSharp { get; } + // + // When base.member is used + // + public bool IsBase { + get { return is_base; } + set { is_base = value; } + } + /// /// Whether this is an instance member. /// @@ -2923,7 +3125,7 @@ namespace Mono.CSharp { // TODO: possible optimalization // Cache resolved constant result in FieldBuilder <-> expression map - public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc, + public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original) { // @@ -2948,12 +3150,16 @@ namespace Mono.CSharp { if (original != null && original.IdenticalNameAndTypeName (ec, left, loc)) return this; - error176 (loc, GetSignatureForError ()); - return null; + return ResolveExtensionMemberAccess (left); } InstanceExpression = left; + return this; + } + protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left) + { + error176 (loc, GetSignatureForError ()); return this; } @@ -2982,6 +3188,13 @@ namespace Mono.CSharp { if (prepare_for_load) ec.ig.Emit (OpCodes.Dup); } + + public virtual void SetTypeArguments (TypeArguments ta) + { + // TODO: need to get correct member type + Report.Error (307, loc, "The property `{0}' cannot be used with type arguments", + GetSignatureForError ()); + } } /// @@ -2989,17 +3202,14 @@ namespace Mono.CSharp { /// public class ExtensionMethodGroupExpr : MethodGroupExpr { - readonly NamespaceEntry namespaceEntry; + readonly NamespaceEntry namespace_entry; public Expression ExtensionExpression; + Argument extension_argument; public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l) : base (list, extensionType, l) { - this.namespaceEntry = n; - } - - public override bool IsBase { - get { return true; } + this.namespace_entry = n; } public override bool IsStatic { @@ -3007,14 +3217,14 @@ namespace Mono.CSharp { } public bool IsTopLevel { - get { return namespaceEntry == null; } + get { return namespace_entry == null; } } public override void EmitArguments (EmitContext ec, ArrayList arguments) { if (arguments == null) arguments = new ArrayList (1); - arguments.Insert (0, new Argument (ExtensionExpression)); + arguments.Insert (0, extension_argument); base.EmitArguments (ec, arguments); } @@ -3022,37 +3232,30 @@ namespace Mono.CSharp { { if (arguments == null) arguments = new ArrayList (1); - arguments.Insert (0, new Argument (ExtensionExpression)); + arguments.Insert (0, extension_argument); base.EmitCall (ec, arguments); } - public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc) + public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc) { - if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0) - return base.OverloadResolve (ec, arguments, may_fail, loc); - if (arguments == null) arguments = new ArrayList (1); arguments.Insert (0, new Argument (ExtensionExpression)); - MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespaceEntry, loc); - - // Restore original arguments - arguments.RemoveAt (0); + MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc); + // Store resolved argument and restore original arguments if (mg != null) - return mg; - - if (!may_fail) - return base.OverloadResolve (ec, arguments, may_fail, loc); + ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0]; + arguments.RemoveAt (0); - return null; + return mg; } MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc) { // Use normal resolve rules - MethodGroupExpr mg = base.OverloadResolve (ec, arguments, true, loc); + MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc); if (mg != null) return mg; @@ -3062,10 +3265,10 @@ namespace Mono.CSharp { // Search continues ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name); if (e == null) - return null; + return base.OverloadResolve (ec, ref arguments, false, loc); e.ExtensionExpression = ExtensionExpression; - return e.ResolveOverloadExtensions (ec, arguments, e.namespaceEntry, loc); + return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc); } } @@ -3073,23 +3276,30 @@ namespace Mono.CSharp { /// MethodGroupExpr represents a group of method candidates which /// can be resolved to the best method overload /// - public class MethodGroupExpr : MemberExpr { + public class MethodGroupExpr : MemberExpr + { + public interface IErrorHandler + { + bool NoExactMatch (EmitContext ec, MethodBase method); + } + + public IErrorHandler CustomErrorHandler; public MethodBase [] Methods; MethodBase best_candidate; - bool has_type_arguments; + // TODO: make private + public TypeArguments type_arguments; bool identical_type_name; - bool is_base; + Type delegate_type; public MethodGroupExpr (MemberInfo [] mi, Type type, Location l) + : this (type, l) { Methods = new MethodBase [mi.Length]; mi.CopyTo (Methods, 0); - eclass = ExprClass.MethodGroup; - this.type = type; - loc = l; } public MethodGroupExpr (ArrayList list, Type type, Location l) + : this (type, l) { try { Methods = (MethodBase[])list.ToArray (typeof (MethodBase)); @@ -3103,24 +3313,29 @@ namespace Mono.CSharp { throw; } - loc = l; + + } + + protected MethodGroupExpr (Type type, Location loc) + { + this.loc = loc; eclass = ExprClass.MethodGroup; this.type = type; } public override Type DeclaringType { get { - // - // We assume that the top-level type is in the end - // + // + // We assume that the top-level type is in the end + // return Methods [Methods.Length - 1].DeclaringType; - //return Methods [0].DeclaringType; + //return Methods [0].DeclaringType; } } - public bool HasTypeArguments { - get { - return has_type_arguments; + public Type DelegateType { + set { + delegate_type = value; } } @@ -3134,15 +3349,6 @@ namespace Mono.CSharp { } } - public virtual bool IsBase { - get { - return is_base; - } - set { - is_base = value; - } - } - public override string GetSignatureForError () { if (best_candidate != null) @@ -3159,6 +3365,9 @@ namespace Mono.CSharp { public override bool IsInstance { get { + if (best_candidate != null) + return !best_candidate.IsStatic; + foreach (MethodBase mb in Methods) if (!mb.IsStatic) return true; @@ -3169,6 +3378,9 @@ namespace Mono.CSharp { public override bool IsStatic { get { + if (best_candidate != null) + return best_candidate.IsStatic; + foreach (MethodBase mb in Methods) if (mb.IsStatic) return true; @@ -3187,57 +3399,77 @@ namespace Mono.CSharp { return (MethodInfo)mg.best_candidate; } - /// - /// Determines "better conversion" as specified in 14.4.2.3 - /// - /// Returns : p if a->p is better, - /// q if a->q is better, - /// null if neither is better - /// - static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q) + // + // 7.4.3.3 Better conversion from expression + // Returns : 1 if a->p is better, + // 2 if a->q is better, + // 0 if neither is better + // + static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q) { Type argument_type = TypeManager.TypeToCoreType (a.Type); - Expression argument_expr = a.Expr; + if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) { + // + // Uwrap delegate from Expression + // + if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) { + p = TypeManager.GetTypeArguments (p) [0]; + q = TypeManager.GetTypeArguments (q) [0]; + } + p = Delegate.GetInvokeMethod (null, p).ReturnType; + q = Delegate.GetInvokeMethod (null, q).ReturnType; + } else { + if (argument_type == p) + return 1; - if (argument_type == null) - throw new Exception ("Expression of type " + a.Expr + - " does not resolve its type"); + if (argument_type == q) + return 2; + } - if (p == null || q == null) - throw new InternalErrorException ("BetterConversion Got a null conversion"); + return BetterTypeConversion (ec, p, q); + } - if (p == q) - return null; + // + // 7.4.3.4 Better conversion from type + // + public static int BetterTypeConversion (EmitContext ec, Type p, Type q) + { + if (p == null || q == null) + throw new InternalErrorException ("BetterTypeConversion got a null conversion"); - if (argument_expr is NullLiteral) - { - // - // If the argument is null and one of the types to compare is 'object' and - // the other is a reference type, we prefer the other. - // - // This follows from the usual rules: - // * There is an implicit conversion from 'null' to type 'object' - // * There is an implicit conversion from 'null' to any reference type - // * There is an implicit conversion from any reference type to type 'object' - // * There is no implicit conversion from type 'object' to other reference types - // => Conversion of 'null' to a reference type is better than conversion to 'object' - // - // FIXME: This probably isn't necessary, since the type of a NullLiteral is the - // null type. I think it used to be 'object' and thus needed a special - // case to avoid the immediately following two checks. - // - if (!p.IsValueType && q == TypeManager.object_type) - return p; - if (!q.IsValueType && p == TypeManager.object_type) - return q; + if (p == TypeManager.int32_type) { + if (q == TypeManager.uint32_type || q == TypeManager.uint64_type) + return 1; + } else if (p == TypeManager.int64_type) { + if (q == TypeManager.uint64_type) + return 1; + } else if (p == TypeManager.sbyte_type) { + if (q == TypeManager.byte_type || q == TypeManager.ushort_type || + q == TypeManager.uint32_type || q == TypeManager.uint64_type) + return 1; + } else if (p == TypeManager.short_type) { + if (q == TypeManager.ushort_type || q == TypeManager.uint32_type || + q == TypeManager.uint64_type) + return 1; } - - if (argument_type == p) - return p; - if (argument_type == q) - return q; + if (q == TypeManager.int32_type) { + if (p == TypeManager.uint32_type || p == TypeManager.uint64_type) + return 2; + } if (q == TypeManager.int64_type) { + if (p == TypeManager.uint64_type) + return 2; + } else if (q == TypeManager.sbyte_type) { + if (p == TypeManager.byte_type || p == TypeManager.ushort_type || + p == TypeManager.uint32_type || p == TypeManager.uint64_type) + return 2; + } if (q == TypeManager.short_type) { + if (p == TypeManager.ushort_type || p == TypeManager.uint32_type || + p == TypeManager.uint64_type) + return 2; + } + // TODO: this is expensive Expression p_tmp = new EmptyExpression (p); Expression q_tmp = new EmptyExpression (q); @@ -3245,44 +3477,12 @@ namespace Mono.CSharp { bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p); if (p_to_q && !q_to_p) - return p; + return 1; if (q_to_p && !p_to_q) - return q; + return 2; - if (p == TypeManager.sbyte_type) - if (q == TypeManager.byte_type || q == TypeManager.ushort_type || - q == TypeManager.uint32_type || q == TypeManager.uint64_type) - return p; - if (q == TypeManager.sbyte_type) - if (p == TypeManager.byte_type || p == TypeManager.ushort_type || - p == TypeManager.uint32_type || p == TypeManager.uint64_type) - return q; - - if (p == TypeManager.short_type) - if (q == TypeManager.ushort_type || q == TypeManager.uint32_type || - q == TypeManager.uint64_type) - return p; - if (q == TypeManager.short_type) - if (p == TypeManager.ushort_type || p == TypeManager.uint32_type || - p == TypeManager.uint64_type) - return q; - - if (p == TypeManager.int32_type) - if (q == TypeManager.uint32_type || q == TypeManager.uint64_type) - return p; - if (q == TypeManager.int32_type) - if (p == TypeManager.uint32_type || p == TypeManager.uint64_type) - return q; - - if (p == TypeManager.int64_type) - if (q == TypeManager.uint64_type) - return p; - if (q == TypeManager.int64_type) - if (p == TypeManager.uint64_type) - return q; - - return null; + return 0; } /// @@ -3326,16 +3526,16 @@ namespace Mono.CSharp { continue; same = false; - Type better = BetterConversion (ec, a, ct, bt); + int result = BetterExpressionConversion (ec, a, ct, bt); // for each argument, the conversion to 'ct' should be no worse than // the conversion to 'bt'. - if (better == bt) + if (result == 2) return false; // for at least one argument, the conversion to 'ct' should be better than // the conversion to 'bt'. - if (better == ct) + if (result != 0) better_at_least_one = true; } @@ -3416,7 +3616,20 @@ namespace Mono.CSharp { return false; } - public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc, + protected override MemberExpr ResolveExtensionMemberAccess (Expression left) + { + if (!IsStatic) + return base.ResolveExtensionMemberAccess (left); + + // + // When left side is an expression and at least one candidate method is + // static, it can be extension method + // + InstanceExpression = left; + return this; + } + + public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original) { if (!(left is TypeExpr) && @@ -3425,6 +3638,12 @@ namespace Mono.CSharp { return base.ResolveMemberAccess (ec, left, loc, original); } + + public override Expression CreateExpressionTree (EmitContext ec) + { + return new Cast (new TypeExpression (typeof (MethodInfo), loc), + new TypeOfMethod ((MethodInfo)best_candidate, loc)); + } override public Expression DoResolve (EmitContext ec) { @@ -3450,7 +3669,7 @@ namespace Mono.CSharp { public virtual void EmitArguments (EmitContext ec, ArrayList arguments) { - Invocation.EmitArguments (ec, best_candidate, arguments, false, null); + Invocation.EmitArguments (ec, arguments, false, null); } public virtual void EmitCall (EmitContext ec, ArrayList arguments) @@ -3458,12 +3677,201 @@ namespace Mono.CSharp { Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc); } + protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method, + Argument a, ParameterData expected_par, Type paramType) + { + if (a is CollectionElementInitializer.ElementInitializerArgument) { + Report.SymbolRelatedToPreviousError (method); + if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) { + Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier", + TypeManager.CSharpSignature (method)); + return; + } + Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments", + TypeManager.CSharpSignature (method)); + } else if (delegate_type == null) { + Report.SymbolRelatedToPreviousError (method); + Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments", + TypeManager.CSharpSignature (method)); + } else + Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments", + TypeManager.CSharpName (delegate_type)); + + Parameter.Modifier mod = expected_par.ParameterModifier (idx); + + string index = (idx + 1).ToString (); + if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^ + (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) { + if ((mod & Parameter.Modifier.ISBYREF) == 0) + Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword", + index, Parameter.GetModifierSignature (a.Modifier)); + else + Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword", + index, Parameter.GetModifierSignature (mod)); + } else { + string p1 = a.GetSignatureForError (); + string p2 = TypeManager.CSharpName (paramType); + + if (p1 == p2) { + Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous "); + Report.SymbolRelatedToPreviousError (a.Expr.Type); + Report.SymbolRelatedToPreviousError (paramType); + } + Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2); + } + } + + protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters) + { + return parameters.Count; + } + public static bool IsAncestralType (Type first_type, Type second_type) { return first_type != second_type && (TypeManager.IsSubclassOf (second_type, first_type) || TypeManager.ImplementsInterface (second_type, first_type)); - } + } + + /// + /// Determines if the candidate method is applicable (section 14.4.2.1) + /// to the given set of arguments + /// A return value rates candidate method compatibility, + /// 0 = the best, int.MaxValue = the worst + /// + public int IsApplicable (EmitContext ec, + ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form) + { + MethodBase candidate = method; + + ParameterData pd = TypeManager.GetParameterData (candidate); + int param_count = GetApplicableParametersCount (candidate, pd); + + if (arg_count != param_count) { + if (!pd.HasParams) + return int.MaxValue - 10000 + Math.Abs (arg_count - param_count); + if (arg_count < param_count - 1) + return int.MaxValue - 10000 + Math.Abs (arg_count - param_count); + } + +#if GMCS_SOURCE + // + // 1. Handle generic method using type arguments when specified or type inference + // + if (TypeManager.IsGenericMethod (candidate)) { + if (type_arguments != null) { + Type [] g_args = candidate.GetGenericArguments (); + if (g_args.Length != type_arguments.Count) + return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length); + + // TODO: Don't create new method, create Parameters only + method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments); + candidate = method; + pd = TypeManager.GetParameterData (candidate); + } else { + int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate); + if (score != 0) + return score - 20000; + + if (TypeManager.IsGenericMethodDefinition (candidate)) + throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution", + TypeManager.CSharpSignature (candidate)); + + pd = TypeManager.GetParameterData (candidate); + } + } else { + if (type_arguments != null) + return int.MaxValue - 15000; + } +#endif + + // + // 2. Each argument has to be implicitly convertible to method parameter + // + method = candidate; + Parameter.Modifier p_mod = 0; + Type pt = null; + for (int i = 0; i < arg_count; i++) { + Argument a = (Argument) arguments [i]; + Parameter.Modifier a_mod = a.Modifier & + ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK); + + if (p_mod != Parameter.Modifier.PARAMS) { + p_mod = pd.ParameterModifier (i) & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK); + + if (p_mod == Parameter.Modifier.ARGLIST) { + if (a.Type == TypeManager.runtime_argument_handle_type) + continue; + + p_mod = 0; + } + + pt = pd.ParameterType (i); + } else { + params_expanded_form = true; + } + + int score = 1; + if (!params_expanded_form) + score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt); + + if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) { + // It can be applicable in expanded form + score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ()); + if (score == 0) + params_expanded_form = true; + } + + if (score != 0) { + if (params_expanded_form) + ++score; + return (arg_count - i) * 2 + score; + } + } + + if (arg_count != param_count) + params_expanded_form = true; + + return 0; + } + + int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter) + { + // + // Types have to be identical when ref or out modifer is used + // + if (arg_mod != 0 || param_mod != 0) { + if (TypeManager.HasElementType (parameter)) + parameter = parameter.GetElementType (); + + Type a_type = argument.Type; + if (TypeManager.HasElementType (a_type)) + a_type = a_type.GetElementType (); + + if (a_type != parameter) + return 2; + + return 0; + } + + // FIXME: Kill this abomination (EmitContext.TempEc) + EmitContext prevec = EmitContext.TempEc; + EmitContext.TempEc = ec; + try { + if (delegate_type != null ? + !Delegate.IsTypeCovariant (argument.Expr, parameter) : + !Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) + return 2; + + if (arg_mod != param_mod) + return 1; + + } finally { + EmitContext.TempEc = prevec; + } + + return 0; + } public static bool IsOverride (MethodBase cand_method, MethodBase base_method) { @@ -3594,7 +4002,7 @@ namespace Mono.CSharp { /// that is the best match of me on Arguments. /// /// - public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments, + public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments, bool may_fail, Location loc) { bool method_params = false; @@ -3637,23 +4045,11 @@ namespace Mono.CSharp { int j = 0; for (int i = 0; i < Methods.Length; ++i) { MethodBase m = Methods [i]; -#if GMCS_SOURCE - Type [] gen_args = null; - if (m.IsGenericMethod && !m.IsGenericMethodDefinition) - gen_args = m.GetGenericArguments (); -#endif if (TypeManager.IsOverride (m)) { if (candidate_overrides == null) candidate_overrides = new ArrayList (); candidate_overrides.Add (m); m = TypeManager.TryGetBaseDefinition (m); -#if GMCS_SOURCE - if (m != null && gen_args != null) { - if (!m.IsGenericMethodDefinition) - throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition"); - m = ((MethodInfo) m).MakeGenericMethod (gen_args); - } -#endif } if (m != null) Methods [j++] = m; @@ -3661,12 +4057,17 @@ namespace Mono.CSharp { nmethods = j; } - int applicable_errors = Report.Errors; - + // + // Enable message recording, it's used mainly by lambda expressions + // + Report.IMessageRecorder msg_recorder = new Report.MessageRecorder (); + Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder); + // // First we construct the set of applicable methods // bool is_sorted = true; + int best_candidate_rate = int.MaxValue; for (int i = 0; i < nmethods; i++) { Type decl_type = Methods [i].DeclaringType; @@ -3679,22 +4080,29 @@ namespace Mono.CSharp { // // Check if candidate is applicable (section 14.4.2.1) - // Is candidate applicable in normal form? // - bool is_applicable = Invocation.IsApplicable (ec, this, Arguments, arg_count, ref Methods [i]); + bool params_expanded_form = false; + int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form); - if (!is_applicable && Invocation.IsParamsMethodApplicable (ec, this, Arguments, arg_count, ref Methods [i])) { - MethodBase candidate = Methods [i]; + if (candidate_rate < best_candidate_rate) { + best_candidate_rate = candidate_rate; + best_candidate = Methods [i]; + } + + if (params_expanded_form) { if (candidate_to_form == null) candidate_to_form = new PtrHashtable (); + MethodBase candidate = Methods [i]; candidate_to_form [candidate] = candidate; - // Candidate is applicable in expanded form - is_applicable = true; } - if (!is_applicable) + if (candidate_rate != 0) { + if (msg_recorder != null) + msg_recorder.EndSession (); continue; + } + msg_recorder = null; candidates.Add (Methods [i]); if (applicable_type == null) @@ -3706,89 +4114,89 @@ namespace Mono.CSharp { } } - if (applicable_errors != Report.Errors) + Report.SetMessageRecorder (prev_recorder); + if (msg_recorder != null && msg_recorder.PrintMessages ()) return null; int candidate_top = candidates.Count; if (applicable_type == null) { - if (ec.IsInProbingMode) - return null; - // - // Okay so we have failed to find anything so we - // return by providing info about the closest match + // When we found a top level method which does not match and it's + // not an extension method. We start extension methods lookup from here // - int errors = Report.Errors; - for (int i = 0; i < nmethods; ++i) { - MethodBase c = Methods [i]; - ParameterData pd = TypeManager.GetParameterData (c); - - if (pd.Count != arg_count) - continue; - -#if GMCS_SOURCE - if (!TypeManager.InferTypeArguments (ec, Arguments, ref c)) - continue; - if (TypeManager.IsGenericMethodDefinition (c)) - continue; -#endif - - Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, - c, false, null, may_fail, loc); - - if (!may_fail && errors == Report.Errors){ - - throw new InternalErrorException ( - "VerifyArgumentsCompat and IsApplicable do not agree; " + - "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync"); + if (InstanceExpression != null) { + ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name); + if (ex_method_lookup != null) { + ex_method_lookup.ExtensionExpression = InstanceExpression; + ex_method_lookup.SetTypeArguments (type_arguments); + return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc); } - - break; } + + if (may_fail) + return null; - if (!may_fail && errors == Report.Errors) { - string report_name = Name; - if (report_name == ".ctor") - report_name = TypeManager.CSharpName (DeclaringType); - -#if GMCS_SOURCE - // - // Type inference - // - for (int i = 0; i < Methods.Length; ++i) { - MethodBase c = Methods [i]; - ParameterData pd = TypeManager.GetParameterData (c); - - if (pd.Count != arg_count) - continue; - - if (TypeManager.InferTypeArguments (ec, Arguments, ref c)) - continue; - - Report.Error ( - 411, loc, "The type arguments for " + - "method `{0}' cannot be inferred from " + - "the usage. Try specifying the type " + - "arguments explicitly", TypeManager.CSharpSignature (c)); - return null; + // + // Okay so we have failed to find exact match so we + // return error info about the closest match + // + if (best_candidate != null) { + if (CustomErrorHandler != null) { + if (CustomErrorHandler.NoExactMatch (ec, best_candidate)) + return null; } -#endif - if (Name == ConstructorInfo.ConstructorName) { - if (almostMatchedMembers.Count != 0) { - Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor", - null, MemberTypes.Constructor, AllBindingFlags); + ParameterData pd = TypeManager.GetParameterData (best_candidate); + bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); + if (arg_count == pd.Count || pd.HasParams) { + if (TypeManager.IsGenericMethodDefinition (best_candidate)) { + if (type_arguments == null) { + Report.Error (411, loc, + "The type arguments for method `{0}' cannot be inferred from " + + "the usage. Try specifying the type arguments explicitly", + TypeManager.CSharpSignature (best_candidate)); + return null; + } + + Type [] g_args = TypeManager.GetGenericArguments (best_candidate); + if (type_arguments.Count != g_args.Length) { + Report.SymbolRelatedToPreviousError (best_candidate); + Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)", + TypeManager.CSharpSignature (best_candidate), + g_args.Length.ToString ()); + return null; + } } else { - Report.SymbolRelatedToPreviousError (type); - Report.Error (1729, loc, - "The type `{0}' does not contain a constructor that takes `{1}' arguments", - TypeManager.CSharpName (type), arg_count); + if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) { + Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc); + return null; + } } - } else { - Invocation.Error_WrongNumArguments (loc, report_name, arg_count); + + if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc)) + return null; } } + + if (almost_matched_members.Count != 0) { + Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor", + null, MemberTypes.Constructor, AllBindingFlags); + return null; + } + + // + // We failed to find any method with correct argument count + // + if (Name == ConstructorInfo.ConstructorName) { + Report.SymbolRelatedToPreviousError (type); + Report.Error (1729, loc, + "The type `{0}' does not contain a constructor that takes `{1}' arguments", + TypeManager.CSharpName (type), arg_count); + } else { + Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments", + Name, arg_count.ToString ()); + } return null; } @@ -3849,7 +4257,9 @@ namespace Mono.CSharp { // best_candidate = (MethodBase) candidates [0]; - method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); + if (delegate_type == null) + method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); + for (int ix = 1; ix < candidate_top; ix++) { MethodBase candidate = (MethodBase) candidates [ix]; @@ -3870,7 +4280,7 @@ namespace Mono.CSharp { // should be better than all the others // MethodBase ambiguous = null; - for (int ix = 0; ix < candidate_top; ix++) { + for (int ix = 1; ix < candidate_top; ix++) { MethodBase candidate = (MethodBase) candidates [ix]; if (candidate == best_candidate) @@ -3902,16 +4312,37 @@ namespace Mono.CSharp { throw new InternalErrorException ( "Should not happen. An 'override' method took part in overload resolution: " + best_candidate); - if (candidate_overrides != null) + if (candidate_overrides != null) { + Type[] gen_args = null; + bool gen_override = false; + if (TypeManager.IsGenericMethod (best_candidate)) + gen_args = TypeManager.GetGenericArguments (best_candidate); + foreach (MethodBase candidate in candidate_overrides) { - if (IsOverride (candidate, best_candidate)) + if (TypeManager.IsGenericMethod (candidate)) { + if (gen_args == null) + continue; + + if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length) + continue; + } else { + if (gen_args != null) + continue; + } + + if (IsOverride (candidate, best_candidate)) { + gen_override = true; best_candidate = candidate; + } } - } - // We can stop here when probing is on - if (ec.IsInProbingMode) - return this; + if (gen_override && gen_args != null) { +#if GMCS_SOURCE + best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args); +#endif + } + } + } // // And now check if the arguments are all @@ -3919,8 +4350,8 @@ namespace Mono.CSharp { // necessary etc. and return if everything is // all right // - if (!Invocation.VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate, - method_params, null, may_fail, loc)) + if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, + method_params, may_fail, loc)) return null; if (best_candidate == null) @@ -3940,68 +4371,189 @@ namespace Mono.CSharp { return this; } - public Expression ResolveGeneric (EmitContext ec, TypeArguments args) + public override void SetTypeArguments (TypeArguments ta) { -#if GMCS_SOURCE - if (!args.Resolve (ec)) - return null; + type_arguments = ta; + } - Type[] atypes = args.Arguments; + public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments, + int arg_count, MethodBase method, + bool chose_params_expanded, + bool may_fail, Location loc) + { + ParameterData pd = TypeManager.GetParameterData (method); - int first_count = 0; - MethodInfo first = null; + int errors = Report.Errors; + Parameter.Modifier p_mod = 0; + Type pt = null; + int a_idx = 0, a_pos = 0; + Argument a = null; + ArrayList params_initializers = null; + + for (; a_idx < arg_count; a_idx++, ++a_pos) { + a = (Argument) arguments [a_idx]; + if (p_mod != Parameter.Modifier.PARAMS) { + p_mod = pd.ParameterModifier (a_idx); + pt = pd.ParameterType (a_idx); + + if (p_mod == Parameter.Modifier.ARGLIST) { + if (a.Type != TypeManager.runtime_argument_handle_type) + break; + continue; + } - ArrayList list = new ArrayList (); - foreach (MethodBase mb in Methods) { - MethodInfo mi = mb as MethodInfo; - if ((mi == null) || !mb.IsGenericMethod) - continue; + if (pt.IsPointer && !ec.InUnsafe) { + if (may_fail) + return false; - Type[] gen_params = mb.GetGenericArguments (); + UnsafeError (loc); + } - if (first == null) { - first = mi; - first_count = gen_params.Length; + if (p_mod == Parameter.Modifier.PARAMS) { + if (chose_params_expanded) { + params_initializers = new ArrayList (arg_count - a_idx); + pt = TypeManager.GetElementType (pt); + } + } else if (p_mod != 0) { + pt = TypeManager.GetElementType (pt); + } } - if (gen_params.Length != atypes.Length) + // + // Types have to be identical when ref or out modifer is used + // + if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) { + if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier) + break; + + if (!TypeManager.IsEqual (a.Expr.Type, pt)) + break; + continue; + } + + Expression conv; + if (TypeManager.IsEqual (a.Type, pt)) { + conv = a.Expr; + } else { + conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc); + if (conv == null) + break; + } - mi = mi.MakeGenericMethod (atypes); - list.Add (mi); - -#if MS_COMPATIBLE - // MS implementation throws NotSupportedException for GetParameters - // on unbaked generic method - Parameters p = TypeManager.GetParameterData (mi) as Parameters; - if (p != null) { - p = p.Clone (); - p.InflateTypes (gen_params, atypes); - TypeManager.RegisterMethod (mi, p); + // + // Convert params arguments to an array initializer + // + if (params_initializers != null) { + params_initializers.Add (conv); + arguments.RemoveAt (a_idx--); + --arg_count; + continue; } -#endif + + // Update the argument with the implicit conversion + a.Expr = conv; } - if (list.Count > 0) { - this.Methods = (MethodBase []) list.ToArray (typeof (MethodBase)); - has_type_arguments = true; - return this; + // + // Fill not provided arguments required by params modifier + // + if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) { + if (arguments == null) + arguments = new ArrayList (1); + + pt = pd.Types [GetApplicableParametersCount (method, pd) - 1]; + pt = TypeManager.GetElementType (pt); + params_initializers = new ArrayList (0); } - if (first != null) { - Report.SymbolRelatedToPreviousError (first); - Report.Error ( - 305, loc, "Using the generic method `{0}' requires `{1}' type arguments", - TypeManager.CSharpSignature (first), first_count.ToString ()); - } else - Report.Error ( - 308, loc, "The non-generic method `{0}' " + - "cannot be used with type arguments", Name); + if (a_idx == arg_count) { + // + // Append an array argument with all params arguments + // + if (params_initializers != null) { + arguments.Add (new Argument ( + new ArrayCreation (new TypeExpression (pt, loc), "[]", + params_initializers, loc).Resolve (ec))); + } + return true; + } - return null; -#else - throw new NotImplementedException (); -#endif + if (!may_fail && Report.Errors == errors) { + if (CustomErrorHandler != null) + CustomErrorHandler.NoExactMatch (ec, best_candidate); + else + Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt); + } + return false; + } + } + + public class ConstantExpr : MemberExpr + { + FieldInfo constant; + + public ConstantExpr (FieldInfo constant, Location loc) + { + this.constant = constant; + this.loc = loc; + } + + public override string Name { + get { throw new NotImplementedException (); } + } + + public override bool IsInstance { + get { return !IsStatic; } + } + + public override bool IsStatic { + get { return constant.IsStatic; } + } + + public override Type DeclaringType { + get { return constant.DeclaringType; } + } + + public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original) + { + constant = TypeManager.GetGenericFieldDefinition (constant); + + IConstant ic = TypeManager.GetConstant (constant); + if (ic == null) { + if (constant.IsLiteral) { + ic = new ExternalConstant (constant); + } else { + ic = ExternalConstant.CreateDecimal (constant); + // HACK: decimal field was not resolved as constant + if (ic == null) + return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original); + } + TypeManager.RegisterConstant (constant, ic); + } + + return base.ResolveMemberAccess (ec, left, loc, original); + } + + public override Expression DoResolve (EmitContext ec) + { + IConstant ic = TypeManager.GetConstant (constant); + if (ic.ResolveValue ()) { + if (!ec.IsInObsoleteScope) + ic.CheckObsoleteness (loc); + } + + return ic.CreateConstantReference (loc); + } + + public override void Emit (EmitContext ec) + { + throw new NotSupportedException (); + } + + public override string GetSignatureForError () + { + return TypeManager.GetFullNameSignature (constant); } } @@ -4065,42 +4617,12 @@ namespace Mono.CSharp { } } - public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc, + public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original) { FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo); - Type t = fi.FieldType; - if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) { - IConstant ic = TypeManager.GetConstant (fi); - if (ic == null) { - if (fi.IsLiteral) { - ic = new ExternalConstant (fi); - } else { - ic = ExternalConstant.CreateDecimal (fi); - if (ic == null) { - return base.ResolveMemberAccess (ec, left, loc, original); - } - } - TypeManager.RegisterConstant (fi, ic); - } - - bool left_is_type = left is TypeExpr; - if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) { - Report.SymbolRelatedToPreviousError (FieldInfo); - error176 (loc, TypeManager.GetFullNameSignature (FieldInfo)); - return null; - } - - if (ic.ResolveValue ()) { - if (!ec.IsInObsoleteScope) - ic.CheckObsoleteness (loc); - } - - return ic.CreateConstantReference (loc); - } - if (t.IsPointer && !ec.InUnsafe) { UnsafeError (loc); } @@ -4143,10 +4665,12 @@ namespace Mono.CSharp { if (InstanceExpression == null) return null; - InstanceExpression.CheckMarshalByRefAccess (); + using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) { + InstanceExpression.CheckMarshalByRefAccess (ec); + } } - if (!in_initializer && !ec.IsFieldInitializer) { + if (!in_initializer && !ec.IsInFieldInitializer) { ObsoleteAttribute oa; FieldBase f = TypeManager.GetField (FieldInfo); if (f != null) { @@ -4179,8 +4703,7 @@ namespace Mono.CSharp { Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement"); } - if (!(InstanceExpression is LocalVariableReference) && - !(InstanceExpression is This)) { + if (InstanceExpression.eclass != ExprClass.Variable) { Report.SymbolRelatedToPreviousError (FieldInfo); Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields", TypeManager.GetFullNameSignature (FieldInfo)); @@ -4259,7 +4782,7 @@ namespace Mono.CSharp { if (FieldInfo.IsInitOnly) { // InitOnly fields can only be assigned in constructors or initializers - if (!ec.IsFieldInitializer && !ec.IsConstructor) + if (!ec.IsInFieldInitializer && !ec.IsConstructor) return Report_AssignToReadonly (right_side); if (ec.IsConstructor) { @@ -4280,7 +4803,7 @@ namespace Mono.CSharp { } if (right_side == EmptyExpression.OutAccess && - !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) { + !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) { Report.SymbolRelatedToPreviousError (DeclaringType); Report.Warning (197, 1, loc, "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class", @@ -4290,9 +4813,9 @@ namespace Mono.CSharp { return this; } - public override void CheckMarshalByRefAccess () + public override void CheckMarshalByRefAccess (EmitContext ec) { - if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) { + if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) { Report.SymbolRelatedToPreviousError (DeclaringType); Report.Warning (1690, 1, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class", GetSignatureForError ()); @@ -4377,16 +4900,19 @@ namespace Mono.CSharp { bool is_static = (fa & FieldAttributes.Static) != 0; bool is_readonly = (fa & FieldAttributes.InitOnly) != 0; ILGenerator ig = ec.ig; - prepared = prepare_for_load; if (is_readonly && !ec.IsConstructor){ Report_AssignToReadonly (source); return; } - EmitInstance (ec, prepare_for_load); + // + // String concatenation creates a new string instance + // + prepared = prepare_for_load && !(source is StringConcat); + EmitInstance (ec, prepared); - source.Emit (ec); + source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); if (!FieldInfo.IsStatic) { @@ -4473,19 +4999,6 @@ namespace Mono.CSharp { } } - // - // A FieldExpr whose address can not be taken - // - public class FieldExprNoAddress : FieldExpr, IMemoryLocation { - public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc) - { - } - - public new void AddressOf (EmitContext ec, AddressOp mode) - { - Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported"); - } - } /// /// Expression that evaluates to a Property. The Assign class @@ -4496,11 +5009,6 @@ namespace Mono.CSharp { /// public class PropertyExpr : MemberExpr, IAssignMethod { public readonly PropertyInfo PropertyInfo; - - // - // This is set externally by the `BaseAccess' class - // - public bool IsBase; MethodInfo getter, setter; bool is_static; @@ -4509,7 +5017,7 @@ namespace Mono.CSharp { LocalTemporary temp; bool prepared; - public PropertyExpr (Type containerType, PropertyInfo pi, Location l) + public PropertyExpr (Type container_type, PropertyInfo pi, Location l) { PropertyInfo = pi; eclass = ExprClass.PropertyAccess; @@ -4518,7 +5026,7 @@ namespace Mono.CSharp { type = TypeManager.TypeToCoreType (pi.PropertyType); - ResolveAccessors (containerType); + ResolveAccessors (container_type); } public override string Name { @@ -4538,7 +5046,23 @@ namespace Mono.CSharp { return is_static; } } - + + public override Expression CreateExpressionTree (EmitContext ec) + { + if (IsSingleDimensionalArrayLength ()) { + ArrayList args = new ArrayList (1); + args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec))); + return CreateExpressionFactoryCall ("ArrayLength", args); + } + + // TODO: it's waiting for PropertyExpr refactoring + //ArrayList args = new ArrayList (2); + //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec))); + //args.Add (getter expression); + //return CreateExpressionFactoryCall ("Property", args); + return base.CreateExpressionTree (ec); + } + public override Type DeclaringType { get { return PropertyInfo.DeclaringType; @@ -4589,9 +5113,9 @@ namespace Mono.CSharp { // hold the information for the accessibility of its setter/getter // // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor - void ResolveAccessors (Type containerType) + void ResolveAccessors (Type container_type) { - FindAccessors (containerType); + FindAccessors (container_type); if (getter != null) { MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter); @@ -4631,7 +5155,7 @@ namespace Mono.CSharp { if (InstanceExpression == null) return false; - InstanceExpression.CheckMarshalByRefAccess (); + InstanceExpression.CheckMarshalByRefAccess (ec); if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) && !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) && @@ -4652,7 +5176,7 @@ namespace Mono.CSharp { Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name); return; } - + StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType)); sig.Append ('.'); ParameterData iparams = TypeManager.GetParameterData (mi); @@ -4664,7 +5188,26 @@ namespace Mono.CSharp { Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly", Name, sig.ToString ()); } - + + public bool IsAccessibleFrom (Type invocation_type, bool lvalue) + { + bool dummy; + MethodInfo accessor = lvalue ? setter : getter; + if (accessor == null && lvalue) + accessor = getter; + return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy); + } + + bool IsSingleDimensionalArrayLength () + { + if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length") + return false; + + string t_name = InstanceExpression.Type.Name; + int t_name_len = t_name.Length; + return t_name_len > 2 && t_name [t_name_len - 2] == '[' && t_name [t_name_len - 3] != ']'; + } + override public Expression DoResolve (EmitContext ec) { if (resolved) @@ -4734,15 +5277,18 @@ namespace Mono.CSharp { override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { if (right_side == EmptyExpression.OutAccess) { - Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter", + if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) { + Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter", + PropertyInfo.Name); + } else { + Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter", GetSignatureForError ()); + } return null; } if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) { - Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable", - GetSignatureForError ()); - return null; + Error_CannotModifyIntermediateExpressionValue (ec); } if (setter == null){ @@ -4803,21 +5349,12 @@ namespace Mono.CSharp { // // Special case: length of single dimension array property is turned into ldlen // - if ((getter == TypeManager.system_int_array_get_length) || - (getter == TypeManager.int_array_get_length)){ - Type iet = InstanceExpression.Type; - - // - // System.Array.Length can be called, but the Type does not - // support invoking GetArrayRank, so test for that case first - // - if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) { - if (!prepared) - EmitInstance (ec, false); - ec.ig.Emit (OpCodes.Ldlen); - ec.ig.Emit (OpCodes.Conv_I4); - return; - } + if (IsSingleDimensionalArrayLength ()) { + if (!prepared) + EmitInstance (ec, false); + ec.ig.Emit (OpCodes.Ldlen); + ec.ig.Emit (OpCodes.Conv_I4); + return; } Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false); @@ -4838,10 +5375,15 @@ namespace Mono.CSharp { { Expression my_source = source; - prepared = prepare_for_load; - - if (prepared) { + if (prepare_for_load) { + if (source is StringConcat) + EmitInstance (ec, false); + else + prepared = true; + source.Emit (ec); + + prepared = true; if (leave_copy) { ec.ig.Emit (OpCodes.Dup); if (!is_static) { @@ -4855,7 +5397,7 @@ namespace Mono.CSharp { temp.Store (ec); my_source = temp; } - + ArrayList args = new ArrayList (1); args.Add (new Argument (my_source, Argument.AType.Expression)); @@ -4873,7 +5415,6 @@ namespace Mono.CSharp { /// public class EventExpr : MemberExpr { public readonly EventInfo EventInfo; - public bool IsBase; bool is_static; MethodInfo add_accessor, remove_accessor; @@ -4920,8 +5461,14 @@ namespace Mono.CSharp { return EventInfo.DeclaringType; } } + + void Error_AssignmentEventOnly () + { + Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator", + GetSignatureForError ()); + } - public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc, + public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original) { // @@ -4936,6 +5483,9 @@ namespace Mono.CSharp { if (!ec.IsInObsoleteScope) mi.CheckObsoleteness (loc); + if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment) + Error_AssignmentEventOnly (); + FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc); InstanceExpression = null; @@ -4943,6 +5493,9 @@ namespace Mono.CSharp { return ml.ResolveMemberAccess (ec, left, loc, original); } } + + if (left is This && !ec.IsInCompoundAssignment) + Error_AssignmentEventOnly (); return base.ResolveMemberAccess (ec, left, loc, original); } @@ -4975,7 +5528,7 @@ namespace Mono.CSharp { // if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null && InstanceExpression.Type != ec.ContainerType && - ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) { + TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) { Report.SymbolRelatedToPreviousError (EventInfo); ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo)); return false; @@ -4984,6 +5537,13 @@ namespace Mono.CSharp { return true; } + public bool IsAccessibleFrom (Type invocation_type) + { + bool dummy; + return IsAccessorAccessible (invocation_type, add_accessor, out dummy) && + IsAccessorAccessible (invocation_type, remove_accessor, out dummy); + } + public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { return DoResolve (ec); @@ -5007,11 +5567,8 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - if (InstanceExpression is This) - Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ()); - else - Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+ - "(except on the defining type)", Name); + Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+ + "(except on the defining type)", GetSignatureForError ()); } public override string GetSignatureForError () @@ -5121,8 +5678,8 @@ namespace Mono.CSharp { // Used for error reporting only ArrayList initializer; - public VarExpr (string name, Location loc) - : base (name, loc) + public VarExpr (Location loc) + : base ("var", loc) { } @@ -5150,12 +5707,7 @@ namespace Mono.CSharp { protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec) { - if (ec is FieldBase) { - Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration"); - return; - } - - base.Error_TypeOrNamespaceNotFound (ec); + Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration"); } public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent) @@ -5167,10 +5719,10 @@ namespace Mono.CSharp { if (initializer == null) return null; - // TODO: refactor, the error is reported too many times if (initializer.Count > 1) { Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location; Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators"); + initializer = null; return null; }