X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fexpression.cs;h=1d35cb53fec2c5cc52974b9b5b05976b2347588c;hb=bd316288ae3fa0cb6f03b367716d04d5244c5d04;hp=8cc8dd847ed9c2e4380931f08675f8f3258ce11d;hpb=c630d478544678de40452b92be3376be9c289974;p=mono.git diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs index 8cc8dd847ed..1d35cb53fec 100644 --- a/mcs/gmcs/expression.cs +++ b/mcs/gmcs/expression.cs @@ -91,10 +91,10 @@ namespace Mono.CSharp { { public Expression Expr; - public ParenthesizedExpression (Expression expr, Location loc) + public ParenthesizedExpression (Expression expr) { this.Expr = expr; - this.loc = loc; + this.loc = expr.Location; } public override Expression DoResolve (EmitContext ec) @@ -173,10 +173,8 @@ namespace Mono.CSharp { void Error23 (Type t) { - Error ( - 23, "Operator " + OperName (Oper) + - " cannot be applied to operand of type `" + - TypeManager.CSharpName (t) + "'"); + Report.Error (23, loc, "Operator `{0}' cannot be applied to operand of type `{1}'", + OperName (Oper), TypeManager.CSharpName (t)); } /// @@ -396,28 +394,24 @@ namespace Mono.CSharp { Expression e; e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc); - if (e != null){ - type = TypeManager.int32_type; - return this; - } + if (e != null) + goto ok; e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc); - if (e != null){ - type = TypeManager.uint32_type; - return this; - } + if (e != null) + goto ok; e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc); - if (e != null){ - type = TypeManager.int64_type; - return this; - } + if (e != null) + goto ok; e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc); - if (e != null){ - type = TypeManager.uint64_type; - return this; - } + if (e != null) + goto ok; Error23 (expr_type); return null; + ok: + Expr = e; + expr_type = e.Type; } + type = expr_type; return this; @@ -432,16 +426,16 @@ namespace Mono.CSharp { } IVariable variable = Expr as IVariable; - bool is_fixed = variable != null && variable.VerifyFixed (false); + bool is_fixed = variable != null && variable.VerifyFixed (); if (!ec.InFixedInitializer && !is_fixed) { - Error (212, "You can only take the address of an unfixed expression inside " + + Error (212, "You can only take the address of unfixed expression inside " + "of a fixed statement initializer"); return null; } if (ec.InFixedInitializer && is_fixed) { - Error (213, "You can not fix an already fixed expression"); + Error (213, "You cannot use the fixed statement to take the address of an already fixed expression"); return null; } @@ -470,7 +464,7 @@ namespace Mono.CSharp { } if (!expr_type.IsPointer){ - Error (193, "The * or -> operator can only be applied to pointers"); + Error (193, "The * or -> operator must be applied to a pointer"); return null; } @@ -580,7 +574,7 @@ namespace Mono.CSharp { Expr = Expr.DoResolveLValue (ec, new EmptyExpression ()); if (Expr == null || Expr.eclass != ExprClass.Variable){ - Error (211, "Cannot take the address of non-variables"); + Error (211, "Cannot take the address of the given expression"); return null; } } @@ -752,8 +746,9 @@ namespace Mono.CSharp { } } - public bool VerifyFixed (bool is_expression) + public bool VerifyFixed () { + // A pointer-indirection is always fixed. return true; } @@ -880,7 +875,7 @@ namespace Mono.CSharp { if (expr == null) return null; } else { - expr.Error_UnexpectedKind ("variable, indexer or property access", loc); + expr.Error_UnexpectedKind (ec, "variable, indexer or property access", loc); return null; } @@ -1162,7 +1157,7 @@ namespace Mono.CSharp { // then e != null (objects) or true (value types) // e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc); - if (e != null){ + if (e != null && !(e is NullCast)){ expr = e; if (etype.IsValueType) action = Action.AlwaysTrue; @@ -1187,10 +1182,10 @@ namespace Mono.CSharp { } if (warning_always_matches) - Warning (183, "The given expression is always of the provided ('{0}') type", TypeManager.CSharpName (probe_type)); + Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type", TypeManager.CSharpName (probe_type)); else if (warning_never_matches){ if (!(probe_type.IsInterface || expr.Type.IsInterface)) - Warning (184, "The given expression is never of the provided ('{0}') type", TypeManager.CSharpName (probe_type)); + Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type)); } return this; @@ -1220,10 +1215,9 @@ namespace Mono.CSharp { static void Error_CannotConvertType (Type source, Type target, Location loc) { - Report.Error ( - 39, loc, "as operator can not convert from `" + - TypeManager.CSharpName (source) + "' to `" + - TypeManager.CSharpName (target) + "'"); + Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion", + TypeManager.CSharpName (source), + TypeManager.CSharpName (target)); } public override Expression DoResolve (EmitContext ec) @@ -1237,9 +1231,9 @@ namespace Mono.CSharp { eclass = ExprClass.Value; Type etype = expr.Type; - if (TypeManager.IsValueType (probe_type)){ - Report.Error (77, loc, "The as operator should be used with a reference type only (" + - TypeManager.CSharpName (probe_type) + " is a value type)"); + if (probe_type.IsValueType) { + Report.Error (77, loc, "The as operator must be used with a reference type (`" + + TypeManager.CSharpName (probe_type) + "' is a value type)"); return null; } @@ -1274,6 +1268,11 @@ namespace Mono.CSharp { Expression target_type; Expression expr; + public Cast (Expression cast_type, Expression expr) + : this (cast_type, expr, cast_type.Location) + { + } + public Cast (Expression cast_type, Expression expr, Location loc) { this.target_type = cast_type; @@ -1341,11 +1340,18 @@ namespace Mono.CSharp { return true; } + // TODO: move to constant /// /// Attempts to do a compile-time folding of a constant cast. /// Expression TryReduce (EmitContext ec, Type target_type) { + if (expr.Type == target_type) + return expr; + + if (TypeManager.IsEnumType (target_type) && TypeManager.EnumToUnderlying (target_type) == expr.Type) + return new EnumConstant ((Constant)expr, target_type); + Expression real_expr = expr; if (real_expr is EnumConstant) real_expr = ((EnumConstant) real_expr).Child; @@ -1815,7 +1821,7 @@ namespace Mono.CSharp { CheckObsoleteAttribute (type); if (type.IsAbstract && type.IsSealed) { - Report.Error (716, loc, "Cannot convert to static type '{0}'", TypeManager.CSharpName (type)); + Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type)); return null; } @@ -1893,12 +1899,12 @@ namespace Mono.CSharp { oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd"; } - public Binary (Operator oper, Expression left, Expression right, Location loc) + public Binary (Operator oper, Expression left, Expression right) { this.oper = oper; this.left = left; this.right = right; - this.loc = loc; + this.loc = left.Location; } public Operator Oper { @@ -2025,7 +2031,7 @@ namespace Mono.CSharp { // type, otherwise ConvertImplict() already finds the user-defined conversion for us, // so we don't explicitly check for performance reasons. // - bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv) + bool DoNumericPromotions (EmitContext ec, Type l, Type r, Expression lexpr, Expression rexpr, bool check_user_conv) { if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){ // @@ -2177,6 +2183,12 @@ namespace Mono.CSharp { left = ForceConversion (ec, left, TypeManager.int32_type); right = ForceConversion (ec, right, TypeManager.int32_type); + bool strConv = + Convert.ImplicitConversionExists (ec, lexpr, TypeManager.string_type) && + Convert.ImplicitConversionExists (ec, rexpr, TypeManager.string_type); + if (strConv && left != null && right != null) + Error_OperatorAmbiguous (loc, oper, l, r); + type = TypeManager.int32_type; } @@ -2185,10 +2197,8 @@ namespace Mono.CSharp { static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r) { - Report.Error (19, loc, - "Operator " + name + " cannot be applied to operands of type `" + - TypeManager.CSharpName (l) + "' and `" + - TypeManager.CSharpName (r) + "'"); + Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'", + name, TypeManager.CSharpName (l), TypeManager.CSharpName (r)); } void Error_OperatorCannotBeApplied () @@ -2252,10 +2262,10 @@ namespace Mono.CSharp { type = e.Type; if (type == TypeManager.int32_type || type == TypeManager.uint32_type){ - right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (31), loc); + right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (31)); right = right.DoResolve (ec); } else { - right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (63), loc); + right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (63)); right = right.DoResolve (ec); } @@ -2275,6 +2285,13 @@ namespace Mono.CSharp { t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type); } + static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type) + { + Report.Warning ((side == "left" ? 252 : 253), 2, loc, + "Possible unintended reference comparison; to get a value comparison, " + + "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type)); + } + Expression ResolveOperator (EmitContext ec) { Type l = left.Type; @@ -2287,7 +2304,7 @@ namespace Mono.CSharp { return null; } - left = new BoxedCast (left); + left = new BoxedCast (left, TypeManager.object_type); Type = TypeManager.bool_type; return this; } @@ -2298,7 +2315,7 @@ namespace Mono.CSharp { return null; } - right = new BoxedCast (right); + right = new BoxedCast (right, TypeManager.object_type); Type = TypeManager.bool_type; return this; } @@ -2325,22 +2342,21 @@ namespace Mono.CSharp { // Do not perform operator overload resolution when both sides are // built-in types // + Expression left_operators = null, right_operators = null; if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))){ // // Step 1: Perform Operator Overload location // - Expression left_expr, right_expr; - string op = oper_names [(int) oper]; MethodGroupExpr union; - left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc); + left_operators = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc); if (r != l){ - right_expr = MemberLookup ( + right_operators = MemberLookup ( ec, r, op, MemberTypes.Method, AllBindingFlags, loc); - union = Invocation.MakeUnionSet (left_expr, right_expr, loc); + union = Invocation.MakeUnionSet (left_operators, right_operators, loc); } else - union = (MethodGroupExpr) left_expr; + union = (MethodGroupExpr) left_operators; if (union != null) { ArrayList args = new ArrayList (2); @@ -2441,6 +2457,21 @@ namespace Mono.CSharp { } } + if (l.IsGenericParameter && r.IsGenericParameter) { + GenericConstraints l_gc, r_gc; + + l_gc = TypeManager.GetTypeParameterConstraints (l); + r_gc = TypeManager.GetTypeParameterConstraints (r); + + if ((l_gc == null) || (r_gc == null) || + !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) || + !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) { + Error_OperatorCannotBeApplied (); + return null; + } + + } + // // operator != (object a, object b) // operator == (object a, object b) @@ -2448,26 +2479,47 @@ namespace Mono.CSharp { // For this to be used, both arguments have to be reference-types. // Read the rationale on the spec (14.9.6) // - // Also, if at compile time we know that the classes do not inherit - // one from the other, then we catch the error there. - // if (!(l.IsValueType || r.IsValueType)){ type = TypeManager.bool_type; if (l == r) return this; - if (l.IsSubclassOf (r) || r.IsSubclassOf (l)) - return this; - // // Also, a standard conversion must exist from either one // - if (!(Convert.ImplicitStandardConversionExists (ec, left, r) || - Convert.ImplicitStandardConversionExists (ec, right, l))){ + bool left_to_right = + Convert.ImplicitStandardConversionExists (ec, left, r); + bool right_to_left = !left_to_right && + Convert.ImplicitStandardConversionExists (ec, right, l); + + if (!left_to_right && !right_to_left) { Error_OperatorCannotBeApplied (); return null; } + + if (left_to_right && left_operators != null && + RootContext.WarningLevel >= 2) { + ArrayList args = new ArrayList (2); + args.Add (new Argument (left, Argument.AType.Expression)); + args.Add (new Argument (left, Argument.AType.Expression)); + MethodBase method = Invocation.OverloadResolve ( + ec, (MethodGroupExpr) left_operators, args, true, Location.Null); + if (method != null) + Warning_UnintendedReferenceComparison (loc, "right", l); + } + + if (right_to_left && right_operators != null && + RootContext.WarningLevel >= 2) { + ArrayList args = new ArrayList (2); + args.Add (new Argument (right, Argument.AType.Expression)); + args.Add (new Argument (right, Argument.AType.Expression)); + MethodBase method = Invocation.OverloadResolve ( + ec, (MethodGroupExpr) right_operators, args, true, Location.Null); + if (method != null) + Warning_UnintendedReferenceComparison (loc, "left", r); + } + // // We are going to have to convert to an object to compare // @@ -2707,7 +2759,7 @@ namespace Mono.CSharp { // This will leave left or right set to null if there is an error // bool check_user_conv = is_user_defined (l) && is_user_defined (r); - DoNumericPromotions (ec, l, r, check_user_conv); + DoNumericPromotions (ec, l, r, left, right, check_user_conv); if (left == null || right == null){ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r); return null; @@ -2761,7 +2813,7 @@ namespace Mono.CSharp { return null; if (left.eclass == ExprClass.Type) { - Error (75, "Casting a negative value needs to have the value in parentheses."); + Error (75, "To cast a negative value, you must enclose the value in parentheses"); return null; } } else @@ -2803,18 +2855,119 @@ namespace Mono.CSharp { } if (rc != null && lc != null){ + int prev_e = Report.Errors; Expression e = ConstantFold.BinaryFold ( ec, oper, lc, rc, loc); - if (e != null) + if (e != null || Report.Errors != prev_e) return e; } if (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)) return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + // Check CS0652 warning here (before resolving operator). + if (oper == Operator.Equality || + oper == Operator.Inequality || + oper == Operator.LessThanOrEqual || + oper == Operator.LessThan || + oper == Operator.GreaterThanOrEqual || + oper == Operator.GreaterThan){ + CheckUselessComparison (left as Constant, right.Type); + CheckUselessComparison (right as Constant, left.Type); + } + return ResolveOperator (ec); } + private void CheckUselessComparison (Constant c, Type type) + { + if (c == null || !IsTypeIntegral (type) + || c is StringConstant + || c is BoolConstant + || c is CharConstant + || c is FloatConstant + || c is DoubleConstant + || c is DecimalConstant + ) + return; + + long value = 0; + + if (c is ULongConstant) { + ulong uvalue = ((ULongConstant) c).Value; + if (uvalue > long.MaxValue) { + if (type == TypeManager.byte_type || + type == TypeManager.sbyte_type || + type == TypeManager.short_type || + type == TypeManager.ushort_type || + type == TypeManager.int32_type || + type == TypeManager.uint32_type || + type == TypeManager.int64_type) + WarnUselessComparison (type); + return; + } + value = (long) uvalue; + } + else if (c is ByteConstant) + value = ((ByteConstant) c).Value; + else if (c is SByteConstant) + value = ((SByteConstant) c).Value; + else if (c is ShortConstant) + value = ((ShortConstant) c).Value; + else if (c is UShortConstant) + value = ((UShortConstant) c).Value; + else if (c is IntConstant) + value = ((IntConstant) c).Value; + else if (c is UIntConstant) + value = ((UIntConstant) c).Value; + else if (c is LongConstant) + value = ((LongConstant) c).Value; + + if (value != 0) { + if (IsValueOutOfRange (value, type)) + WarnUselessComparison (type); + return; + } + } + + private bool IsValueOutOfRange (long value, Type type) + { + if (IsTypeUnsigned (type) && value < 0) + return true; + return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) || + type == TypeManager.byte_type && value >= 0x100 || + type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) || + type == TypeManager.ushort_type && value >= 0x10000 || + type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) || + type == TypeManager.uint32_type && value >= 0x100000000; + } + + private static bool IsTypeIntegral (Type type) + { + return type == TypeManager.uint64_type || + type == TypeManager.int64_type || + type == TypeManager.uint32_type || + type == TypeManager.int32_type || + type == TypeManager.ushort_type || + type == TypeManager.short_type || + type == TypeManager.sbyte_type || + type == TypeManager.byte_type; + } + + private static bool IsTypeUnsigned (Type type) + { + return type == TypeManager.uint64_type || + type == TypeManager.uint32_type || + type == TypeManager.ushort_type || + type == TypeManager.byte_type; + } + + private void WarnUselessComparison (Type type) + { + Report.Warning (652, 2, loc, "Comparison to integral constant is useless; the constant is outside the range of type `{0}'", + TypeManager.CSharpName (type)); + } + /// /// EmitBranchable is called from Statement.EmitBoolExpression in the /// context of a conditional bool expression. This function will return @@ -3422,7 +3575,7 @@ namespace Mono.CSharp { } if (method.ReturnType != type) { - Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator ('{0}') " + + Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " + "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method)); return null; } @@ -3559,12 +3712,12 @@ namespace Mono.CSharp { public class Conditional : Expression { Expression expr, trueExpr, falseExpr; - public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l) + public Conditional (Expression expr, Expression trueExpr, Expression falseExpr) { this.expr = expr; this.trueExpr = trueExpr; this.falseExpr = falseExpr; - this.loc = l; + this.loc = expr.Location; } public Expression Expr { @@ -3603,6 +3756,11 @@ namespace Mono.CSharp { return null; } + Assign ass = expr as Assign; + if (ass != null && ass.Source is Constant) { + Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?"); + } + trueExpr = trueExpr.Resolve (ec); falseExpr = falseExpr.Resolve (ec); @@ -3640,10 +3798,8 @@ namespace Mono.CSharp { type = true_type; falseExpr = conv; } else { - Error (173, "The type of the conditional expression can " + - "not be computed because there is no implicit conversion" + - " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" + - " and `" + TypeManager.CSharpName (falseExpr.Type) + "'"); + Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'", + trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ()); return null; } } @@ -3718,6 +3874,12 @@ namespace Mono.CSharp { } } + public bool VerifyAssigned (EmitContext ec) + { + VariableInfo variable_info = local_info.VariableInfo; + return variable_info == null || variable_info.IsAssigned (ec, loc); + } + protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side) { if (local_info == null) { @@ -3736,11 +3898,10 @@ namespace Mono.CSharp { if (lvalue_right_side != null){ if (is_readonly){ if (lvalue_right_side is LocalVariableReference || lvalue_right_side == EmptyExpression.Null) - Report.Error (1657, loc, "Cannot pass '{0}' with '{1}' modifier because it is a '{2}'", - Name, lvalue_right_side == EmptyExpression.Null ? "out" : "ref", - local_info.GetReadOnlyContext ()); + Report.Error (1657, loc, "Cannot pass `{0}' as a ref or out argument because it is a `{1}'", + Name, local_info.GetReadOnlyContext ()); else - Report.Error (1656, loc, "Cannot assign to '{0}' because it is a '{1}'", + Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'", Name, local_info.GetReadOnlyContext ()); return null; } @@ -3756,7 +3917,7 @@ namespace Mono.CSharp { return e.Resolve (ec); } - if ((variable_info != null) && !variable_info.IsAssigned (ec, loc)) + if (!VerifyAssigned (ec)) return null; if (lvalue_right_side == null) @@ -3795,9 +3956,10 @@ namespace Mono.CSharp { return ret; } - public bool VerifyFixed (bool is_expression) + public bool VerifyFixed () { - return !is_expression || local_info.IsFixed; + // A local Variable is always fixed. + return true; } public override int GetHashCode() @@ -3951,9 +4113,10 @@ namespace Mono.CSharp { get { return vi; } } - public bool VerifyFixed (bool is_expression) + public bool VerifyFixed () { - return !is_expression || TypeManager.IsValueType (type); + // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param). + return mod == Parameter.Modifier.NONE; } public bool IsAssigned (EmitContext ec, Location loc) @@ -3962,7 +4125,7 @@ namespace Mono.CSharp { return true; Report.Error (269, loc, - "Use of unassigned out parameter '{0}'", name); + "Use of unassigned out parameter `{0}'", name); return false; } @@ -4000,8 +4163,8 @@ namespace Mono.CSharp { if (ec.CurrentAnonymousMethod != null){ if (is_ref){ - Report.Error (1628, Location, - "Can not reference a ref or out parameter in an anonymous method"); + Report.Error (1628, Location, "Cannot use ref or out parameter `{0}' inside an anonymous method block", + name); return; } @@ -4046,7 +4209,7 @@ namespace Mono.CSharp { { DoResolveBase (ec); - if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc)) + if (is_out && ec.DoFlowAnalysis && (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc)) return null; return this; @@ -4286,7 +4449,7 @@ namespace Mono.CSharp { void Error_LValueRequired (Location loc) { - Report.Error (1510, loc, "An lvalue is required as an argument to out or ref"); + Report.Error (1510, loc, "A ref or out argument must be an assignable variable"); } public bool Resolve (EmitContext ec, Location loc) @@ -4336,8 +4499,9 @@ namespace Mono.CSharp { if (instance.GetType () != typeof (This)){ if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){ Report.SymbolRelatedToPreviousError (fe.InstanceExpression.Type); - Report.Error (197, loc, "Cannot pass '{0}' as ref or out or take its address because it is a member of a marshal-by-reference class", - fe.Name); + 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", + fe.GetSignatureForError ()); return false; } } @@ -4350,10 +4514,8 @@ namespace Mono.CSharp { // if (Expr.eclass == ExprClass.PropertyAccess || Expr.eclass == ExprClass.IndexerAccess){ - Report.Error ( - 206, loc, - "A property or indexer can not be passed as an out or ref " + - "parameter"); + Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter", + Expr.GetSignatureForError ()); } else { Error_LValueRequired (loc); } @@ -4390,9 +4552,7 @@ namespace Mono.CSharp { if (Expr is IMemoryLocation) ((IMemoryLocation) Expr).AddressOf (ec, mode); else { - Report.Error ( - 1510, Expr.Location, - "An lvalue is required as an argument to out or ref"); + Error_LValueRequired (Expr.Location); return; } } @@ -4417,11 +4577,11 @@ namespace Mono.CSharp { // FIXME: only allow expr to be a method invocation or a // delegate invocation (7.5.5) // - public Invocation (Expression expr, ArrayList arguments, Location l) + public Invocation (Expression expr, ArrayList arguments) { this.expr = expr; Arguments = arguments; - loc = l; + loc = expr.Location; } public Expression Expr { @@ -4431,7 +4591,7 @@ namespace Mono.CSharp { } /// - /// Determines "better conversion" as specified in 7.4.2.3 + /// Determines "better conversion" as specified in 14.4.2.3 /// /// Returns : p if a->p is better, /// q if a->q is better, @@ -4641,34 +4801,18 @@ namespace Mono.CSharp { public static string FullMethodDesc (MethodBase mb) { - string ret_type = ""; + if (mb == null) + return ""; - if (mb == null) - return ""; - - if (mb is MethodInfo) - ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType); - - StringBuilder sb = new StringBuilder (ret_type); - sb.Append (" "); - sb.Append (mb.ReflectedType.ToString ()); - sb.Append ("."); - sb.Append (mb.Name); - - ParameterData pd = TypeManager.GetParameterData (mb); - - int count = pd.Count; - sb.Append (" ("); - - for (int i = count; i > 0; ) { - i--; - - sb.Append (pd.ParameterDesc (count - i - 1)); - if (i != 0) - sb.Append (", "); + StringBuilder sb; + if (mb is MethodInfo) { + sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType)); + sb.Append (" "); } - - sb.Append (")"); + else + sb = new StringBuilder (); + + sb.Append (TypeManager.CSharpSignature (mb)); return sb.ToString (); } @@ -4865,7 +5009,7 @@ namespace Mono.CSharp { if (a_mod == p_mod || (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) { if (a_mod == Parameter.Modifier.NONE) { - if (!Convert.ImplicitConversionExists (ec, + if (!TypeManager.IsEqual (a.Type, pd.ParameterType (i)) && !Convert.ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i))) return false; @@ -4933,27 +5077,27 @@ namespace Mono.CSharp { if (Arguments != null) arg_count = Arguments.Count; - if ((me.Name == "Invoke") && - TypeManager.IsDelegateType (me.DeclaringType)) { - Error_InvokeOnDelegate (loc); - return null; - } + if ((me.Name == "Invoke") && + TypeManager.IsDelegateType (me.DeclaringType)) { + Error_InvokeOnDelegate (loc); + return null; + } MethodBase[] methods = me.Methods; - // - // First we construct the set of applicable methods - // + // + // First we construct the set of applicable methods + // bool is_sorted = true; for (int i = 0; i < methods.Length; i++){ - Type decl_type = methods [i].DeclaringType; - - // - // If we have already found an applicable method - // we eliminate all base types (Section 14.5.5.1) - // - if ((applicable_type != null) && - IsAncestralType (decl_type, applicable_type)) + Type decl_type = methods [i].DeclaringType; + + // + // If we have already found an applicable method + // we eliminate all base types (Section 14.5.5.1) + // + if ((applicable_type != null) && + IsAncestralType (decl_type, applicable_type)) continue; // @@ -4978,8 +5122,8 @@ namespace Mono.CSharp { ec, me, Arguments, arg_count, ref methods [i]); if (!is_applicable && - (IsParamsMethodApplicable ( - ec, me, Arguments, arg_count, ref methods [i]))) { + (IsParamsMethodApplicable ( + ec, me, Arguments, arg_count, ref methods [i]))) { MethodBase candidate = methods [i]; if (candidate_to_form == null) candidate_to_form = new PtrHashtable (); @@ -5009,6 +5153,7 @@ namespace Mono.CSharp { // Okay so we have failed to find anything so we // return by providing info about the closest match // + int errors = Report.Errors; for (int i = 0; i < methods.Length; ++i) { MethodBase c = (MethodBase) methods [i]; ParameterData pd = TypeManager.GetParameterData (c); @@ -5020,11 +5165,17 @@ namespace Mono.CSharp { continue; VerifyArgumentsCompat (ec, Arguments, arg_count, - c, false, null, may_fail, loc); - break; + 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"); + + break; } - if (!may_fail) { + if (!may_fail && errors == Report.Errors) { string report_name = me.Name; if (report_name == ".ctor") report_name = me.DeclaringType.ToString (); @@ -5047,11 +5198,9 @@ namespace Mono.CSharp { return null; } - Error_WrongNumArguments ( - loc, report_name, arg_count); - return null; + Error_WrongNumArguments (loc, report_name, arg_count); } - + return null; } @@ -5127,12 +5276,11 @@ namespace Mono.CSharp { method_params = cand_params; } } - // // Now check that there are no ambiguities i.e the selected method // should be better than all the others // - bool ambiguous = false; + MethodBase ambiguous = null; for (int ix = 0; ix < candidate_top; ix++){ MethodBase candidate = (MethodBase) candidates [ix]; @@ -5145,13 +5293,14 @@ namespace Mono.CSharp { candidate, cand_params, loc)) { Report.SymbolRelatedToPreviousError (candidate); - ambiguous = true; + ambiguous = candidate; } } - if (ambiguous) { + if (ambiguous != null) { Report.SymbolRelatedToPreviousError (method); - Report.Error (121, loc, "Ambiguous call when selecting function due to implicit casts"); + Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'", + TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method)); return null; } @@ -5191,16 +5340,10 @@ namespace Mono.CSharp { return method; } - static void Error_WrongNumArguments (Location loc, String name, int arg_count) + public static void Error_WrongNumArguments (Location loc, String name, int arg_count) { - if (name == "Finalize" && arg_count == 0) { - Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available"); - } - else { - Report.Error (1501, loc, - "No overload for method `" + name + "' takes `" + - arg_count + "' arguments"); - } + Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments", + name, arg_count); } static void Error_InvokeOnDelegate (Location loc) @@ -5213,27 +5356,26 @@ namespace Mono.CSharp { Type delegate_type, Argument a, ParameterData expected_par) { if (delegate_type == null) - Report.Error (1502, loc, "The best overloaded match for method '{0}' has some invalid arguments", + Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments", TypeManager.CSharpSignature (method)); else - Report.Error (1594, loc, - "Delegate '" + delegate_type.ToString () + - "' has some invalid arguments."); + Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments", + TypeManager.CSharpName (delegate_type)); string par_desc = expected_par.ParameterDesc (idx); if (a.Modifier != expected_par.ParameterModifier (idx)) { if ((expected_par.ParameterModifier (idx) & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0) - Report.Error (1615, loc, "Argument '{0}' should not be passed with the '{1}' keyword", + Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword", idx + 1, Parameter.GetModifierSignature (a.Modifier)); else - Report.Error (1620, loc, "Argument '{0}' must be passed with the '{1}' keyword", + Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword", idx + 1, Parameter.GetModifierSignature (expected_par.ParameterModifier (idx))); return; } Report.Error (1503, loc, - String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'", + String.Format ("Argument {0}: Cannot convert from `{1}' to `{2}'", idx + 1, Argument.FullDesc (a), par_desc)); } @@ -5314,13 +5456,7 @@ namespace Mono.CSharp { if (a_mod != p_mod && pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) { if (!may_fail) { - Report.Error (1502, loc, - "The best overloaded match for method '" + FullMethodDesc (method)+ - "' has some invalid arguments"); - Report.Error (1503, loc, - "Argument " + (j+1) + - ": Cannot convert from '" + Argument.FullDesc (a) - + "' to '" + pd.ParameterDesc (j) + "'"); + Invocation.Error_InvalidArguments (loc, j, method, null, a, pd); } return false; @@ -5386,12 +5522,12 @@ namespace Mono.CSharp { mg.IdenticalTypeName) { mg.InstanceExpression = null; } else { - MemberExpr.error176 (loc, mi.Name); + MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi)); return null; } } else { if (iexpr == null || iexpr is EmptyExpression) { - SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name); + SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi)); return null; } } @@ -5408,21 +5544,20 @@ namespace Mono.CSharp { // Only base will allow this invocation to happen. // if (mg.IsBase && method.IsAbstract){ - Report.Error (205, loc, "Cannot call an abstract base member: " + - FullMethodDesc (method)); + Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method)); return null; } - if (method.Name == "Finalize" && Arguments == null) { - Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor"); + if (Arguments == null && method.Name == "Finalize") { + if (mg.IsBase) + Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor"); + else + Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available"); return null; } - if ((method.Attributes & MethodAttributes.SpecialName) != 0){ - if (TypeManager.LookupDeclSpace (method.DeclaringType) != null || TypeManager.IsSpecialMethod (method)) { - Report.Error (571, loc, TypeManager.CSharpSignature (method) + ": can not call operator or accessor"); - return null; - } + if ((method.Attributes & MethodAttributes.SpecialName) != 0 && IsSpecialMethodInvocation (method)) { + return null; } if (mg.InstanceExpression != null) @@ -5432,6 +5567,32 @@ namespace Mono.CSharp { return this; } + bool IsSpecialMethodInvocation (MethodBase method) + { + IMethodData md = TypeManager.GetMethod (method); + if (md != null) { + if (!(md is AbstractPropertyEventMethod) && !(md is Operator)) + return false; + } else { + if (!TypeManager.IsSpecialMethod (method)) + return false; + + int args = TypeManager.GetParameterData (method).Count; + if (method.Name.StartsWith ("get_") && args > 0) + return false; + else if (method.Name.StartsWith ("set_") && args > 2) + return false; + + // TODO: check operators and events as well ? + } + + Report.SymbolRelatedToPreviousError (method); + Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor", + TypeManager.CSharpSignature (method, true)); + + return true; + } + // // Emits the list of arguments as an array // @@ -5662,7 +5823,12 @@ namespace Mono.CSharp { return; if (!is_static){ - this_call = instance_expr == null; + if (instance_expr == EmptyExpression.Null) { + SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method)); + return; + } + + this_call = instance_expr is This; if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType)) struct_call = true; @@ -5672,7 +5838,7 @@ namespace Mono.CSharp { if (!omit_args) { Type t = null; if (this_call) { - ig.Emit (OpCodes.Ldarg_0); + ec.EmitThis (); t = decl_type; } else { Type iexpr_type = instance_expr.Type; @@ -5783,11 +5949,11 @@ namespace Mono.CSharp { Expression expr; Expression argument; - public InvocationOrCast (Expression expr, Expression argument, Location loc) + public InvocationOrCast (Expression expr, Expression argument) { this.expr = expr; this.argument = argument; - this.loc = loc; + this.loc = expr.Location; } public override Expression DoResolve (EmitContext ec) @@ -5929,7 +6095,7 @@ namespace Mono.CSharp { value_target = value; value_target_set = true; if (!(value_target is IMemoryLocation)){ - Error_UnexpectedKind ("variable", loc); + Error_UnexpectedKind (null, "variable", loc); return false; } return true; @@ -5966,7 +6132,7 @@ namespace Mono.CSharp { /// /// Converts complex core type syntax like 'new int ()' to simple constant /// - Expression Constantify (Type t) + public static Constant Constantify (Type t) { if (t == TypeManager.int32_type) return new IntConstant (0); @@ -6013,7 +6179,7 @@ namespace Mono.CSharp { return RequestedType; return this; } - + TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec); if (texpr == null) return null; @@ -6023,16 +6189,14 @@ namespace Mono.CSharp { if (c != null) return c; } - + type = texpr.Type; if (type == null) return null; CheckObsoleteAttribute (type); - bool IsDelegate = TypeManager.IsDelegateType (type); - - if (IsDelegate){ + if (TypeManager.IsDelegateType (type)) { RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec); if (RequestedType != null) if (!(RequestedType is DelegateCreation)) @@ -6066,12 +6230,14 @@ namespace Mono.CSharp { } if (type.IsAbstract && type.IsSealed) { - Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type)); + Report.SymbolRelatedToPreviousError (type); + Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type)); return null; } if (type.IsInterface || type.IsAbstract){ - Error (144, "It is not possible to create instances of interfaces or abstract classes"); + Report.SymbolRelatedToPreviousError (type); + Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type)); return null; } @@ -6085,47 +6251,31 @@ namespace Mono.CSharp { if (is_struct && Arguments == null) return this; - Expression ml; - ml = MemberLookupFinal (ec, type, type, ".ctor", - // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'. - MemberTypes.Constructor, - AllBindingFlags | BindingFlags.DeclaredOnly, loc); + Expression ml = MemberLookupFinal (ec, type, type, ".ctor", + MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc); if (ml == null) return null; - - if (! (ml is MethodGroupExpr)){ - if (!is_struct){ - ml.Error_UnexpectedKind ("method group", loc); - return null; - } + + MethodGroupExpr mg = ml as MethodGroupExpr; + + if (mg == null) { + ml.Error_UnexpectedKind (ec, "method group", loc); + return null; } - if (ml != null) { - if (Arguments != null){ - foreach (Argument a in Arguments){ - if (!a.Resolve (ec, loc)) - return null; - } + if (Arguments != null){ + foreach (Argument a in Arguments){ + if (!a.Resolve (ec, loc)) + return null; } - - method = Invocation.OverloadResolve ( - ec, (MethodGroupExpr) ml, Arguments, true, loc); - } + method = Invocation.OverloadResolve (ec, mg, Arguments, false, loc); if (method == null) { - if (almostMatchedMembers.Count != 0) { + if (almostMatchedMembers.Count != 0) MemberLookupFailed (ec, type, type, ".ctor", null, true, loc); - return null; - } - - if (!is_struct || Arguments.Count > 0) { - Error (1501, String.Format ( - "New invocation: Can not find a constructor in `{0}' for this argument list", - TypeManager.CSharpName (type))); - return null; - } + return null; } return this; @@ -6344,7 +6494,7 @@ namespace Mono.CSharp { void Error_IncorrectArrayInitializer () { - Error (178, "Incorrectly structured array initializer"); + Error (178, "Invalid rank specifier: expected `,' or `]'"); } public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims) @@ -6385,7 +6535,7 @@ namespace Mono.CSharp { return false; } if (specified_dims && (idx + 1 >= arguments.Count)){ - Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression"); + Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead"); return false; } @@ -6569,7 +6719,7 @@ namespace Mono.CSharp { array_element_type = TypeManager.GetElementType (type); if (array_element_type.IsAbstract && array_element_type.IsSealed) { - Report.Error (719, loc, "'{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type)); + Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type)); return null; } @@ -6588,7 +6738,7 @@ namespace Mono.CSharp { AllBindingFlags, loc); if (!(ml is MethodGroupExpr)) { - ml.Error_UnexpectedKind ("method group", loc); + ml.Error_UnexpectedKind (ec, "method group", loc); return null; } @@ -6856,7 +7006,7 @@ namespace Mono.CSharp { if (e is StringConstant || e is DecimalConstant || !(e is Constant) || num_automatic_initializers <= max_automatic_initializers) { Type etype = e.Type; - + ig.Emit (OpCodes.Dup); for (int idx = 0; idx < dims; idx++) @@ -6866,7 +7016,8 @@ namespace Mono.CSharp { // If we are dealing with a struct, get the // address of it, so we can store it. // - if ((dims == 1) && etype.IsValueType && + if ((dims == 1) && + TypeManager.IsValueType (etype) && (!TypeManager.IsBuiltinOrEnum (etype) || etype == TypeManager.decimal_type)) { if (e is New){ @@ -7010,12 +7161,10 @@ namespace Mono.CSharp { get { return variable_info; } } - public bool VerifyFixed (bool is_expression) + public bool VerifyFixed () { - if ((variable_info == null) || (variable_info.LocalInfo == null)) - return false; - else - return variable_info.LocalInfo.IsFixed; + // Treat 'this' as a value parameter for the purpose of fixed variable determination. + return true; } public bool ResolveBase (EmitContext ec) @@ -7028,12 +7177,12 @@ namespace Mono.CSharp { type = ec.ContainerType; if (ec.IsStatic) { - Error (26, "Keyword this not valid in static code"); + Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer"); return false; } - if ((block != null) && (block.ThisVariable != null)) - variable_info = block.ThisVariable.VariableInfo; + if (block != null && block.Toplevel.ThisVariable != null) + variable_info = block.Toplevel.ThisVariable.VariableInfo; if (ec.CurrentAnonymousMethod != null) ec.CaptureThis (); @@ -7046,16 +7195,14 @@ namespace Mono.CSharp { if (!ResolveBase (ec)) return null; - if ((variable_info != null) && !variable_info.IsAssigned (ec)) { - Error (188, "The this object cannot be used before all " + - "of its fields are assigned to"); + if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) && !variable_info.IsAssigned (ec)) { + Error (188, "The `this' object cannot be used before all of its fields are assigned to"); variable_info.SetAssigned (ec); return this; } if (ec.IsFieldInitializer) { - Error (27, "Keyword `this' can't be used outside a constructor, " + - "a method or a property."); + Error (27, "Keyword `this' is not available in the current context"); return null; } @@ -7160,7 +7307,7 @@ namespace Mono.CSharp { if (!ResolveBase (ec)) return null; - if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) { + if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) { Error (190, "The __arglist construct is valid only within " + "a variable argument method."); return null; @@ -7262,8 +7409,7 @@ namespace Mono.CSharp { typearg = texpr.Type; if (typearg == TypeManager.void_type) { - Error (673, "System.Void cannot be used from C# - " + - "use typeof (void) to get the void type object"); + Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object"); return null; } @@ -7342,15 +7488,14 @@ namespace Mono.CSharp { } if (!ec.InUnsafe) { - Report.Error (233, loc, "'{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)", + Report.Error (233, loc, "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)", TypeManager.CSharpName (type_queried)); return null; } CheckObsoleteAttribute (type_queried); - if (!TypeManager.IsUnmanagedType (type_queried)){ - Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")"); + if (!TypeManager.VerifyUnManaged (type_queried, loc)){ return null; } @@ -7370,13 +7515,96 @@ namespace Mono.CSharp { } } + /// + /// Implements the qualified-alias-member (::) expression. + /// + public class QualifiedAliasMember : Expression + { + string alias, identifier; + + public QualifiedAliasMember (string alias, string identifier, Location l) + { + this.alias = alias; + this.identifier = identifier; + loc = l; + } + + public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent) + { + if (alias == "global") + return new MemberAccess (Namespace.Root, identifier, loc).ResolveAsTypeStep (ec, silent); + + int errors = Report.Errors; + FullNamedExpression fne = ec.DeclSpace.NamespaceEntry.LookupAlias (alias); + if (fne == null) { + if (errors == Report.Errors) + Report.Error (432, loc, "Alias `{0}' not found", alias); + return null; + } + if (fne.eclass != ExprClass.Namespace) { + if (!silent) + Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias); + return null; + } + return new MemberAccess (fne, identifier, loc).ResolveAsTypeStep (ec, silent); + } + + public override Expression DoResolve (EmitContext ec) + { + FullNamedExpression fne; + if (alias == "global") { + fne = Namespace.Root; + } else { + int errors = Report.Errors; + fne = ec.DeclSpace.NamespaceEntry.LookupAlias (alias); + if (fne == null) { + if (errors == Report.Errors) + Report.Error (432, loc, "Alias `{0}' not found", alias); + return null; + } + } + + Expression retval = new MemberAccess (fne, identifier, loc).DoResolve (ec); + if (retval == null) + return null; + + if (!(retval is FullNamedExpression)) { + Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier); + return null; + } + + // We defer this check till the end to match the behaviour of CSC + if (fne.eclass != ExprClass.Namespace) { + Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias); + return null; + } + return retval; + } + + public override void Emit (EmitContext ec) + { + throw new InternalErrorException ("QualifiedAliasMember found in resolved tree"); + } + + + public override string ToString () + { + return alias + "::" + identifier; + } + + public override string GetSignatureForError () + { + return ToString (); + } + } + /// /// Implements the member access expression /// public class MemberAccess : Expression { - public string Identifier; - protected Expression expr; - protected TypeArguments args; + public readonly string Identifier; // TODO: LocatedToken + Expression expr; + TypeArguments args; public MemberAccess (Expression expr, string id, Location l) { @@ -7393,11 +7621,11 @@ namespace Mono.CSharp { } public Expression Expr { - get { - return expr; - } + get { return expr; } } + // TODO: this method has very poor performace for Enum fields and + // probably for other constants as well Expression DoResolve (EmitContext ec, Expression right_side) { if (type != null) @@ -7411,75 +7639,26 @@ namespace Mono.CSharp { // SimpleName original = expr as SimpleName; - expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type | - ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis); + Expression new_expr = expr.Resolve (ec, + ResolveFlags.VariableOrValue | ResolveFlags.Type | + ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis); - if (expr == null) + if (new_expr == null) return null; - if (expr is Namespace) { - Namespace ns = (Namespace) expr; + if (new_expr is Namespace) { + Namespace ns = (Namespace) new_expr; string lookup_id = MemberName.MakeName (Identifier, args); FullNamedExpression retval = ns.Lookup (ec.DeclSpace, lookup_id, loc); if ((retval != null) && (args != null)) retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec); if (retval == null) - Report.Error (234, loc, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier, ns.FullName); + Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?", + Identifier, ns.FullName); return retval; } - - // - // TODO: I mailed Ravi about this, and apparently we can get rid - // of this and put it in the right place. - // - // Handle enums here when they are in transit. - // Note that we cannot afford to hit MemberLookup in this case because - // it will fail to find any members at all - // - Type expr_type; - if (expr is TypeExpr){ - expr_type = expr.Type; - - if (!ec.DeclSpace.CheckAccessLevel (expr_type)){ - Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", expr_type); - return null; - } - - if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){ - Enum en = TypeManager.LookupEnum (expr_type); - - if (en != null) { - object value = en.LookupEnumValue (Identifier, loc); - - if (value != null){ - MemberCore mc = en.GetDefinition (Identifier); - ObsoleteAttribute oa = mc.GetObsoleteAttribute (en); - if (oa != null) { - AttributeTester.Report_ObsoleteMessage (oa, mc.GetSignatureForError (), Location); - } - oa = en.GetObsoleteAttribute (en); - if (oa != null) { - AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location); - } - - Constant c = Constantify (value, en.UnderlyingType); - return new EnumConstant (c, expr_type); - } - } else { - CheckObsoleteAttribute (expr_type); - - FieldInfo fi = expr_type.GetField (Identifier); - if (fi != null) { - ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi); - if (oa != null) - AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location); - } - } - } - } else - expr_type = expr.Type; - + Type expr_type = new_expr.Type; if (expr_type.IsPointer){ Error (23, "The `.' operator can not be applied to pointer operands (" + TypeManager.CSharpName (expr_type) + ")"); @@ -7501,14 +7680,14 @@ namespace Mono.CSharp { } if (member_lookup is TypeExpr) { - if (!(expr is TypeExpr) && - (original == null || !original.IdenticalNameAndTypeName (ec, expr, loc))) { - Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" + - member_lookup.Type + "' instead"); + if (!(new_expr is TypeExpr) && + (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) { + Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead", + Identifier, member_lookup.GetSignatureForError ()); return null; } - ConstructedType ct = expr as ConstructedType; + ConstructedType ct = new_expr as ConstructedType; if (ct != null) { // // When looking up a nested type in a generic instance @@ -7527,7 +7706,7 @@ namespace Mono.CSharp { } MemberExpr me = (MemberExpr) member_lookup; - member_lookup = me.ResolveMemberAccess (ec, expr, loc, original); + member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original); if (member_lookup == null) return null; @@ -7539,15 +7718,22 @@ namespace Mono.CSharp { return mg.ResolveGeneric (ec, args); } + if (original != null && !TypeManager.IsValueType (expr_type)) { + me = member_lookup as MemberExpr; + if (me != null && me.IsInstance) { + LocalVariableReference var = new_expr as LocalVariableReference; + if (var != null && !var.VerifyAssigned (ec)) + return null; + } + } + // The following DoResolve/DoResolveLValue will do the definite assignment // check. if (right_side != null) - member_lookup = member_lookup.DoResolveLValue (ec, right_side); + return member_lookup.DoResolveLValue (ec, right_side); else - member_lookup = member_lookup.DoResolve (ec); - - return member_lookup; + return member_lookup.DoResolve (ec); } public override Expression DoResolve (EmitContext ec) @@ -7560,17 +7746,19 @@ namespace Mono.CSharp { return DoResolve (ec, right_side); } - public override FullNamedExpression ResolveAsTypeStep (EmitContext ec) + public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent) { - return ResolveNamespaceOrType (ec, false); + return ResolveNamespaceOrType (ec, silent); } public FullNamedExpression ResolveNamespaceOrType (EmitContext ec, bool silent) { - FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec); + FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec, silent); - if (new_expr == null) + if (new_expr == null) { + Report.Error (234, "No such name or typespace {0}", expr); return null; + } string lookup_id = MemberName.MakeName (Identifier, args); @@ -7580,7 +7768,8 @@ namespace Mono.CSharp { if ((retval != null) && (args != null)) retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec); if (!silent && retval == null) - Report.Error (234, loc, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier, ns.FullName); + Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?", + Identifier, ns.FullName); return retval; } @@ -7596,20 +7785,22 @@ namespace Mono.CSharp { return null; } - Expression member_lookup = MemberLookup (ec, expr_type, expr_type, lookup_id, loc); + Expression member_lookup = MemberLookup ( + ec, ec.ContainerType, expr_type, expr_type, lookup_id, + MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc); if (member_lookup == null) { int errors = Report.Errors; MemberLookupFailed (ec, expr_type, expr_type, lookup_id, null, false, loc); - if (!silent && errors == Report.Errors) - Report.Error (234, loc, "The type name `{0}' could not be found in type `{1}'", - lookup_id, new_expr.FullName); + if (!silent && errors == Report.Errors) { + Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'", + Identifier, new_expr.GetSignatureForError ()); + } return null; } if (!(member_lookup is TypeExpr)) { - Report.Error (118, loc, "'{0}.{1}' denotes a '{2}', where a type was expected", - new_expr.FullName, lookup_id, member_lookup.ExprClassName ()); + new_expr.Error_UnexpectedKind (ec, "type", loc); return null; } @@ -7648,6 +7839,11 @@ namespace Mono.CSharp { { return expr + "." + MemberName.MakeName (Identifier, args); } + + public override string GetSignatureForError () + { + return expr.GetSignatureForError () + "." + Identifier; + } } /// @@ -7758,11 +7954,11 @@ namespace Mono.CSharp { public ArrayList Arguments; public Expression Expr; - public ElementAccess (Expression e, ArrayList e_list, Location l) + public ElementAccess (Expression e, ArrayList e_list) { Expr = e; - loc = l; + loc = e.Location; if (e_list == null) return; @@ -7794,11 +7990,11 @@ namespace Mono.CSharp { Expression MakePointerAccess (EmitContext ec, Type t) { if (t == TypeManager.void_ptr_type){ - Error (242, "The array index operation is not valid for void pointers"); + Error (242, "The array index operation is not valid on void pointers"); return null; } if (Arguments.Count != 1){ - Error (196, "A pointer must be indexed by a single value"); + Error (196, "A pointer must be indexed by only one value"); return null; } Expression p; @@ -7823,7 +8019,7 @@ namespace Mono.CSharp { Type t = Expr.Type; if (t == TypeManager.array_type){ - Report.Error (21, loc, "Cannot use indexer on System.Array"); + Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'"); return null; } @@ -7860,7 +8056,7 @@ namespace Mono.CSharp { if (ff != null) { if (!(fe.InstanceExpression is LocalVariableReference) && !(fe.InstanceExpression is This)) { - Error (1708, "Fixed buffers can only be accessed through locals or fields"); + Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields"); return null; } // TODO: not sure whether it is correct @@ -7919,10 +8115,8 @@ namespace Mono.CSharp { Type t = ea.Expr.Type; if (t.GetArrayRank () != ea.Arguments.Count){ - ea.Error (22, - "Incorrect number of indexes for array " + - " expected: " + t.GetArrayRank () + " got: " + - ea.Arguments.Count); + Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'", + ea.Arguments.Count, t.GetArrayRank ()); return null; } @@ -7941,7 +8135,7 @@ namespace Mono.CSharp { argtype == TypeManager.uint64_type) { Constant c = a.Expr as Constant; if (c != null && c.IsNegative) { - Report.Warning (251, 2, a.Expr.Location, "Indexing an array with a negative index (array indices always start at zero)"); + Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)"); } continue; } @@ -7997,6 +8191,8 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldobj, type); } else if (type.IsGenericParameter) ig.Emit (OpCodes.Ldelem_Any, type); + else if (type.IsPointer) + ig.Emit (OpCodes.Ldelem_I); else ig.Emit (OpCodes.Ldelem_Ref); } @@ -8037,7 +8233,9 @@ namespace Mono.CSharp { } else if (t.IsGenericParameter) { has_type_arg = true; return OpCodes.Stelem_Any; - } else + } else if (t.IsPointer) + return OpCodes.Stelem_I; + else return OpCodes.Stelem_Ref; } @@ -8257,16 +8455,17 @@ namespace Mono.CSharp { } class Indexers { - public ArrayList Properties; - static Hashtable map; + // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again. + public readonly ArrayList Properties; + static Indexers empty; public struct Indexer { - public readonly Type Type; + public readonly PropertyInfo PropertyInfo; public readonly MethodInfo Getter, Setter; - public Indexer (Type type, MethodInfo get, MethodInfo set) + public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set) { - this.Type = type; + this.PropertyInfo = property_info; this.Getter = get; this.Setter = set; } @@ -8274,22 +8473,33 @@ namespace Mono.CSharp { static Indexers () { - map = new Hashtable (); + empty = new Indexers (null); } - Indexers () + Indexers (ArrayList array) { - Properties = new ArrayList (); + Properties = array; } - - void Append (MemberInfo [] mi) + + static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi) { + bool dummy; + if (mi == null) + return; foreach (PropertyInfo property in mi){ MethodInfo get, set; get = property.GetGetMethod (true); set = property.GetSetMethod (true); - Properties.Add (new Indexer (property.PropertyType, get, set)); + if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy)) + get = null; + if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy)) + set = null; + if (get != null || set != null) { + if (ix == empty) + ix = new Indexers (new ArrayList ()); + ix.Properties.Add (new Indexer (property, get, set)); + } } } @@ -8297,51 +8507,27 @@ namespace Mono.CSharp { { string p_name = TypeManager.IndexerPropertyName (lookup_type); - MemberInfo [] mi = TypeManager.MemberLookup ( + return TypeManager.MemberLookup ( caller_type, caller_type, lookup_type, MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, p_name, null); - - if (mi == null || mi.Length == 0) - return null; - - return mi; } static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) { - Indexers ix = (Indexers) map [lookup_type]; - - if (ix != null) - return ix; + Indexers ix = empty; Type copy = lookup_type; while (copy != TypeManager.object_type && copy != null){ - MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy); - - if (mi != null){ - if (ix == null) - ix = new Indexers (); - - ix.Append (mi); - } - + Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy)); copy = copy.BaseType; } - if (!lookup_type.IsInterface) - return ix; - - Type [] ifaces = TypeManager.GetInterfaces (lookup_type); - if (ifaces != null) { - foreach (Type itype in ifaces) { - MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype); - if (mi != null){ - if (ix == null) - ix = new Indexers (); - - ix.Append (mi); - } + if (lookup_type.IsInterface) { + Type [] ifaces = TypeManager.GetInterfaces (lookup_type); + if (ifaces != null) { + foreach (Type itype in ifaces) + Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype)); } } @@ -8403,15 +8589,12 @@ namespace Mono.CSharp { bool found_any = false, found_any_getters = false; Type lookup_type = indexer_type; - Indexers ilist; - ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc); - if (ilist != null) { + Indexers ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc); + if (ilist.Properties != null) { found_any = true; - if (ilist.Properties != null) { - foreach (Indexers.Indexer ix in ilist.Properties) { - if (ix.Getter != null) - AllGetters.Add(ix.Getter); - } + foreach (Indexers.Indexer ix in ilist.Properties) { + if (ix.Getter != null) + AllGetters.Add (ix.Getter); } } @@ -8423,21 +8606,19 @@ namespace Mono.CSharp { } if (!found_any) { - Report.Error (21, loc, - "Type `" + TypeManager.CSharpName (indexer_type) + - "' does not have any indexers defined"); + Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'", + TypeManager.CSharpName (indexer_type)); return null; } if (!found_any_getters) { - Error (154, "indexer can not be used in this context, because " + - "it lacks a `get' accessor"); + Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor", + "XXXXXXXX"); return null; } if (get == null) { - Error (1501, "No Overload for method `this' takes `" + - arguments.Count + "' arguments"); + Invocation.Error_WrongNumArguments (loc, "this", arguments.Count); return null; } @@ -8445,7 +8626,7 @@ namespace Mono.CSharp { // Only base will allow this invocation to happen. // if (get.IsAbstract && this is BaseIndexerAccess){ - Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get)); + Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get)); return null; } @@ -8470,13 +8651,11 @@ namespace Mono.CSharp { bool found_any = false, found_any_setters = false; Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc); - if (ilist != null) { + if (ilist.Properties != null) { found_any = true; - if (ilist.Properties != null) { - foreach (Indexers.Indexer ix in ilist.Properties) { - if (ix.Setter != null) - AllSetters.Add(ix.Setter); - } + foreach (Indexers.Indexer ix in ilist.Properties) { + if (ix.Setter != null) + AllSetters.Add (ix.Setter); } } if (AllSetters.Count > 0) { @@ -8489,9 +8668,8 @@ namespace Mono.CSharp { } if (!found_any) { - Report.Error (21, loc, - "Type `" + TypeManager.CSharpName (indexer_type) + - "' does not have any indexers defined"); + Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'", + TypeManager.CSharpName (indexer_type)); return null; } @@ -8502,8 +8680,7 @@ namespace Mono.CSharp { } if (set == null) { - Error (1501, "No Overload for method `this' takes `" + - arguments.Count + "' arguments"); + Invocation.Error_WrongNumArguments (loc, "this", arguments.Count); return null; } @@ -8511,7 +8688,7 @@ namespace Mono.CSharp { // Only base will allow this invocation to happen. // if (set.IsAbstract && this is BaseIndexerAccess){ - Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set)); + Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set)); return null; } @@ -8521,11 +8698,11 @@ namespace Mono.CSharp { type = TypeManager.void_type; // default value foreach (Indexers.Indexer ix in ilist.Properties){ if (ix.Setter == set){ - type = ix.Type; + type = ix.PropertyInfo.PropertyType; break; } } - + instance_expr.CheckMarshallByRefAccess (ec.ContainerType); eclass = ExprClass.IndexerAccess; @@ -8632,12 +8809,12 @@ namespace Mono.CSharp { Type base_type = current_type.BaseType; if (ec.IsStatic){ - Error (1511, "Keyword base is not allowed in static method"); + Error (1511, "Keyword `base' is not available in a static method"); return null; } if (ec.IsFieldInitializer){ - Error (1512, "Keyword base is not available in the current context"); + Error (1512, "Keyword `base' is not available in the current context"); return null; } @@ -8823,6 +9000,11 @@ namespace Mono.CSharp { Expression left; string dim; + public ComposedCast (Expression left, string dim) + : this (left, dim, left.Location) + { + } + public ComposedCast (Expression left, string dim, Location l) { this.left = left; @@ -8862,8 +9044,7 @@ namespace Mono.CSharp { return nullable.ResolveAsTypeTerminal (ec); } - if (dim == "*" && !TypeManager.IsUnmanagedType (ltype)) { - Report.Error (208, loc, "Cannot declare a pointer to a managed type ('{0}')", ltype); + if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc)) { return null; } @@ -8883,7 +9064,7 @@ namespace Mono.CSharp { if (type.IsArray && (type.GetElementType () == TypeManager.arg_iterator_type || type.GetElementType () == TypeManager.typed_reference_type)) { - Report.Error (611, loc, "Array elements cannot be of type '{0}'", TypeManager.CSharpName (type.GetElementType ())); + Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (type.GetElementType ())); return null; } @@ -9022,8 +9203,7 @@ namespace Mono.CSharp { } if (ec.InCatch || ec.InFinally) { - Error (255, - "stackalloc can not be used in a catch or finally block"); + Error (255, "Cannot use stackalloc in finally or catch"); return null; }