X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fexpression.cs;h=1d35cb53fec2c5cc52974b9b5b05976b2347588c;hb=bd316288ae3fa0cb6f03b367716d04d5244c5d04;hp=0d5c61e671cd7f77b6dd1667789b6fca91e3db6d;hpb=265d84316b21f3964127ea648fbbcb1b16f4c70e;p=mono.git diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs index 0d5c61e671c..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) @@ -394,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; @@ -879,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; } @@ -1161,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; @@ -1186,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; @@ -1235,7 +1231,7 @@ namespace Mono.CSharp { eclass = ExprClass.Value; Type etype = expr.Type; - if (TypeManager.IsValueType (probe_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; @@ -1272,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; @@ -1339,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; @@ -1891,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 { @@ -2023,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)){ // @@ -2175,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; } @@ -2248,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); } @@ -2271,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; @@ -2283,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; } @@ -2294,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; } @@ -2321,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); @@ -2459,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 // @@ -2718,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; @@ -2814,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 @@ -3570,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 { @@ -3614,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); @@ -3727,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) { @@ -3764,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) @@ -4056,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; @@ -4424,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 { @@ -4438,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, @@ -4856,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; @@ -5000,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); @@ -5012,11 +5166,16 @@ namespace Mono.CSharp { VerifyArgumentsCompat (ec, Arguments, arg_count, c, false, null, may_fail, loc); - break; - } - if (!may_fail) { + 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 && errors == Report.Errors) { string report_name = me.Name; if (report_name == ".ctor") report_name = me.DeclaringType.ToString (); @@ -5039,9 +5198,7 @@ namespace Mono.CSharp { return null; } - Error_WrongNumArguments ( - loc, report_name, arg_count); - return null; + Error_WrongNumArguments (loc, report_name, arg_count); } return null; @@ -5119,7 +5276,6 @@ 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 @@ -5186,13 +5342,8 @@ namespace Mono.CSharp { 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 `{0}' takes `{1}' arguments", - name, arg_count); - } + Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments", + name, arg_count); } static void Error_InvokeOnDelegate (Location loc) @@ -5397,17 +5548,16 @@ namespace Mono.CSharp { 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, "`{0}': cannot explicitly call operator or accessor", - TypeManager.CSharpSignature (method, true)); - return null; - } + if ((method.Attributes & MethodAttributes.SpecialName) != 0 && IsSpecialMethodInvocation (method)) { + return null; } if (mg.InstanceExpression != null) @@ -5417,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 +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; @@ -5773,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) @@ -5919,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; @@ -5956,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); @@ -6003,7 +6179,7 @@ namespace Mono.CSharp { return RequestedType; return this; } - + TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec); if (texpr == null) return null; @@ -6013,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)) @@ -6056,11 +6230,13 @@ namespace Mono.CSharp { } if (type.IsAbstract && type.IsSealed) { + 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){ + Report.SymbolRelatedToPreviousError (type); Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type)); return null; } @@ -6075,46 +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) { - Invocation.Error_WrongNumArguments (loc, TypeManager.CSharpName (type), - Arguments == null ? 0 : Arguments.Count); - return null; - } + return null; } return this; @@ -6577,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; } @@ -6845,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++) @@ -6855,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){ @@ -7019,8 +7181,8 @@ namespace Mono.CSharp { 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 (); @@ -7033,7 +7195,7 @@ namespace Mono.CSharp { if (!ResolveBase (ec)) return null; - if ((variable_info != null) && !variable_info.IsAssigned (ec)) { + 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; @@ -7145,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; @@ -7353,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) { @@ -7376,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) @@ -7394,14 +7639,15 @@ 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)) @@ -7411,59 +7657,8 @@ namespace Mono.CSharp { 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)){ - ErrorIsInaccesible (loc, TypeManager.CSharpName (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) + ")"); @@ -7485,14 +7680,14 @@ namespace Mono.CSharp { } if (member_lookup is TypeExpr) { - if (!(expr is TypeExpr) && - (original == null || !original.IdenticalNameAndTypeName (ec, expr, loc))) { + 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 @@ -7511,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; @@ -7523,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) @@ -7544,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); @@ -7581,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 or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?", - 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; } @@ -7633,6 +7839,11 @@ namespace Mono.CSharp { { return expr + "." + MemberName.MakeName (Identifier, args); } + + public override string GetSignatureForError () + { + return expr.GetSignatureForError () + "." + Identifier; + } } /// @@ -7743,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; @@ -7980,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); } @@ -8020,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; } @@ -8785,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;