X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fexpression.cs;h=dad971332431f25d5370495b330041392c1775b0;hb=4a9ecda075e6914d55f4621a87073299b3baa1e3;hp=77566cb60f4549e85a33d591b99dc8bca6fe4844;hpb=ea6c3bb0c2fda5a633b0e21abad9b29683579264;p=mono.git diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs index 77566cb60f4..dad97133243 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) @@ -107,6 +107,13 @@ namespace Mono.CSharp { { throw new Exception ("Should not happen"); } + + public override Location Location + { + get { + return Expr.Location; + } + } } /// @@ -173,10 +180,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)); } /// @@ -190,37 +195,37 @@ namespace Mono.CSharp { Expression e = null; if (expr is IntConstant) - e = new IntConstant (-((IntConstant) expr).Value); + e = new IntConstant (-((IntConstant) expr).Value, expr.Location); else if (expr is UIntConstant){ uint value = ((UIntConstant) expr).Value; if (value < 2147483649) - return new IntConstant (-(int)value); + return new IntConstant (-(int)value, expr.Location); else - e = new LongConstant (-value); + e = new LongConstant (-value, expr.Location); } else if (expr is LongConstant) - e = new LongConstant (-((LongConstant) expr).Value); + e = new LongConstant (-((LongConstant) expr).Value, expr.Location); else if (expr is ULongConstant){ ulong value = ((ULongConstant) expr).Value; if (value < 9223372036854775809) - return new LongConstant(-(long)value); + return new LongConstant(-(long)value, expr.Location); } else if (expr is FloatConstant) - e = new FloatConstant (-((FloatConstant) expr).Value); + e = new FloatConstant (-((FloatConstant) expr).Value, expr.Location); else if (expr is DoubleConstant) - e = new DoubleConstant (-((DoubleConstant) expr).Value); + e = new DoubleConstant (-((DoubleConstant) expr).Value, expr.Location); else if (expr is DecimalConstant) - e = new DecimalConstant (-((DecimalConstant) expr).Value); + e = new DecimalConstant (-((DecimalConstant) expr).Value, expr.Location); else if (expr is ShortConstant) - e = new IntConstant (-((ShortConstant) expr).Value); + e = new IntConstant (-((ShortConstant) expr).Value, expr.Location); else if (expr is UShortConstant) - e = new IntConstant (-((UShortConstant) expr).Value); + e = new IntConstant (-((UShortConstant) expr).Value, expr.Location); else if (expr is SByteConstant) - e = new IntConstant (-((SByteConstant) expr).Value); + e = new IntConstant (-((SByteConstant) expr).Value, expr.Location); else if (expr is ByteConstant) - e = new IntConstant (-((ByteConstant) expr).Value); + e = new IntConstant (-((ByteConstant) expr).Value, expr.Location); return e; } @@ -236,6 +241,12 @@ namespace Mono.CSharp { switch (Oper){ case Operator.UnaryPlus: + if (expr_type == TypeManager.bool_type){ + result = null; + Error23 (expr_type); + return false; + } + result = e; return true; @@ -251,7 +262,7 @@ namespace Mono.CSharp { } BoolConstant b = (BoolConstant) e; - result = new BoolConstant (!(b.Value)); + result = new BoolConstant (!(b.Value), b.Location); return true; case Operator.OnesComplement: @@ -300,13 +311,13 @@ namespace Mono.CSharp { } if (expr_type == TypeManager.int32_type){ - result = new IntConstant (~ ((IntConstant) e).Value); + result = new IntConstant (~ ((IntConstant) e).Value, e.Location); } else if (expr_type == TypeManager.uint32_type){ - result = new UIntConstant (~ ((UIntConstant) e).Value); + result = new UIntConstant (~ ((UIntConstant) e).Value, e.Location); } else if (expr_type == TypeManager.int64_type){ - result = new LongConstant (~ ((LongConstant) e).Value); + result = new LongConstant (~ ((LongConstant) e).Value, e.Location); } else if (expr_type == TypeManager.uint64_type){ - result = new ULongConstant (~ ((ULongConstant) e).Value); + result = new ULongConstant (~ ((ULongConstant) e).Value, e.Location); } else { result = null; Error23 (expr_type); @@ -390,28 +401,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; @@ -426,16 +433,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; } @@ -464,7 +471,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; } @@ -574,7 +581,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; } } @@ -674,10 +681,6 @@ namespace Mono.CSharp { eclass = ExprClass.Variable; loc = l; } - - void LoadExprValue (EmitContext ec) - { - } public override void Emit (EmitContext ec) { @@ -750,8 +753,9 @@ namespace Mono.CSharp { } } - public bool VerifyFixed (bool is_expression) + public bool VerifyFixed () { + // A pointer-indirection is always fixed. return true; } @@ -810,14 +814,6 @@ namespace Mono.CSharp { "++" : "--"; } - void Error23 (Type t) - { - Error ( - 23, "Operator " + OperName (mode) + - " cannot be applied to operand of type `" + - TypeManager.CSharpName (t) + "'"); - } - /// /// Returns whether an object of type `t' can be incremented /// or decremented with add/sub (ie, basically whether we can @@ -882,11 +878,11 @@ namespace Mono.CSharp { return null; } } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){ - expr = expr.ResolveLValue (ec, this); + expr = expr.ResolveLValue (ec, this, Location); 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; } @@ -1038,7 +1034,7 @@ namespace Mono.CSharp { public abstract class Probe : Expression { public Expression ProbeType; protected Expression expr; - protected Type probe_type; + protected TypeExpr probe_type_expr; public Probe (Expression expr, Expression probe_type, Location l) { @@ -1055,12 +1051,11 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - TypeExpr texpr = ProbeType.ResolveAsTypeTerminal (ec); - if (texpr == null) + probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec); + if (probe_type_expr == null) + return null; + if (probe_type_expr.ResolveType (ec) == null) return null; - probe_type = texpr.Type; - - CheckObsoleteAttribute (probe_type); expr = expr.Resolve (ec); if (expr == null) @@ -1112,7 +1107,7 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ceq); return; case Action.Probe: - ig.Emit (OpCodes.Isinst, probe_type); + ig.Emit (OpCodes.Isinst, probe_type_expr.Type); ig.Emit (OpCodes.Ldnull); ig.Emit (OpCodes.Cgt_Un); return; @@ -1142,7 +1137,7 @@ namespace Mono.CSharp { return; case Action.Probe: expr.Emit (ec); - ig.Emit (OpCodes.Isinst, probe_type); + ig.Emit (OpCodes.Isinst, probe_type_expr.Type); ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target); return; } @@ -1167,8 +1162,9 @@ namespace Mono.CSharp { // First case, if at compile time, there is an implicit conversion // then e != null (objects) or true (value types) // + Type probe_type = probe_type_expr.Type; 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; @@ -1193,10 +1189,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; @@ -1213,6 +1209,7 @@ namespace Mono.CSharp { } bool do_isinst = false; + Expression resolved_type; public override void Emit (EmitContext ec) { @@ -1221,43 +1218,68 @@ namespace Mono.CSharp { expr.Emit (ec); if (do_isinst) - ig.Emit (OpCodes.Isinst, probe_type); + ig.Emit (OpCodes.Isinst, probe_type_expr.Type); } 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) { - Expression e = base.DoResolve (ec); + if (resolved_type == null) { + resolved_type = base.DoResolve (ec); - if (e == null) - return null; + if (resolved_type == null) + return null; + } - type = probe_type; + type = probe_type_expr.Type; 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 (type.IsValueType) { + Report.Error (77, loc, "The as operator must be used with a reference type (`" + + TypeManager.CSharpName (type) + "' is a value type)"); return null; } + + // + // If the type is a type parameter, ensure + // that it is constrained by a class + // + TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr; + if (tpe != null){ + Constraints constraints = tpe.TypeParameter.Constraints; + bool error = false; + + if (constraints == null) + error = true; + else { + if (!constraints.HasClassConstraint) + if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0) + error = true; + } + if (error){ + Report.Error (413, loc, + "The as operator requires that the `{0}' type parameter be constrained by a class", + probe_type_expr); + return null; + } + } - e = Convert.ImplicitConversion (ec, expr, probe_type, loc); + Expression e = Convert.ImplicitConversion (ec, expr, type, loc); if (e != null){ expr = e; do_isinst = false; return this; } - if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){ + if (Convert.ExplicitReferenceConversionExists (etype, type)){ if (etype.IsGenericParameter) expr = new BoxedCast (expr, etype); @@ -1265,7 +1287,7 @@ namespace Mono.CSharp { return this; } - Error_CannotConvertType (etype, probe_type, loc); + Error_CannotConvertType (etype, type, loc); return null; } } @@ -1280,6 +1302,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; @@ -1301,496 +1328,6 @@ namespace Mono.CSharp { expr = value; } } - - bool CheckRange (EmitContext ec, long value, Type type, long min, long max) - { - if (!ec.ConstantCheckState) - return true; - - if ((value < min) || (value > max)) { - Error (221, "Constant value `" + value + "' cannot be converted " + - "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " + - "syntax to override)"); - return false; - } - - return true; - } - - bool CheckRange (EmitContext ec, ulong value, Type type, ulong max) - { - if (!ec.ConstantCheckState) - return true; - - if (value > max) { - Error (221, "Constant value `" + value + "' cannot be converted " + - "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " + - "syntax to override)"); - return false; - } - - return true; - } - - bool CheckUnsigned (EmitContext ec, long value, Type type) - { - if (!ec.ConstantCheckState) - return true; - - if (value < 0) { - Error (221, "Constant value `" + value + "' cannot be converted " + - "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " + - "syntax to override)"); - return false; - } - - return true; - } - - /// - /// Attempts to do a compile-time folding of a constant cast. - /// - Expression TryReduce (EmitContext ec, Type target_type) - { - Expression real_expr = expr; - if (real_expr is EnumConstant) - real_expr = ((EnumConstant) real_expr).Child; - - if (real_expr is ByteConstant){ - byte v = ((ByteConstant) real_expr).Value; - - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.short_type) - return new ShortConstant ((short) v); - if (target_type == TypeManager.ushort_type) - return new UShortConstant ((ushort) v); - if (target_type == TypeManager.int32_type) - return new IntConstant ((int) v); - if (target_type == TypeManager.uint32_type) - return new UIntConstant ((uint) v); - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) - return new ULongConstant ((ulong) v); - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) - return new CharConstant ((char) v); - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is SByteConstant){ - sbyte v = ((SByteConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.short_type) - return new ShortConstant ((short) v); - if (target_type == TypeManager.ushort_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new UShortConstant ((ushort) v); - } if (target_type == TypeManager.int32_type) - return new IntConstant ((int) v); - if (target_type == TypeManager.uint32_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new UIntConstant ((uint) v); - } if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new ULongConstant ((ulong) v); - } - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is ShortConstant){ - short v = ((ShortConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.ushort_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new UShortConstant ((ushort) v); - } - if (target_type == TypeManager.int32_type) - return new IntConstant ((int) v); - if (target_type == TypeManager.uint32_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new UIntConstant ((uint) v); - } - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new ULongConstant ((ulong) v); - } - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is UShortConstant){ - ushort v = ((UShortConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.short_type) { - if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue)) - return null; - return new ShortConstant ((short) v); - } - if (target_type == TypeManager.int32_type) - return new IntConstant ((int) v); - if (target_type == TypeManager.uint32_type) - return new UIntConstant ((uint) v); - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) - return new ULongConstant ((ulong) v); - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is IntConstant){ - int v = ((IntConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.short_type) { - if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue)) - return null; - return new ShortConstant ((short) v); - } - if (target_type == TypeManager.ushort_type) { - if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue)) - return null; - return new UShortConstant ((ushort) v); - } - if (target_type == TypeManager.uint32_type) { - if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue)) - return null; - return new UIntConstant ((uint) v); - } - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new ULongConstant ((ulong) v); - } - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is UIntConstant){ - uint v = ((UIntConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.short_type) { - if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue)) - return null; - return new ShortConstant ((short) v); - } - if (target_type == TypeManager.ushort_type) { - if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue)) - return null; - return new UShortConstant ((ushort) v); - } - if (target_type == TypeManager.int32_type) { - if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue)) - return null; - return new IntConstant ((int) v); - } - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) - return new ULongConstant ((ulong) v); - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is LongConstant){ - long v = ((LongConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.short_type) { - if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue)) - return null; - return new ShortConstant ((short) v); - } - if (target_type == TypeManager.ushort_type) { - if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue)) - return null; - return new UShortConstant ((ushort) v); - } - if (target_type == TypeManager.int32_type) { - if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue)) - return null; - return new IntConstant ((int) v); - } - if (target_type == TypeManager.uint32_type) { - if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue)) - return null; - return new UIntConstant ((uint) v); - } - if (target_type == TypeManager.uint64_type) { - if (!CheckUnsigned (ec, v, target_type)) - return null; - return new ULongConstant ((ulong) v); - } - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is ULongConstant){ - ulong v = ((ULongConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckRange (ec, v, target_type, Byte.MaxValue)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.short_type) { - if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue)) - return null; - return new ShortConstant ((short) v); - } - if (target_type == TypeManager.ushort_type) { - if (!CheckRange (ec, v, target_type, UInt16.MaxValue)) - return null; - return new UShortConstant ((ushort) v); - } - if (target_type == TypeManager.int32_type) { - if (!CheckRange (ec, v, target_type, Int32.MaxValue)) - return null; - return new IntConstant ((int) v); - } - if (target_type == TypeManager.uint32_type) { - if (!CheckRange (ec, v, target_type, UInt32.MaxValue)) - return null; - return new UIntConstant ((uint) v); - } - if (target_type == TypeManager.int64_type) { - if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue)) - return null; - return new LongConstant ((long) v); - } - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckRange (ec, v, target_type, Char.MaxValue)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is FloatConstant){ - float v = ((FloatConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) - return new ByteConstant ((byte) v); - if (target_type == TypeManager.sbyte_type) - return new SByteConstant ((sbyte) v); - if (target_type == TypeManager.short_type) - return new ShortConstant ((short) v); - if (target_type == TypeManager.ushort_type) - return new UShortConstant ((ushort) v); - if (target_type == TypeManager.int32_type) - return new IntConstant ((int) v); - if (target_type == TypeManager.uint32_type) - return new UIntConstant ((uint) v); - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) - return new ULongConstant ((ulong) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) - return new CharConstant ((char) v); - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - if (real_expr is DoubleConstant){ - double v = ((DoubleConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type){ - return new ByteConstant ((byte) v); - } if (target_type == TypeManager.sbyte_type) - return new SByteConstant ((sbyte) v); - if (target_type == TypeManager.short_type) - return new ShortConstant ((short) v); - if (target_type == TypeManager.ushort_type) - return new UShortConstant ((ushort) v); - if (target_type == TypeManager.int32_type) - return new IntConstant ((int) v); - if (target_type == TypeManager.uint32_type) - return new UIntConstant ((uint) v); - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) - return new ULongConstant ((ulong) v); - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.char_type) - return new CharConstant ((char) v); - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - - if (real_expr is CharConstant){ - char v = ((CharConstant) real_expr).Value; - - if (target_type == TypeManager.byte_type) { - if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue)) - return null; - return new ByteConstant ((byte) v); - } - if (target_type == TypeManager.sbyte_type) { - if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue)) - return null; - return new SByteConstant ((sbyte) v); - } - if (target_type == TypeManager.short_type) { - if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue)) - return null; - return new ShortConstant ((short) v); - } - if (target_type == TypeManager.int32_type) - return new IntConstant ((int) v); - if (target_type == TypeManager.uint32_type) - return new UIntConstant ((uint) v); - if (target_type == TypeManager.int64_type) - return new LongConstant ((long) v); - if (target_type == TypeManager.uint64_type) - return new ULongConstant ((ulong) v); - if (target_type == TypeManager.float_type) - return new FloatConstant ((float) v); - if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) v); - if (target_type == TypeManager.char_type) { - if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue)) - return null; - return new CharConstant ((char) v); - } - if (target_type == TypeManager.decimal_type) - return new DecimalConstant ((decimal) v); - } - - return null; - } public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { @@ -1816,22 +1353,20 @@ namespace Mono.CSharp { if (target == null) return null; - type = target.Type; - - CheckObsoleteAttribute (type); + type = target.ResolveType (ec); 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; } eclass = ExprClass.Value; - if (expr is Constant){ - Expression e = TryReduce (ec, type); - - if (e != null) - return e; + Constant c = expr as Constant; + if (c != null) { + c = c.TryReduce (ec, type, loc); + if (c != null) + return c; } if (type.IsPointer && !ec.InUnsafe) { @@ -1899,12 +1434,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 { @@ -1938,7 +1473,7 @@ namespace Mono.CSharp { /// /// Returns a stringified representation of the Operator /// - static string OperName (Operator oper) + public static string OperName (Operator oper) { switch (oper){ case Operator.Multiply: @@ -2031,7 +1566,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)){ // @@ -2074,9 +1609,9 @@ namespace Mono.CSharp { long ll = ((LongConstant) right).Value; if (ll >= 0) - right = new ULongConstant ((ulong) ll); + right = new ULongConstant ((ulong) ll, right.Location); } else { - e = Convert.ImplicitNumericConversion (ec, right, l, loc); + e = Convert.ImplicitNumericConversion (ec, right, l); if (e != null) right = e; } @@ -2091,9 +1626,9 @@ namespace Mono.CSharp { long ll = ((LongConstant) left).Value; if (ll > 0) - left = new ULongConstant ((ulong) ll); + left = new ULongConstant ((ulong) ll, right.Location); } else { - e = Convert.ImplicitNumericConversion (ec, left, r, loc); + e = Convert.ImplicitNumericConversion (ec, left, r); if (e != null) left = e; } @@ -2135,7 +1670,7 @@ namespace Mono.CSharp { int val = ic.Value; if (val >= 0){ - right = new UIntConstant ((uint) val); + right = new UIntConstant ((uint) val, ic.Location); type = l; return true; @@ -2148,7 +1683,7 @@ namespace Mono.CSharp { int val = ic.Value; if (val >= 0){ - left = new UIntConstant ((uint) val); + left = new UIntConstant ((uint) val, ic.Location); type = r; return true; } @@ -2183,6 +1718,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; } @@ -2191,15 +1732,18 @@ 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) + "'"); + Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r)); + } + + public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right) + { + Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'", + name, left, right); } void Error_OperatorCannotBeApplied () { - Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type); + Error_OperatorCannotBeApplied (Location, OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ()); } static bool is_unsigned (Type t) @@ -2258,10 +1802,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 IntConstant (31, loc)); right = right.DoResolve (ec); } else { - right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (63), loc); + right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (63, loc)); right = right.DoResolve (ec); } @@ -2271,29 +1815,36 @@ namespace Mono.CSharp { return null; } + // + // This is used to check if a test 'x == null' can be optimized to a reference equals, + // i.e., not invoke op_Equality. + // + static bool EqualsNullIsReferenceEquals (Type t) + { + return t == TypeManager.object_type || t == TypeManager.string_type || + 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; Type r = right.Type; - // - // Special cases: string or type parameter comapred to null - // if (oper == Operator.Equality || oper == Operator.Inequality){ - if ((!TypeManager.IsValueType (l) && r == TypeManager.null_type) || - (!TypeManager.IsValueType (r) && l == TypeManager.null_type)) { - Type = TypeManager.bool_type; - - return this; - } - if (l.IsGenericParameter && (right is NullLiteral)) { if (l.BaseType == TypeManager.value_type) { Error_OperatorCannotBeApplied (); return null; } - left = new BoxedCast (left); + left = new BoxedCast (left, TypeManager.object_type); Type = TypeManager.bool_type; return this; } @@ -2304,11 +1855,21 @@ namespace Mono.CSharp { return null; } - right = new BoxedCast (right); + right = new BoxedCast (right, TypeManager.object_type); Type = TypeManager.bool_type; return this; } - + + // + // Optimize out call to op_Equality in a few cases. + // + if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) || + (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) { + Type = TypeManager.bool_type; + + return this; + } + // IntPtr equality if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) { Type = TypeManager.bool_type; @@ -2321,22 +1882,21 @@ namespace Mono.CSharp { // Do not perform operator overload resolution when both sides are // built-in types // - if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){ + 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); @@ -2364,7 +1924,7 @@ namespace Mono.CSharp { // Simple constant folding if (left is StringConstant && right is StringConstant) - return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value); + return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location); if (l == TypeManager.string_type || r == TypeManager.string_type) { @@ -2418,13 +1978,38 @@ namespace Mono.CSharp { return this; } - bool left_is_null = left is NullLiteral; - bool right_is_null = right is NullLiteral; - if (left_is_null || right_is_null) { - if (oper == Operator.Equality) - return new BoolLiteral (left_is_null == right_is_null); - else - return new BoolLiteral (left_is_null != right_is_null); + if (l.IsPointer || r.IsPointer) { + if (l.IsPointer && r.IsPointer) { + type = TypeManager.bool_type; + return this; + } + + if (l.IsPointer && r == TypeManager.null_type) { + right = new EmptyCast (NullPointer.Null, l); + type = TypeManager.bool_type; + return this; + } + + if (r.IsPointer && l == TypeManager.null_type) { + left = new EmptyCast (NullPointer.Null, r); + type = TypeManager.bool_type; + return this; + } + } + + 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; + } + } // @@ -2434,26 +2019,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 // @@ -2634,6 +2240,10 @@ namespace Mono.CSharp { if (oper == Operator.BitwiseAnd || oper == Operator.BitwiseOr || oper == Operator.ExclusiveOr){ + if (left.Type != right.Type){ + Error_OperatorCannotBeApplied (); + return null; + } type = l; return this; } @@ -2678,8 +2288,7 @@ namespace Mono.CSharp { // Pointer comparison // if (l.IsPointer && r.IsPointer){ - if (oper == Operator.Equality || oper == Operator.Inequality || - oper == Operator.LessThan || oper == Operator.LessThanOrEqual || + if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual || oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){ type = TypeManager.bool_type; return this; @@ -2690,7 +2299,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; @@ -2735,6 +2344,43 @@ namespace Mono.CSharp { return this; } + Constant EnumLiftUp (EmitContext ec, Constant left, Constant right) + { + switch (oper) { + case Operator.BitwiseOr: + case Operator.BitwiseAnd: + case Operator.ExclusiveOr: + case Operator.Equality: + case Operator.Inequality: + case Operator.LessThan: + case Operator.LessThanOrEqual: + case Operator.GreaterThan: + case Operator.GreaterThanOrEqual: + if (left is EnumConstant) + return left; + + if (left.IsZeroInteger) + return new EnumConstant (left, right.Type); + + break; + + case Operator.Addition: + case Operator.Subtraction: + return left; + + case Operator.Multiply: + case Operator.Division: + case Operator.Modulus: + case Operator.LeftShift: + case Operator.RightShift: + if (right is EnumConstant || left is EnumConstant) + break; + return left; + } + Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type); + return null; + } + public override Expression DoResolve (EmitContext ec) { if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) { @@ -2744,7 +2390,7 @@ namespace Mono.CSharp { return null; if (left.eclass == ExprClass.Type) { - Error (75, "Casting a negative value needs to have the value in parentheses."); + Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses"); return null; } } else @@ -2767,20 +2413,153 @@ namespace Mono.CSharp { if (right == null) return null; - eclass = ExprClass.Value; + eclass = ExprClass.Value; + Constant rc = right as Constant; + + if (lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) { + left = lc = EnumLiftUp (ec, lc, rc); + if (lc == null) + return null; + + right = rc = EnumLiftUp (ec, rc, lc); + if (rc == null) + return null; + } + + if (oper == Operator.BitwiseAnd) { + if (rc != null && rc.IsZeroInteger) { + return lc is EnumConstant ? + new EnumConstant (rc, lc.Type): + rc; + } + + if (lc != null && lc.IsZeroInteger) { + return rc is EnumConstant ? + new EnumConstant (lc, rc.Type): + lc; + } + } + else if (oper == Operator.BitwiseOr) { + if (lc is EnumConstant && + rc != null && rc.IsZeroInteger) + return lc; + if (rc is EnumConstant && + lc != null && lc.IsZeroInteger) + return rc; + } + + if (rc != null && lc != null){ + int prev_e = Report.Errors; + Expression e = ConstantFold.BinaryFold ( + ec, oper, lc, rc, loc); + 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); + } - Constant rc = right as Constant; - if (rc != null & lc != null){ - Expression e = ConstantFold.BinaryFold ( - ec, oper, lc, rc, loc); - if (e != null) - return e; + 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; } + } - if (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)) - return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); + 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; + } - return ResolveOperator (ec); + 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)); } /// @@ -3196,7 +2975,7 @@ namespace Mono.CSharp { if (operand is StringConstant && operands.Count != 0) { StringConstant last_operand = operands [operands.Count - 1] as StringConstant; if (last_operand != null) { - operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value); + operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location); return; } } @@ -3353,7 +3132,7 @@ namespace Mono.CSharp { protected void Error19 () { - Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type); + Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ()); } protected void Error218 () @@ -3390,7 +3169,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; } @@ -3491,7 +3270,7 @@ namespace Mono.CSharp { Constant right_const = right as Constant; if (right_const != null && size != 0) { - Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size), right_const, loc); + Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc); if (ex == null) return; ex.Emit (ec); @@ -3527,12 +3306,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 { @@ -3571,6 +3350,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); @@ -3608,10 +3392,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; } } @@ -3686,6 +3468,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) { @@ -3703,13 +3491,18 @@ namespace Mono.CSharp { VariableInfo variable_info = local_info.VariableInfo; if (lvalue_right_side != null){ if (is_readonly){ - Error (1604, "cannot assign to `" + Name + "' because it is readonly"); + if (lvalue_right_side is LocalVariableReference || lvalue_right_side == EmptyExpression.Null) + 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}'", + Name, local_info.GetReadOnlyContext ()); return null; } - + if (variable_info != null) variable_info.SetAssigned (ec); - } + } Expression e = Block.GetConstantExpression (Name); if (e != null) { @@ -3718,7 +3511,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) @@ -3729,7 +3522,9 @@ namespace Mono.CSharp { // If we are referencing a variable from the external block // flag it for capturing // - if (local_info.Block.Toplevel != ec.CurrentBlock.Toplevel){ + if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) || + ec.CurrentAnonymousMethod.IsIterator) + { if (local_info.AddressTaken){ AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); return null; @@ -3748,16 +3543,27 @@ namespace Mono.CSharp { override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { - Expression ret = DoResolveBase (ec, right_side); - if (ret != null) - CheckObsoleteAttribute (ret.Type); + return DoResolveBase (ec, right_side); + } + + public bool VerifyFixed () + { + // A local Variable is always fixed. + return true; + } - return ret; + public override int GetHashCode() + { + return Name.GetHashCode (); } - public bool VerifyFixed (bool is_expression) + public override bool Equals (object obj) { - return !is_expression || local_info.IsFixed; + LocalVariableReference lvr = obj as LocalVariableReference; + if (lvr == null) + return false; + + return Name == lvr.Name && Block == lvr.Block; } public override void Emit (EmitContext ec) @@ -3768,7 +3574,7 @@ namespace Mono.CSharp { // // A local variable on the local CLR stack // - ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); + ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); } else { // // A local variable captured by anonymous methods. @@ -3803,10 +3609,10 @@ namespace Mono.CSharp { // if (local_info.LocalBuilder == null) throw new Exception ("This should not happen: both Field and Local are null"); - - source.Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); + + source.Emit (ec); + if (leave_copy) + ec.ig.Emit (OpCodes.Dup); ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); } else { // @@ -3889,13 +3695,18 @@ namespace Mono.CSharp { eclass = ExprClass.Variable; } + public ParameterReference (InternalParameters pars, Block block, int idx, Location loc) + : this (pars.Parameters, block, idx, pars.ParameterName (idx), loc) + { } + public VariableInfo VariableInfo { 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) @@ -3904,7 +3715,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; } @@ -3942,22 +3753,36 @@ 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; } - + // // If we are referencing the parameter from the external block // flag it for capturing // //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name)); - if (!block.IsLocalParameter (name)){ + if (!block.Toplevel.IsLocalParameter (name)){ ec.CaptureParameter (name, type, idx); } } } + public override int GetHashCode() + { + return name.GetHashCode (); + } + + public override bool Equals (object obj) + { + ParameterReference pr = obj as ParameterReference; + if (pr == null) + return false; + + return name == pr.name && block == pr.block; + } + // // Notice that for ref/out parameters, the type exposed is not the // same type exposed externally. @@ -3974,12 +3799,9 @@ 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; - if (ec.RemapToProxy) - return ec.RemapParameter (idx); - return this; } @@ -3989,9 +3811,6 @@ namespace Mono.CSharp { SetAssigned (ec); - if (ec.RemapToProxy) - return ec.RemapParameterLValue (idx, right_side); - return this; } @@ -4023,7 +3842,6 @@ namespace Mono.CSharp { if (!ec.MethodIsStatic) arg_idx++; - EmitLdArg (ig, arg_idx); // @@ -4033,11 +3851,6 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitParameter (name); - return; - } - Emit (ec, false); } @@ -4046,6 +3859,14 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; int arg_idx = idx; + if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ + if (leave_copy) + throw new InternalErrorException (); + + ec.EmitParameter (name); + return; + } + if (!ec.MethodIsStatic) arg_idx++; @@ -4175,17 +3996,19 @@ namespace Mono.CSharp { } } - public Parameter.Modifier GetParameterModifier () + public Parameter.Modifier Modifier { - switch (ArgType) { - case AType.Out: - return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF; + get { + switch (ArgType) { + case AType.Out: + return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF; - case AType.Ref: - return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF; + case AType.Ref: + return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF; - default: - return Parameter.Modifier.NONE; + default: + return Parameter.Modifier.NONE; + } } } @@ -4216,66 +4039,42 @@ 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) { + bool old_do_flow_analysis = ec.DoFlowAnalysis; + ec.DoFlowAnalysis = true; + if (ArgType == AType.Ref) { + ec.InRefOutArgumentResolving = true; Expr = Expr.Resolve (ec); - if (Expr == null) + ec.InRefOutArgumentResolving = false; + if (Expr == null) { + ec.DoFlowAnalysis = old_do_flow_analysis; return false; - - if (!ec.IsConstructor) { - FieldExpr fe = Expr as FieldExpr; - if (fe != null && fe.FieldInfo.IsInitOnly) { - if (fe.FieldInfo.IsStatic) - Report.Error (199, loc, "A static readonly field cannot be passed ref or out (except in a static constructor)"); - else - Report.Error (192, loc, "A readonly field cannot be passed ref or out (except in a constructor)"); - return false; - } } + Expr = Expr.DoResolveLValue (ec, Expr); if (Expr == null) Error_LValueRequired (loc); } else if (ArgType == AType.Out) { + ec.InRefOutArgumentResolving = true; Expr = Expr.DoResolveLValue (ec, EmptyExpression.Null); + ec.InRefOutArgumentResolving = false; + if (Expr == null) Error_LValueRequired (loc); } else Expr = Expr.Resolve (ec); + ec.DoFlowAnalysis = old_do_flow_analysis; + if (Expr == null) return false; - if (Expr is IMemberExpr) { - IMemberExpr me = Expr as IMemberExpr; - - // - // This can happen with the following code: - // - // class X {} - // class Y { - // public Y (X x) {} - // } - // class Z : Y { - // X X; - // public Z () : base (X) {} - // } - // - // SimpleNameResolve is conservative about flagging the X as - // an error since it has identical name and type. However, - // because there's no MemberAccess, that is not really justified. - // It is still simpler to fix it here, rather than in SimpleNameResolve. - // - if (me.IsInstance && me.InstanceExpression == null) { - SimpleName.Error_ObjectRefRequired (ec, loc, me.Name); - return false; - } - } - if (ArgType == AType.Expression) return true; else { @@ -4290,8 +4089,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; } } @@ -4304,10 +4104,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); } @@ -4344,9 +4142,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; } } @@ -4371,11 +4167,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 { @@ -4385,7 +4181,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, @@ -4595,34 +4391,18 @@ namespace Mono.CSharp { public static string FullMethodDesc (MethodBase mb) { - string ret_type = ""; - - 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--; + if (mb == null) + return ""; - 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 (); } @@ -4736,7 +4516,7 @@ namespace Mono.CSharp { Argument a = (Argument) arguments [i]; - Parameter.Modifier a_mod = a.GetParameterModifier () & + Parameter.Modifier a_mod = a.Modifier & (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF))); Parameter.Modifier p_mod = pd.ParameterModifier (i) & (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF))); @@ -4811,16 +4591,15 @@ namespace Mono.CSharp { Argument a = (Argument) arguments [i]; - Parameter.Modifier a_mod = a.GetParameterModifier () & + Parameter.Modifier a_mod = a.Modifier & unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); Parameter.Modifier p_mod = pd.ParameterModifier (i) & unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); - 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; @@ -4888,27 +4667,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; // @@ -4918,9 +4697,7 @@ namespace Mono.CSharp { // We avoid doing the 'applicable' test here, since it'll anyway be applied // to the base virtual function, and IsOverride is much faster than IsApplicable. // - if (!me.IsBase && - methods [i].IsVirtual && - (methods [i].Attributes & MethodAttributes.NewSlot) == 0) { + if (!me.IsBase && TypeManager.IsOverride (methods [i])) { if (candidate_overrides == null) candidate_overrides = new ArrayList (); candidate_overrides.Add (methods [i]); @@ -4935,8 +4712,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 (); @@ -4966,6 +4743,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); @@ -4977,11 +4755,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 (); @@ -5004,11 +4788,9 @@ namespace Mono.CSharp { return null; } - Error_WrongNumArguments ( - loc, report_name, arg_count); - return null; + Error_WrongNumArguments (loc, report_name, arg_count); } - + return null; } @@ -5084,12 +4866,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]; @@ -5102,13 +4883,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; } @@ -5116,10 +4898,10 @@ namespace Mono.CSharp { // If the method is a virtual function, pick an override closer to the LHS type. // if (!me.IsBase && method.IsVirtual) { - if ((method.Attributes & MethodAttributes.NewSlot) != MethodAttributes.NewSlot) + if (TypeManager.IsOverride (method)) throw new InternalErrorException ( "Should not happen. An 'override' method took part in overload resolution: " + method); - + if (candidate_overrides != null) foreach (MethodBase candidate in candidate_overrides) { if (IsOverride (candidate, method)) @@ -5137,19 +4919,21 @@ namespace Mono.CSharp { method_params, null, may_fail, loc)) return null; + if (method != null) { + MethodBase the_method = method; + if (the_method.Mono_IsInflatedMethod) + the_method = the_method.GetGenericMethodDefinition (); + IMethodData data = TypeManager.GetMethod (the_method); + if (data != null) + data.SetMemberIsUsed (); + } 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) @@ -5159,20 +4943,30 @@ namespace Mono.CSharp { } static void Error_InvalidArguments (Location loc, int idx, MethodBase method, - Type delegate_type, string arg_sig, string par_desc) + Type delegate_type, Argument a, ParameterData expected_par) { if (delegate_type == null) - Report.Error (1502, loc, - "The best overloaded match for method '" + - FullMethodDesc (method) + - "' 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", + idx + 1, Parameter.GetModifierSignature (a.Modifier)); + else + 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}'", - idx, arg_sig, par_desc)); + String.Format ("Argument {0}: Cannot convert from `{1}' to `{2}'", + idx + 1, Argument.FullDesc (a), par_desc)); } public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments, @@ -5191,11 +4985,11 @@ namespace Mono.CSharp { Parameter.Modifier pm = pd.ParameterModifier (j); if (pm == Parameter.Modifier.PARAMS){ - if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) { + if ((pm & ~Parameter.Modifier.PARAMS) != a.Modifier) { if (!may_fail) Error_InvalidArguments ( loc, j, method, delegate_type, - Argument.FullDesc (a), pd.ParameterDesc (j)); + a, pd); return false; } @@ -5207,11 +5001,11 @@ namespace Mono.CSharp { // // Check modifiers // - if (pd.ParameterModifier (j) != a.GetParameterModifier ()){ + if (pd.ParameterModifier (j) != a.Modifier){ if (!may_fail) Error_InvalidArguments ( loc, j, method, delegate_type, - Argument.FullDesc (a), pd.ParameterDesc (j)); + a, pd); return false; } } @@ -5226,9 +5020,7 @@ namespace Mono.CSharp { if (conv == null) { if (!may_fail) - Error_InvalidArguments ( - loc, j, method, delegate_type, - Argument.FullDesc (a), pd.ParameterDesc (j)); + Error_InvalidArguments (loc, j, method, delegate_type, a, pd); return false; } @@ -5246,7 +5038,7 @@ namespace Mono.CSharp { } } - Parameter.Modifier a_mod = a.GetParameterModifier () & + Parameter.Modifier a_mod = a.Modifier & unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); Parameter.Modifier p_mod = pd.ParameterModifier (j) & unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); @@ -5254,13 +5046,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; @@ -5319,17 +5105,19 @@ namespace Mono.CSharp { MethodInfo mi = method as MethodInfo; if (mi != null) { type = TypeManager.TypeToCoreType (mi.ReturnType); - if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null)) { - SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name); - return null; - } - Expression iexpr = mg.InstanceExpression; - if (mi.IsStatic && (iexpr != null) && !(iexpr is This)) { - if (mg.IdenticalTypeName) + if (mi.IsStatic) { + if (iexpr == null || + iexpr is This || iexpr is EmptyExpression || + mg.IdenticalTypeName) { mg.InstanceExpression = null; - else { - MemberAccess.error176 (loc, mi.Name); + } else { + MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi)); + return null; + } + } else { + if (iexpr == null || iexpr is EmptyExpression) { + SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi)); return null; } } @@ -5346,21 +5134,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) @@ -5370,6 +5157,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 // @@ -5420,33 +5233,12 @@ namespace Mono.CSharp { /// public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg) { - ParameterData pd; - if (mb != null) - pd = TypeManager.GetParameterData (mb); - else - pd = null; - + ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb); + int top = arguments == null ? 0 : arguments.Count; LocalTemporary [] temps = null; - if (dup_args) - temps = new LocalTemporary [arguments.Count]; - - // - // If we are calling a params method with no arguments, special case it - // - if (arguments == null){ - if (pd != null && pd.Count > 0 && - pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){ - ILGenerator ig = ec.ig; - - IntConstant.EmitInt (ig, 0); - ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0))); - } - - return; - } - - int top = arguments.Count; + if (dup_args && top != 0) + temps = new LocalTemporary [top]; for (int i = 0; i < top; i++){ Argument a = (Argument) arguments [i]; @@ -5600,7 +5392,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; @@ -5609,57 +5406,54 @@ namespace Mono.CSharp { // if (!omit_args) { Type t = null; - if (this_call) { - ig.Emit (OpCodes.Ldarg_0); - t = decl_type; - } else { - Type iexpr_type = instance_expr.Type; + Type iexpr_type = instance_expr.Type; + // + // Push the instance expression + // + if (TypeManager.IsValueType (iexpr_type)) { // - // Push the instance expression - // - if (TypeManager.IsValueType (iexpr_type)) { + // Special case: calls to a function declared in a + // reference-type with a value-type argument need + // to have their value boxed. + if (decl_type.IsValueType || + iexpr_type.IsGenericParameter) { // - // Special case: calls to a function declared in a - // reference-type with a value-type argument need - // to have their value boxed. - if (decl_type.IsValueType || - iexpr_type.IsGenericParameter) { - // - // If the expression implements IMemoryLocation, then - // we can optimize and use AddressOf on the - // return. - // - // If not we have to use some temporary storage for - // it. - if (instance_expr is IMemoryLocation) { - ((IMemoryLocation)instance_expr). - AddressOf (ec, AddressOp.LoadStore); - } else { - LocalTemporary temp = new LocalTemporary (ec, iexpr_type); - instance_expr.Emit (ec); - temp.Store (ec); - temp.AddressOf (ec, AddressOp.Load); - } - - // avoid the overhead of doing this all the time. - if (dup_args) - t = TypeManager.GetReferenceType (iexpr_type); + // If the expression implements IMemoryLocation, then + // we can optimize and use AddressOf on the + // return. + // + // If not we have to use some temporary storage for + // it. + if (instance_expr is IMemoryLocation) { + ((IMemoryLocation)instance_expr). + AddressOf (ec, AddressOp.LoadStore); } else { + LocalTemporary temp = new LocalTemporary (ec, iexpr_type); instance_expr.Emit (ec); - ig.Emit (OpCodes.Box, instance_expr.Type); - t = TypeManager.object_type; + temp.Store (ec); + temp.AddressOf (ec, AddressOp.Load); } + + // avoid the overhead of doing this all the time. + if (dup_args) + t = TypeManager.GetReferenceType (iexpr_type); } else { instance_expr.Emit (ec); - t = instance_expr.Type; + ig.Emit (OpCodes.Box, instance_expr.Type); + t = TypeManager.object_type; } + } else { + instance_expr.Emit (ec); + t = instance_expr.Type; } if (dup_args) { - this_arg = new LocalTemporary (ec, t); ig.Emit (OpCodes.Dup); - this_arg.Store (ec); + if (Arguments != null && Arguments.Count != 0) { + this_arg = new LocalTemporary (ec, t); + this_arg.Store (ec); + } } } } @@ -5721,11 +5515,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) @@ -5867,7 +5661,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; @@ -5904,34 +5698,34 @@ 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); + return new IntConstant (0, Location.Null); if (t == TypeManager.uint32_type) - return new UIntConstant (0); + return new UIntConstant (0, Location.Null); if (t == TypeManager.int64_type) - return new LongConstant (0); + return new LongConstant (0, Location.Null); if (t == TypeManager.uint64_type) - return new ULongConstant (0); + return new ULongConstant (0, Location.Null); if (t == TypeManager.float_type) - return new FloatConstant (0); + return new FloatConstant (0, Location.Null); if (t == TypeManager.double_type) - return new DoubleConstant (0); + return new DoubleConstant (0, Location.Null); if (t == TypeManager.short_type) - return new ShortConstant (0); + return new ShortConstant (0, Location.Null); if (t == TypeManager.ushort_type) - return new UShortConstant (0); + return new UShortConstant (0, Location.Null); if (t == TypeManager.sbyte_type) - return new SByteConstant (0); + return new SByteConstant (0, Location.Null); if (t == TypeManager.byte_type) - return new ByteConstant (0); + return new ByteConstant (0, Location.Null); if (t == TypeManager.char_type) - return new CharConstant ('\0'); + return new CharConstant ('\0', Location.Null); if (t == TypeManager.bool_type) - return new BoolConstant (false); + return new BoolConstant (false, Location.Null); if (t == TypeManager.decimal_type) - return new DecimalConstant (0); + return new DecimalConstant (0, Location.Null); return null; } @@ -5951,26 +5745,20 @@ namespace Mono.CSharp { return RequestedType; return this; } - + TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec); if (texpr == null) return null; + type = texpr.ResolveType (ec); + if (Arguments == null) { Expression c = Constantify (type); 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)) @@ -5979,7 +5767,9 @@ namespace Mono.CSharp { } if (type.IsGenericParameter) { - if (!TypeManager.HasConstructorConstraint (type)) { + GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type); + + if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) { Error (304, String.Format ( "Cannot create an instance of the " + "variable type '{0}' because it " + @@ -6001,13 +5791,15 @@ namespace Mono.CSharp { return this; } - if (type.IsInterface || type.IsAbstract){ - Error (144, "It is not possible to create instances of interfaces or abstract classes"); + 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.IsAbstract && type.IsSealed) { - Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type)); + 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; } @@ -6021,47 +5813,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; @@ -6280,7 +6056,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) @@ -6307,9 +6083,11 @@ namespace Mono.CSharp { } int child_bounds = -1; - foreach (object o in probe) { + for (int i = 0; i < probe.Count; ++i) { + object o = probe [i]; if (o is ArrayList) { - int current_bounds = ((ArrayList) o).Count; + ArrayList sub_probe = o as ArrayList; + int current_bounds = sub_probe.Count; if (child_bounds == -1) child_bounds = current_bounds; @@ -6319,11 +6097,11 @@ 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; } - bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims); + bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims); if (!ret) return false; } else { @@ -6334,6 +6112,7 @@ namespace Mono.CSharp { Expression tmp = (Expression) o; tmp = tmp.Resolve (ec); + probe [i] = tmp; if (tmp == null) return false; @@ -6369,7 +6148,7 @@ namespace Mono.CSharp { int i = 0; for (ArrayList probe = initializers; probe != null;) { if (probe.Count > 0 && probe [0] is ArrayList) { - Expression e = new IntConstant (probe.Count); + Expression e = new IntConstant (probe.Count, Location.Null); arguments.Add (new Argument (e, Argument.AType.Expression)); bounds [i++] = probe.Count; @@ -6377,7 +6156,7 @@ namespace Mono.CSharp { probe = (ArrayList) probe [0]; } else { - Expression e = new IntConstant (probe.Count); + Expression e = new IntConstant (probe.Count, Location.Null); arguments.Add (new Argument (e, Argument.AType.Expression)); bounds [i++] = probe.Count; @@ -6430,53 +6209,6 @@ namespace Mono.CSharp { } } - // - // Converts `source' to an int, uint, long or ulong. - // - Expression ExpressionToArrayArgument (EmitContext ec, Expression source) - { - Expression target; - - bool old_checked = ec.CheckState; - ec.CheckState = true; - - target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc); - if (target == null){ - target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc); - if (target == null){ - target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc); - if (target == null){ - target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc); - if (target == null) - Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type); - } - } - } - ec.CheckState = old_checked; - - // - // Only positive constants are allowed at compile time - // - if (target is Constant){ - if (target is IntConstant){ - if (((IntConstant) target).Value < 0){ - Expression.Error_NegativeArrayIndex (loc); - return null; - } - } - - if (target is LongConstant){ - if (((LongConstant) target).Value < 0){ - Expression.Error_NegativeArrayIndex (loc); - return null; - } - } - - } - - return target; - } - // // Creates the type of the array // @@ -6504,7 +6236,7 @@ namespace Mono.CSharp { if (array_type_expr == null) return false; - type = array_type_expr.Type; + type = array_type_expr.ResolveType (ec); if (!type.IsArray) { Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead."); @@ -6549,7 +6281,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; } @@ -6568,7 +6300,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; } @@ -6836,7 +6568,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++) @@ -6846,7 +6578,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){ @@ -6990,12 +6723,9 @@ 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; + return !TypeManager.IsValueType (Type); } public bool ResolveBase (EmitContext ec) @@ -7008,12 +6738,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 (); @@ -7026,16 +6756,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; } @@ -7089,6 +6817,20 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldobj, type); } + public override int GetHashCode() + { + return block.GetHashCode (); + } + + public override bool Equals (object obj) + { + This t = obj as This; + if (t == null) + return false; + + return block == t.block; + } + public void AddressOf (EmitContext ec, AddressOp mode) { ec.EmitThis (); @@ -7126,7 +6868,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; @@ -7225,11 +6967,10 @@ namespace Mono.CSharp { if (texpr == null) return null; - typearg = texpr.Type; + typearg = texpr.ResolveType (ec); 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; } @@ -7237,10 +6978,11 @@ namespace Mono.CSharp { UnsafeError (loc); return null; } - CheckObsoleteAttribute (typearg); type = TypeManager.type_type; - eclass = ExprClass.Type; + // Even though what is returned is a type object, it's treated as a value by the compiler. + // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'. + eclass = ExprClass.Value; return this; } @@ -7268,7 +7010,8 @@ namespace Mono.CSharp { { type = TypeManager.type_type; typearg = TypeManager.void_type; - eclass = ExprClass.Type; + // See description in TypeOf. + eclass = ExprClass.Value; return this; } } @@ -7297,23 +7040,20 @@ namespace Mono.CSharp { return null; } - type_queried = texpr.Type; + type_queried = texpr.ResolveType (ec); int size_of = GetTypeSize (type_queried); if (size_of > 0) { - return new IntConstant (size_of); + return new IntConstant (size_of, loc); } 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; } @@ -7334,256 +7074,118 @@ namespace Mono.CSharp { } /// - /// Implements the member access expression + /// Implements the qualified-alias-member (::) expression. /// - public class MemberAccess : Expression { - public string Identifier; - protected Expression expr; - protected TypeArguments args; - - public MemberAccess (Expression expr, string id, Location l) + public class QualifiedAliasMember : Expression + { + string alias, identifier; + + public QualifiedAliasMember (string alias, string identifier, Location l) { - this.expr = expr; - Identifier = id; + this.alias = alias; + this.identifier = identifier; loc = l; } - public MemberAccess (Expression expr, string id, TypeArguments args, - Location l) - : this (expr, id, l) + public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent) { - this.args = args; - } + if (alias == "global") + return new MemberAccess (Namespace.Root, identifier, loc).ResolveAsTypeStep (ec, silent); - public Expression Expr { - get { - return expr; + 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 static void error176 (Location loc, string name) - { - Report.Error (176, loc, "Static member `" + - name + "' cannot be accessed " + - "with an instance reference, qualify with a " + - "type name instead"); - } - - public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc) + public override Expression DoResolve (EmitContext ec) { - SimpleName sn = left_original as SimpleName; - return sn != null && sn.IdenticalNameAndTypeName (ec, left, loc); - } - - // TODO: possible optimalization - // Cache resolved constant result in FieldBuilder <-> expresion map - public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup, - Expression left, Location loc, - Expression left_original) - { - bool left_is_type, left_is_explicit; - - // If `left' is null, then we're called from SimpleNameResolve and this is - // a member in the currently defining class. - if (left == null) { - left_is_type = ec.IsStatic || ec.IsFieldInitializer; - left_is_explicit = false; - - // Implicitly default to `this' unless we're static. - if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext) - left = ec.GetThis (loc); + FullNamedExpression fne; + if (alias == "global") { + fne = Namespace.Root; } else { - left_is_type = left is TypeExpr; - left_is_explicit = true; - } - - if (member_lookup is FieldExpr){ - FieldExpr fe = (FieldExpr) member_lookup; - FieldInfo fi = fe.FieldInfo.Mono_GetGenericFieldDefinition (); - Type decl_type = fi.DeclaringType; - - bool is_emitted = fi is FieldBuilder; - Type t = fi.FieldType; - - if (is_emitted) { - Const c = TypeManager.LookupConstant ((FieldBuilder) fi); - - if (c != null) { - object o; - if (!c.LookupConstantValue (out o)) - return null; - - object real_value = ((Constant) c.Expr).GetValue (); - - Expression exp = Constantify (real_value, t); - - if (left_is_explicit && !left_is_type && !IdenticalNameAndTypeName (ec, left_original, left, loc)) { - Report.SymbolRelatedToPreviousError (c); - error176 (loc, c.GetSignatureForError ()); - return null; - } - - return exp; - } - } - - // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly - if (fi.IsInitOnly && !is_emitted && t == TypeManager.decimal_type) { - object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false); - if (attrs.Length == 1) - return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value); - } - - if (fi.IsLiteral) { - object o; - - if (is_emitted) - o = TypeManager.GetValue ((FieldBuilder) fi); - else - o = fi.GetValue (fi); - - if (decl_type.IsSubclassOf (TypeManager.enum_type)) { - if (left_is_explicit && !left_is_type && - !IdenticalNameAndTypeName (ec, left_original, member_lookup, loc)) { - error176 (loc, fe.FieldInfo.Name); - return null; - } - - Expression enum_member = MemberLookup ( - ec, decl_type, "value__", MemberTypes.Field, - AllBindingFlags, loc); - - Enum en = TypeManager.LookupEnum (decl_type); - - Constant c; - if (en != null) - c = Constantify (o, en.UnderlyingType); - else - c = Constantify (o, enum_member.Type); - - return new EnumConstant (c, decl_type); - } - - Expression exp = Constantify (o, t); - - if (left_is_explicit && !left_is_type) { - error176 (loc, fe.FieldInfo.Name); - return null; - } - - return exp; - } - - if (t.IsPointer && !ec.InUnsafe){ - UnsafeError (loc); + 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; } } - if (member_lookup is EventExpr) { - EventExpr ee = (EventExpr) member_lookup; - - // - // If the event is local to this class, we transform ourselves into - // a FieldExpr - // - - if (ee.EventInfo.DeclaringType == ec.ContainerType || - TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) { - MemberInfo mi = GetFieldFromEvent (ee); - - if (mi == null) { - // - // If this happens, then we have an event with its own - // accessors and private field etc so there's no need - // to transform ourselves. - // - ee.InstanceExpression = left; - return ee; - } - - Expression ml = ExprClassFromMemberInfo (ec, mi, loc); - - if (ml == null) { - Report.Error (-200, loc, "Internal error!!"); - return null; - } - - if (!left_is_explicit) - left = null; - - ee.InstanceExpression = left; + Expression retval = new MemberAccess (fne, identifier, loc).DoResolve (ec); + if (retval == null) + return null; - return ResolveMemberAccess (ec, ml, left, loc, left_original); - } + 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; } - if (member_lookup is IMemberExpr) { - IMemberExpr me = (IMemberExpr) member_lookup; - MethodGroupExpr mg = me as MethodGroupExpr; - - if (left_is_type){ - if ((mg != null) && left_is_explicit && left.Type.IsInterface) - mg.IsExplicitImpl = left_is_explicit; - - if (!me.IsStatic){ - if ((ec.IsFieldInitializer || ec.IsStatic) && - IdenticalNameAndTypeName (ec, left_original, member_lookup, loc)) - return member_lookup; - - SimpleName.Error_ObjectRefRequired (ec, loc, me.Name); - return null; - } - - } else { - if (!me.IsInstance){ - if (IdenticalNameAndTypeName (ec, left_original, left, loc)) - return member_lookup; - - if (left_is_explicit) { - error176 (loc, me.Name); - 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; + } - // - // Since we can not check for instance objects in SimpleName, - // becaue of the rule that allows types and variables to share - // the name (as long as they can be de-ambiguated later, see - // IdenticalNameAndTypeName), we have to check whether left - // is an instance variable in a static context - // - // However, if the left-hand value is explicitly given, then - // it is already our instance expression, so we aren't in - // static context. - // + public override void Emit (EmitContext ec) + { + throw new InternalErrorException ("QualifiedAliasMember found in resolved tree"); + } - if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){ - IMemberExpr mexp = (IMemberExpr) left; - if (!mexp.IsStatic){ - SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name); - return null; - } - } + public override string ToString () + { + return alias + "::" + identifier; + } - if ((mg != null) && IdenticalNameAndTypeName (ec, left_original, left, loc)) - mg.IdenticalTypeName = true; + public override string GetSignatureForError () + { + return ToString (); + } + } - me.InstanceExpression = left; - } + /// + /// Implements the member access expression + /// + public class MemberAccess : Expression { + public readonly string Identifier; + Expression expr; + TypeArguments args; + + // TODO: Location can be removed + public MemberAccess (Expression expr, string id, Location l) + { + this.expr = expr; + Identifier = id; + loc = expr.Location; + } - return member_lookup; - } + public MemberAccess (Expression expr, string id, TypeArguments args, + Location l) + : this (expr, id, l) + { + this.args = args; + } - Console.WriteLine ("Left is: " + left); - Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet"); - Environment.Exit (1); - return null; + public Expression Expr { + get { return expr; } } - - public virtual Expression DoResolve (EmitContext ec, Expression right_side, - ResolveFlags flags) + + // 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) throw new Exception (); @@ -7595,74 +7197,27 @@ namespace Mono.CSharp { // definite assignment check on the actual field and not on the whole struct. // - Expression original = expr; - expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis); - if (expr == null) + SimpleName original = expr as SimpleName; + Expression new_expr = expr.Resolve (ec, + ResolveFlags.VariableOrValue | ResolveFlags.Type | + ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis); + + 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 (ec, 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) + ")"); @@ -7679,40 +7234,38 @@ namespace Mono.CSharp { } if (member_lookup == null) { MemberLookupFailed ( - ec, expr_type, expr_type, Identifier, null, false, loc); + ec, expr_type, expr_type, Identifier, null, true, loc); return null; } if (member_lookup is TypeExpr) { - if (!(expr is TypeExpr) && - !IdenticalNameAndTypeName (ec, original, 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; } - return member_lookup; - } - - if (args != null) { - string full_name = expr_type + "." + Identifier; + ConstructedType ct = new_expr as ConstructedType; + if (ct != null) { + // + // When looking up a nested type in a generic instance + // via reflection, we always get a generic type definition + // and not a generic instance - so we have to do this here. + // + // See gtest-172-lib.cs and gtest-172.cs for an example. + // + ct = new ConstructedType ( + member_lookup.Type, ct.TypeArguments, loc); - if (member_lookup is FieldExpr) { - Report.Error (307, loc, "The field `{0}' cannot " + - "be used with type arguments", full_name); - return null; - } else if (member_lookup is EventExpr) { - Report.Error (307, loc, "The event `{0}' cannot " + - "be used with type arguments", full_name); - return null; - } else if (member_lookup is PropertyExpr) { - Report.Error (307, loc, "The property `{0}' cannot " + - "be used with type arguments", full_name); - return null; + return ct.ResolveAsTypeStep (ec); } + + return member_lookup; } - - member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original); + + MemberExpr me = (MemberExpr) member_lookup; + member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original); if (member_lookup == null) return null; @@ -7724,38 +7277,47 @@ 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) { - return DoResolve (ec, null, ResolveFlags.VariableOrValue | ResolveFlags.Type); + return DoResolve (ec, null); } public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { - return DoResolve (ec, right_side, ResolveFlags.VariableOrValue | ResolveFlags.Type); + 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); @@ -7765,7 +7327,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; } @@ -7773,7 +7336,7 @@ namespace Mono.CSharp { if (tnew_expr == null) return null; - Type expr_type = tnew_expr.Type; + Type expr_type = tnew_expr.ResolveType (ec); if (expr_type.IsPointer){ Error (23, "The `.' operator can not be applied to pointer operands (" + @@ -7781,20 +7344,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; } @@ -7833,6 +7398,11 @@ namespace Mono.CSharp { { return expr + "." + MemberName.MakeName (Identifier, args); } + + public override string GetSignatureForError () + { + return expr.GetSignatureForError () + "." + Identifier; + } } /// @@ -7943,11 +7513,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; @@ -7979,11 +7549,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; @@ -8008,7 +7578,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; } @@ -8034,7 +7604,7 @@ namespace Mono.CSharp { Type t = Expr.Type; if (t.IsArray) - return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side); + return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side); if (t.IsPointer) return MakePointerAccess (ec, Expr.Type); @@ -8045,7 +7615,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 @@ -8056,7 +7626,7 @@ namespace Mono.CSharp { return MakePointerAccess (ec, ff.ElementType); } } - return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side); + return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side); } public override void Emit (EmitContext ec) @@ -8104,10 +7674,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; } @@ -8126,7 +7694,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; } @@ -8182,6 +7750,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); } @@ -8222,7 +7792,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; } @@ -8424,20 +7996,35 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Call, address); } } - } + public void EmitGetLength (EmitContext ec, int dim) + { + int rank = ea.Expr.Type.GetArrayRank (); + ILGenerator ig = ec.ig; + + ea.Expr.Emit (ec); + if (rank == 1) { + ig.Emit (OpCodes.Ldlen); + ig.Emit (OpCodes.Conv_I4); + } else { + IntLiteral.EmitInt (ig, dim); + ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int); + } + } + } 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; } @@ -8445,22 +8032,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)); + } } } @@ -8468,51 +8066,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)); } } @@ -8574,15 +8148,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); } } @@ -8594,21 +8165,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; } @@ -8616,7 +8185,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; } @@ -8641,13 +8210,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) { @@ -8660,9 +8227,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; } @@ -8673,8 +8239,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; } @@ -8682,7 +8247,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; } @@ -8692,11 +8257,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; @@ -8801,15 +8366,14 @@ namespace Mono.CSharp { Expression member_lookup; Type current_type = ec.ContainerType; Type base_type = current_type.BaseType; - Expression e; 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; } @@ -8827,10 +8391,12 @@ namespace Mono.CSharp { left = new TypeExpression (base_type, loc); else left = ec.GetThis (loc); + + MemberExpr me = (MemberExpr) member_lookup; - e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null); + Expression e = me.ResolveMemberAccess (ec, left, loc, null); - if (e is PropertyExpr){ + if (e is PropertyExpr) { PropertyExpr pe = (PropertyExpr) e; pe.IsBase = true; @@ -8889,6 +8455,23 @@ namespace Mono.CSharp { public class EmptyExpression : Expression { public static readonly EmptyExpression Null = new EmptyExpression (); + static EmptyExpression temp = new EmptyExpression (); + public static EmptyExpression Grab () + { + if (temp == null) + throw new InternalErrorException ("Nested Grab"); + EmptyExpression retval = temp; + temp = null; + return retval; + } + + public static void Release (EmptyExpression e) + { + if (temp != null) + throw new InternalErrorException ("Already released"); + temp = e; + } + // TODO: should be protected public EmptyExpression () { @@ -8976,6 +8559,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; @@ -8983,13 +8571,27 @@ namespace Mono.CSharp { loc = l; } + public Expression RemoveNullable () + { + if (dim.EndsWith ("?")) { + dim = dim.Substring (0, dim.Length - 1); + if (dim == "") + return left; + } + + return this; + } + protected override TypeExpr DoResolveAsTypeStep (EmitContext ec) { TypeExpr lexpr = left.ResolveAsTypeTerminal (ec); if (lexpr == null) return null; - Type ltype = lexpr.Type; + bool old = ec.TestObsoleteMethodUsage; + ec.TestObsoleteMethodUsage = true; + Type ltype = lexpr.ResolveType (ec); + ec.TestObsoleteMethodUsage = old; if ((ltype == TypeManager.void_type) && (dim != "*")) { Report.Error (1547, Location, @@ -9004,6 +8606,10 @@ namespace Mono.CSharp { return nullable.ResolveAsTypeTerminal (ec); } + if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc)) { + return null; + } + if (dim != "") type = TypeManager.GetConstructedType (ltype, dim); else @@ -9020,7 +8626,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; } @@ -9041,7 +8647,7 @@ namespace Mono.CSharp { } } - public class FixedBufferPtr: Expression { + public class FixedBufferPtr : Expression { Expression array; public FixedBufferPtr (Expression array, Type array_type, Location l) @@ -9158,10 +8764,8 @@ namespace Mono.CSharp { return null; } - if (ec.CurrentBranching.InCatch () || - ec.CurrentBranching.InFinally (true)) { - Error (255, - "stackalloc can not be used in a catch or finally block"); + if (ec.InCatch || ec.InFinally) { + Error (255, "Cannot use stackalloc in finally or catch"); return null; } @@ -9169,7 +8773,7 @@ namespace Mono.CSharp { if (texpr == null) return null; - otype = texpr.Type; + otype = texpr.ResolveType (ec); if (!TypeManager.VerifyUnManaged (otype, loc)) return null;